[clang] Make [[clang::lifetimebound]] work for expressions coming from default arguments (PR #112047)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Oct 11 15:11:35 PDT 2024
https://github.com/higher-performance updated https://github.com/llvm/llvm-project/pull/112047
>From 33da8c34977110619fa9ec2e9c9e830c993ce31a Mon Sep 17 00:00:00 2001
From: higher-performance <higher.performance.github at gmail.com>
Date: Fri, 11 Oct 2024 17:09:13 -0400
Subject: [PATCH] Make [[clang::lifetimebound]] work for expressions coming
from default arguments
---
clang/lib/Sema/CheckExprLifetime.cpp | 20 +++++++++++++++++++-
clang/test/SemaCXX/attr-lifetimebound.cpp | 6 ++++++
2 files changed, 25 insertions(+), 1 deletion(-)
diff --git a/clang/lib/Sema/CheckExprLifetime.cpp b/clang/lib/Sema/CheckExprLifetime.cpp
index f62e18543851c1..de639e951b8f28 100644
--- a/clang/lib/Sema/CheckExprLifetime.cpp
+++ b/clang/lib/Sema/CheckExprLifetime.cpp
@@ -194,6 +194,7 @@ struct IndirectLocalPathEntry {
GslReferenceInit,
GslPointerInit,
GslPointerAssignment,
+ DefaultArg,
} Kind;
Expr *E;
union {
@@ -532,6 +533,11 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
}
} while (Init != Old);
+ if (auto *DAE = dyn_cast<CXXDefaultArgExpr>(Init)) {
+ Path.push_back({IndirectLocalPathEntry::DefaultArg, DAE, DAE->getParam()});
+ Init = DAE->getExpr();
+ }
+
if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(Init)) {
if (Visit(Path, Local(MTE), RK))
visitLocalsRetainedByInitializer(Path, MTE->getSubExpr(), Visit, true);
@@ -916,6 +922,9 @@ static SourceRange nextPathEntryRange(const IndirectLocalPath &Path, unsigned I,
if (!Path[I].Capture->capturesVariable())
continue;
return Path[I].E->getSourceRange();
+
+ case IndirectLocalPathEntry::DefaultArg:
+ return cast<CXXDefaultArgExpr>(Path[I].E)->getUsedLocation();
}
}
return E->getSourceRange();
@@ -1221,7 +1230,7 @@ static void checkExprLifetimeImpl(Sema &SemaRef,
break;
}
- case IndirectLocalPathEntry::LambdaCaptureInit:
+ case IndirectLocalPathEntry::LambdaCaptureInit: {
if (!Elem.Capture->capturesVariable())
break;
// FIXME: We can't easily tell apart an init-capture from a nested
@@ -1234,6 +1243,15 @@ static void checkExprLifetimeImpl(Sema &SemaRef,
<< nextPathEntryRange(Path, I + 1, L);
break;
}
+
+ case IndirectLocalPathEntry::DefaultArg: {
+ const auto *DAE = cast<CXXDefaultArgExpr>(Elem.E);
+ SemaRef.Diag(DAE->getParam()->getDefaultArgRange().getBegin(),
+ diag::note_default_argument_declared_here)
+ << DAE->getParam() << nextPathEntryRange(Path, I + 1, L);
+ break;
+ }
+ }
}
// We didn't lifetime-extend, so don't go any further; we don't need more
diff --git a/clang/test/SemaCXX/attr-lifetimebound.cpp b/clang/test/SemaCXX/attr-lifetimebound.cpp
index 0fb997a5671085..d39d7e9eb54bff 100644
--- a/clang/test/SemaCXX/attr-lifetimebound.cpp
+++ b/clang/test/SemaCXX/attr-lifetimebound.cpp
@@ -19,8 +19,10 @@ namespace usage_invalid {
namespace usage_ok {
struct IntRef { int *target; };
+ const int *defaultparam(const int &def1 [[clang::lifetimebound]] = 0); // #def1
int &refparam(int ¶m [[clang::lifetimebound]]);
int &classparam(IntRef param [[clang::lifetimebound]]);
+ const int *c = defaultparam(); // expected-warning {{temporary whose address is used as value of local variable 'c' will be destroyed at the end of the full-expression}} expected-note@#def1 {{default argument declared here}}
// Do not diagnose non-void return types; they can still be lifetime-bound.
long long ptrintcast(int ¶m [[clang::lifetimebound]]) {
@@ -34,13 +36,17 @@ namespace usage_ok {
struct A {
A();
A(int);
+ A(const char*, const int& def2 [[clang::lifetimebound]] = 0); // #def2
int *class_member() [[clang::lifetimebound]];
operator int*() [[clang::lifetimebound]];
+ const int *defaulted_param(const int &def3 [[clang::lifetimebound]] = 0); // #def3
};
int *p = A().class_member(); // expected-warning {{temporary whose address is used as value of local variable 'p' will be destroyed at the end of the full-expression}}
int *q = A(); // expected-warning {{temporary whose address is used as value of local variable 'q' will be destroyed at the end of the full-expression}}
int *r = A(1); // expected-warning {{temporary whose address is used as value of local variable 'r' will be destroyed at the end of the full-expression}}
+ A a = A(""); // expected-warning {{temporary whose address is used as value of local variable 'a' will be destroyed at the end of the full-expression}} expected-note@#def2 {{default argument declared here}}
+ const int *s = A().defaulted_param(); // expected-warning {{temporary whose address is used as value of local variable 's' will be destroyed at the end of the full-expression}} expected-note@#def3 {{default argument declared here}}
void test_assignment() {
p = A().class_member(); // expected-warning {{object backing the pointer p will be destroyed at the end of the full-expression}}
More information about the cfe-commits
mailing list