[clang] Fix lifetimebound for field access (PR #100197)
Utkarsh Saxena via cfe-commits
cfe-commits at lists.llvm.org
Wed Jul 24 01:46:20 PDT 2024
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 <usx at google.com>
Date: Tue, 23 Jul 2024 19:41:44 +0000
Subject: [PATCH 1/4] 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 <usx at google.com>
Date: Tue, 23 Jul 2024 20:32:33 +0000
Subject: [PATCH 2/4] 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 <usx at google.com>
Date: Tue, 23 Jul 2024 20:33:18 +0000
Subject: [PATCH 3/4] 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 <usx at google.com>
Date: Wed, 24 Jul 2024 08:46:06 +0000
Subject: [PATCH 4/4] 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}}
}
}
More information about the cfe-commits
mailing list