https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/100197
>From b76d65484c3195f27e8d01208ccc6e6f8ab55273 Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena <u...@google.com> Date: Tue, 23 Jul 2024 19:41:44 +0000 Subject: [PATCH 1/5] Fix lifetimebound for field access --- clang/lib/Sema/CheckExprLifetime.cpp | 8 ++++++++ clang/test/SemaCXX/attr-lifetimebound.cpp | 21 +++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/clang/lib/Sema/CheckExprLifetime.cpp b/clang/lib/Sema/CheckExprLifetime.cpp index 5c8ef564f30aa..4d26a2e0f50c6 100644 --- a/clang/lib/Sema/CheckExprLifetime.cpp +++ b/clang/lib/Sema/CheckExprLifetime.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "CheckExprLifetime.h" +#include "clang/AST/Decl.h" #include "clang/AST/Expr.h" #include "clang/Basic/DiagnosticSema.h" #include "clang/Sema/Initialization.h" @@ -548,6 +549,13 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path, EnableLifetimeWarnings); } + if (auto* M = dyn_cast<MemberExpr>(Init)) { + // Lifetime of a field is the lifetime of the base object. + if (isa<FieldDecl>(M->getMemberDecl())) + visitLocalsRetainedByInitializer(Path, M->getBase(), Visit, true, + EnableLifetimeWarnings); + } + if (isa<CallExpr>(Init)) { if (EnableLifetimeWarnings) handleGslAnnotatedTypes(Path, Init, Visit); diff --git a/clang/test/SemaCXX/attr-lifetimebound.cpp b/clang/test/SemaCXX/attr-lifetimebound.cpp index 70bc545c07bd9..b43c43bb21699 100644 --- a/clang/test/SemaCXX/attr-lifetimebound.cpp +++ b/clang/test/SemaCXX/attr-lifetimebound.cpp @@ -47,6 +47,26 @@ namespace usage_ok { q = A(); // expected-warning {{object backing the pointer q will be destroyed at the end of the full-expression}} r = A(1); // expected-warning {{object backing the pointer r will be destroyed at the end of the full-expression}} } + + struct FieldCheck { + struct Set { + int a; + }; + struct Pair { + const int& a; + int b; + Set c; + }; + Pair p; + FieldCheck(const int a): p(a){} + Pair& getPairR() [[clang::lifetimebound]] { return p; } + Pair* getPairP() [[clang::lifetimebound]] { return &p; } + }; + void test_field_access() { + const int& a = FieldCheck{0}.getPairR().a; // expected-warning {{temporary bound to local reference 'a' will be destroyed at the end of the full-expression}} + const int& b = FieldCheck{0}.getPairP()->b; // expected-warning {{temporary bound to local reference 'b' will be destroyed at the end of the full-expression}} + const int& c = FieldCheck{0}.getPairP()->c.a; // expected-warning {{temporary bound to local reference 'c' will be destroyed at the end of the full-expression}} + } } # 1 "<std>" 1 3 @@ -239,3 +259,4 @@ namespace move_forward_et_al_examples { S X; S *AddressOfOk = std::addressof(X); } // namespace move_forward_et_al_examples + >From 247f986b7a4b4743826a53e9317c4a65ebe289fe Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena <u...@google.com> Date: Tue, 23 Jul 2024 20:32:33 +0000 Subject: [PATCH 2/5] release notes --- clang/docs/ReleaseNotes.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 7ac6ed934290d..fdad9202c0ea9 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -744,6 +744,8 @@ Improvements to Clang's diagnostics - Clang now diagnoses dangling assignments for pointer-like objects (annotated with `[[gsl::Pointer]]`) under `-Wdangling-assignment-gsl` (off by default) Fixes #GH63310. +- Clang now diagnoses dangling references to fields of temporary objects. Fixes #GH81589. + Improvements to Clang's time-trace ---------------------------------- >From 3825954a382d6bedd79f7ad332cd6937c74fe5fa Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena <u...@google.com> Date: Tue, 23 Jul 2024 20:33:18 +0000 Subject: [PATCH 3/5] format --- clang/lib/Sema/CheckExprLifetime.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/Sema/CheckExprLifetime.cpp b/clang/lib/Sema/CheckExprLifetime.cpp index 4d26a2e0f50c6..66b61fbbbeda7 100644 --- a/clang/lib/Sema/CheckExprLifetime.cpp +++ b/clang/lib/Sema/CheckExprLifetime.cpp @@ -549,7 +549,7 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path, EnableLifetimeWarnings); } - if (auto* M = dyn_cast<MemberExpr>(Init)) { + if (auto *M = dyn_cast<MemberExpr>(Init)) { // Lifetime of a field is the lifetime of the base object. if (isa<FieldDecl>(M->getMemberDecl())) visitLocalsRetainedByInitializer(Path, M->getBase(), Visit, true, >From dcfd225abfa0bcbd6e00f3c30c7c490982974fee Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena <u...@google.com> Date: Wed, 24 Jul 2024 08:46:06 +0000 Subject: [PATCH 4/5] Lifetime of reference type field is unknown. skip it --- clang/lib/Sema/CheckExprLifetime.cpp | 5 +++-- clang/test/SemaCXX/attr-lifetimebound.cpp | 7 ++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/clang/lib/Sema/CheckExprLifetime.cpp b/clang/lib/Sema/CheckExprLifetime.cpp index 66b61fbbbeda7..112cf3d081822 100644 --- a/clang/lib/Sema/CheckExprLifetime.cpp +++ b/clang/lib/Sema/CheckExprLifetime.cpp @@ -550,8 +550,9 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path, } if (auto *M = dyn_cast<MemberExpr>(Init)) { - // Lifetime of a field is the lifetime of the base object. - if (isa<FieldDecl>(M->getMemberDecl())) + // Lifetime of a non-reference type field is same as base object. + if (auto *F = dyn_cast<FieldDecl>(M->getMemberDecl()); + F && !F->getType()->isReferenceType()) visitLocalsRetainedByInitializer(Path, M->getBase(), Visit, true, EnableLifetimeWarnings); } diff --git a/clang/test/SemaCXX/attr-lifetimebound.cpp b/clang/test/SemaCXX/attr-lifetimebound.cpp index b43c43bb21699..78c1cb91e17a2 100644 --- a/clang/test/SemaCXX/attr-lifetimebound.cpp +++ b/clang/test/SemaCXX/attr-lifetimebound.cpp @@ -63,9 +63,10 @@ namespace usage_ok { Pair* getPairP() [[clang::lifetimebound]] { return &p; } }; void test_field_access() { - const int& a = FieldCheck{0}.getPairR().a; // expected-warning {{temporary bound to local reference 'a' will be destroyed at the end of the full-expression}} - const int& b = FieldCheck{0}.getPairP()->b; // expected-warning {{temporary bound to local reference 'b' will be destroyed at the end of the full-expression}} - const int& c = FieldCheck{0}.getPairP()->c.a; // expected-warning {{temporary bound to local reference 'c' will be destroyed at the end of the full-expression}} + int x = 0; + const int& a = FieldCheck{x}.getPairR().a; + const int& b = FieldCheck{x}.getPairP()->b; // expected-warning {{temporary bound to local reference 'b' will be destroyed at the end of the full-expression}} + const int& c = FieldCheck{x}.getPairP()->c.a; // expected-warning {{temporary bound to local reference 'c' will be destroyed at the end of the full-expression}} } } >From 3209eb2a7635adc80bfc17e8b7d58b0ecc923803 Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena <u...@google.com> Date: Wed, 24 Jul 2024 08:50:34 +0000 Subject: [PATCH 5/5] add negative tests --- clang/test/SemaCXX/attr-lifetimebound.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/clang/test/SemaCXX/attr-lifetimebound.cpp b/clang/test/SemaCXX/attr-lifetimebound.cpp index 78c1cb91e17a2..2b925a90bfd4a 100644 --- a/clang/test/SemaCXX/attr-lifetimebound.cpp +++ b/clang/test/SemaCXX/attr-lifetimebound.cpp @@ -58,15 +58,17 @@ namespace usage_ok { Set c; }; Pair p; - FieldCheck(const int a): p(a){} - Pair& getPairR() [[clang::lifetimebound]] { return p; } - Pair* getPairP() [[clang::lifetimebound]] { return &p; } + FieldCheck(const int& a): p(a){} + Pair& getR() [[clang::lifetimebound]] { return p; } + Pair* getP() [[clang::lifetimebound]] { return &p; } + Pair* getNoLB() { return &p; } }; void test_field_access() { int x = 0; - const int& a = FieldCheck{x}.getPairR().a; - const int& b = FieldCheck{x}.getPairP()->b; // expected-warning {{temporary bound to local reference 'b' will be destroyed at the end of the full-expression}} - const int& c = FieldCheck{x}.getPairP()->c.a; // expected-warning {{temporary bound to local reference 'c' will be destroyed at the end of the full-expression}} + const int& a = FieldCheck{x}.getR().a; + const int& b = FieldCheck{x}.getP()->b; // expected-warning {{temporary bound to local reference 'b' will be destroyed at the end of the full-expression}} + const int& c = FieldCheck{x}.getP()->c.a; // expected-warning {{temporary bound to local reference 'c' will be destroyed at the end of the full-expression}} + const int& d = FieldCheck{x}.getNoLB()->c.a; } } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits