[llvm-branch-commits] [clang] [LifetimeSafety] Improve aliasing notes to include callee name (PR #203606)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Fri Jun 12 11:49:43 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-temporal-safety
Author: Utkarsh Saxena (usx95)
<details>
<summary>Changes</summary>
---
Patch is 50.60 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/203606.diff
4 Files Affected:
- (modified) clang/lib/Sema/SemaLifetimeSafety.h (+14-1)
- (modified) clang/test/Sema/LifetimeSafety/annotation-suggestions.cpp (+6-6)
- (modified) clang/test/Sema/LifetimeSafety/nocfg.cpp (+39-25)
- (modified) clang/test/Sema/LifetimeSafety/safety.cpp (+56-51)
``````````diff
diff --git a/clang/lib/Sema/SemaLifetimeSafety.h b/clang/lib/Sema/SemaLifetimeSafety.h
index 36ad0a8a358ae..91f1290f38723 100644
--- a/clang/lib/Sema/SemaLifetimeSafety.h
+++ b/clang/lib/Sema/SemaLifetimeSafety.h
@@ -495,9 +495,22 @@ class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper {
return "temporary object";
if (isa<CXXNewExpr>(E))
return "allocated object";
-
if (const auto *DRE = dyn_cast<DeclRefExpr>(E))
return getDiagSubjectDescription(DRE->getDecl());
+
+ if (const auto *CE = dyn_cast<CallExpr>(E)) {
+ const auto *FD = CE->getDirectCallee();
+ if (!FD)
+ return "result of call";
+ if (FD->isOverloadedOperator() || isa<CXXConversionDecl>(FD))
+ return "expression";
+ std::string Name;
+ llvm::raw_string_ostream OS(Name);
+ FD->getNameForDiagnostic(OS, S.getPrintingPolicy(),
+ /*Qualified=*/false);
+ return "result of call to '" + Name + "'";
+ }
+
// TODO: Handle other expression types.
return "expression";
}
diff --git a/clang/test/Sema/LifetimeSafety/annotation-suggestions.cpp b/clang/test/Sema/LifetimeSafety/annotation-suggestions.cpp
index 6abdc32c2d743..cef3397b57a6f 100644
--- a/clang/test/Sema/LifetimeSafety/annotation-suggestions.cpp
+++ b/clang/test/Sema/LifetimeSafety/annotation-suggestions.cpp
@@ -278,21 +278,21 @@ View return_view_field(const ViewProvider& v) { // expected-warning {{paramet
void test_get_on_temporary_pointer() {
const ReturnsSelf* s_ref = &ReturnsSelf().get(); // expected-warning {{temporary object does not live long enough}}.
// expected-note at -1 {{destroyed here}}
- // expected-note at -2 {{expression aliases the storage of temporary object}}
+ // expected-note at -2 {{result of call to 'get' aliases the storage of temporary object}}
(void)s_ref; // expected-note {{later used here}}
}
void test_get_on_temporary_ref() {
const ReturnsSelf& s_ref = ReturnsSelf().get(); // expected-warning {{temporary object does not live long enough}}.
// expected-note at -1 {{destroyed here}}
- // expected-note at -2 {{expression aliases the storage of temporary object}}
+ // expected-note at -2 {{result of call to 'get' aliases the storage of temporary object}}
(void)s_ref; // expected-note {{later used here}}
}
void test_getView_on_temporary() {
View sv = ViewProvider{1}.getView(); // expected-warning {{temporary object does not live long enough}}.
// expected-note at -1 {{destroyed here}}
- // expected-note at -2 {{expression aliases the storage of temporary object}}
+ // expected-note at -2 {{result of call to 'getView' aliases the storage of temporary object}}
(void)sv; // expected-note {{later used here}}
}
@@ -603,7 +603,7 @@ void uaf_via_inferred_lifetimebound() {
{
int local;
f = return_lambda_capturing_param(local); // expected-warning {{local variable 'local' does not live long enough}} \
- // expected-note {{expression aliases the storage of local variable 'local'}}
+ // expected-note {{result of call to 'return_lambda_capturing_param' aliases the storage of local variable 'local'}}
} // expected-note {{destroyed here}}
(void)f; // expected-note {{later used here}}
}
@@ -627,7 +627,7 @@ void test_inference() {
{
MyObj obj;
ptr = create_target(obj); // expected-warning {{local variable 'obj' does not live long enough}} \
- // expected-note {{expression aliases the storage of local variable 'obj'}}
+ // expected-note {{result of call to 'create_target' aliases the storage of local variable 'obj'}}
} // expected-note {{destroyed here}}
(void)ptr; // expected-note {{later used here}}
}
@@ -642,7 +642,7 @@ View* MakeView(const MyObj& in) { // expected-warning {{parameter in intra-TU fu
void test_new_allocation() {
View* v = MakeView(MyObj{}); // expected-warning {{temporary object does not live long enough}} \
// expected-note {{destroyed here}} \
- // expected-note {{expression aliases the storage of temporary object}}
+ // expected-note {{result of call to 'MakeView' aliases the storage of temporary object}}
(void)v; // expected-note {{later used here}}
}
diff --git a/clang/test/Sema/LifetimeSafety/nocfg.cpp b/clang/test/Sema/LifetimeSafety/nocfg.cpp
index 3d7d59086ea54..b9a6150daf712 100644
--- a/clang/test/Sema/LifetimeSafety/nocfg.cpp
+++ b/clang/test/Sema/LifetimeSafety/nocfg.cpp
@@ -194,7 +194,7 @@ struct Unannotated {
void modelIterators() {
std::vector<int>::iterator it = std::vector<int>().begin(); // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}} \
// cfg-warning {{temporary object does not live long enough}} cfg-note {{destroyed here}} \
- // cfg-note {{expression aliases the storage of temporary object}}
+ // cfg-note {{result of call to 'begin' aliases the storage of temporary object}}
(void)it; // cfg-note {{later used here}}
}
@@ -243,12 +243,12 @@ int &danglingRawPtrFromLocal3() {
std::string_view containerWithAnnotatedElements() {
std::string_view c1 = std::vector<std::string>().at(0); // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}} \
// cfg-warning {{temporary object does not live long enough}} cfg-note {{destroyed here}} \
- // cfg-note {{expression aliases the storage of temporary object}}
+ // cfg-note {{result of call to 'at' aliases the storage of temporary object}}
use(c1); // cfg-note {{later used here}}
c1 = std::vector<std::string>().at(0); // expected-warning {{object backing the pointer}} \
// cfg-warning {{temporary object does not live long enough}} cfg-note {{destroyed here}} \
- // cfg-note {{expression aliases the storage of temporary object}}
+ // cfg-note {{result of call to 'at' aliases the storage of temporary object}}
use(c1); // cfg-note {{later used here}}
// no warning on constructing from gsl-pointer
@@ -319,14 +319,14 @@ void danglingReferenceFromTempOwner() {
// https://github.com/llvm/llvm-project/issues/175893
int &&r3 = std::optional<int>(5).value(); // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}} \
// cfg-warning {{temporary object does not live long enough}} cfg-note {{destroyed here}} \
- // cfg-note {{expression aliases the storage of temporary object}}
+ // cfg-note {{result of call to 'value' aliases the storage of temporary object}}
const int &r4 = std::vector<int>().at(3); // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}} \
// cfg-warning {{temporary object does not live long enough}} cfg-note {{destroyed here}} \
- // cfg-note {{expression aliases the storage of temporary object}}
+ // cfg-note {{result of call to 'at' aliases the storage of temporary object}}
int &&r5 = std::vector<int>().at(3); // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}} \
// cfg-warning {{temporary object does not live long enough}} cfg-note {{destroyed here}} \
- // cfg-note {{expression aliases the storage of temporary object}}
+ // cfg-note {{result of call to 'at' aliases the storage of temporary object}}
use(r, r2, r3, r4, r5); // cfg-note 5 {{later used here}}
std::string_view sv = *getTempOptStr(); // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}} \
@@ -621,7 +621,7 @@ std::string_view ReturnStringView(std::string_view abc [[clang::lifetimebound]])
void test() {
std::string_view svjkk1 = ReturnStringView(StrCat("bar", "x")); // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}} \
// cfg-warning {{temporary object does not live long enough}} cfg-note {{destroyed here}} \
- // cfg-note {{expression aliases the storage of temporary object}}
+ // cfg-note {{result of call to 'ReturnStringView' aliases the storage of temporary object}}
use(svjkk1); // cfg-note {{later used here}}
}
} // namespace GH100549
@@ -856,7 +856,7 @@ namespace GH118064{
void test() {
auto y = std::set<int>{}.begin(); // expected-warning {{object backing the pointer}} \
// cfg-warning {{temporary object does not live long enough}} cfg-note {{destroyed here}} \
- // cfg-note {{expression aliases the storage of temporary object}}
+ // cfg-note {{result of call to 'begin' aliases the storage of temporary object}}
use(y); // cfg-note {{later used here}}
}
} // namespace GH118064
@@ -872,11 +872,11 @@ std::string_view TakeStr(std::string abc [[clang::lifetimebound]]);
std::string_view test1_1() {
std::string_view t1 = Ref(std::string()); // expected-warning {{object backing}} \
// cfg-warning {{temporary object does not live long enough}} cfg-note {{destroyed here}} \
- // cfg-note {{expression aliases the storage of temporary object}}
+ // cfg-note {{result of call to 'Ref' aliases the storage of temporary object}}
use(t1); // cfg-note {{later used here}}
t1 = Ref(std::string()); // expected-warning {{object backing}} \
// cfg-warning {{temporary object does not live long enough}} cfg-note {{destroyed here}} \
- // cfg-note {{expression aliases the storage of temporary object}}
+ // cfg-note {{result of call to 'Ref' aliases the storage of temporary object}}
use(t1); // cfg-note {{later used here}}
return Ref(std::string()); // expected-warning {{returning address}} \
// cfg-warning {{stack memory associated with temporary object is returned}} cfg-note {{returned here}}
@@ -885,11 +885,11 @@ std::string_view test1_1() {
std::string_view test1_2() {
std::string_view t2 = TakeSv(std::string()); // expected-warning {{object backing}} \
// cfg-warning {{temporary object does not live long enough}} cfg-note {{destroyed here}} \
- // cfg-note {{expression aliases the storage of temporary object}}
+ // cfg-note {{result of call to 'TakeSv' aliases the storage of temporary object}}
use(t2); // cfg-note {{later used here}}
t2 = TakeSv(std::string()); // expected-warning {{object backing}} \
// cfg-warning {{temporary object does not live long enough}} cfg-note {{destroyed here}} \
- // cfg-note {{expression aliases the storage of temporary object}}
+ // cfg-note {{result of call to 'TakeSv' aliases the storage of temporary object}}
use(t2); // cfg-note {{later used here}}
return TakeSv(std::string()); // expected-warning {{returning address}} \
@@ -899,11 +899,11 @@ std::string_view test1_2() {
std::string_view test1_3() {
std::string_view t3 = TakeStrRef(std::string()); // expected-warning {{temporary}} \
// cfg-warning {{temporary object does not live long enough}} cfg-note {{destroyed here}} \
- // cfg-note {{expression aliases the storage of temporary object}}
+ // cfg-note {{result of call to 'TakeStrRef' aliases the storage of temporary object}}
use(t3); // cfg-note {{later used here}}
t3 = TakeStrRef(std::string()); // expected-warning {{object backing}} \
// cfg-warning {{temporary object does not live long enough}} cfg-note {{destroyed here}} \
- // cfg-note {{expression aliases the storage of temporary object}}
+ // cfg-note {{result of call to 'TakeStrRef' aliases the storage of temporary object}}
use(t3); // cfg-note {{later used here}}
return TakeStrRef(std::string()); // expected-warning {{returning address}} \
// cfg-warning {{stack memory associated with temporary object is returned}} cfg-note {{returned here}}
@@ -926,11 +926,11 @@ struct Foo {
std::string_view test2_1(Foo<std::string> r1, Foo<std::string_view> r2) {
std::string_view t1 = Foo<std::string>().get(); // expected-warning {{object backing}} \
// cfg-warning {{temporary object does not live long enough}} cfg-note {{destroyed here}} \
- // cfg-note {{expression aliases the storage of temporary object}}
+ // cfg-note {{result of call to 'get' aliases the storage of temporary object}}
use(t1); // cfg-note {{later used here}}
t1 = Foo<std::string>().get(); // expected-warning {{object backing}} \
// cfg-warning {{temporary object does not live long enough}} cfg-note {{destroyed here}} \
- // cfg-note {{expression aliases the storage of temporary object}}
+ // cfg-note {{result of call to 'get' aliases the storage of temporary object}}
use(t1); // cfg-note {{later used here}}
return r1.get(); // expected-warning {{address of stack}} \
// cfg-warning {{stack memory associated with parameter 'r1' is returned}} cfg-note {{returned here}}
@@ -1049,11 +1049,16 @@ void operator_star_arrow_reference() {
auto temporary = []() { return std::vector<std::string>{{"1"}}; };
const char* x = temporary().begin()->data(); // cfg-warning {{temporary object does not live long enough}} cfg-note {{destroyed here}} \
- // cfg-note 3 {{expression aliases the storage of temporary object}}
+ // cfg-note {{result of call to 'begin' aliases the storage of temporary object}} \
+ // cfg-note {{expression aliases the storage of temporary object}} \
+ // cfg-note {{result of call to 'data' aliases the storage of temporary object}}
const char* y = (*temporary().begin()).data(); // cfg-warning {{temporary object does not live long enough}} cfg-note {{destroyed here}} \
- // cfg-note 3 {{expression aliases the storage of temporary object}}
+ // cfg-note {{result of call to 'begin' aliases the storage of temporary object}} \
+ // cfg-note {{expression aliases the storage of temporary object}} \
+ // cfg-note {{result of call to 'data' aliases the storage of temporary object}}
const std::string& z = (*temporary().begin()); // cfg-warning {{temporary object does not live long enough}} cfg-note {{destroyed here}} \
- // cfg-note 2 {{expression aliases the storage of temporary object}}
+ // cfg-note {{result of call to 'begin' aliases the storage of temporary object}} \
+ // cfg-note {{expression aliases the storage of temporary object}}
use(p, q, r, x, y, z); // cfg-note 3 {{later used here}}
}
@@ -1066,11 +1071,16 @@ void operator_star_arrow_of_iterators_false_positive_no_cfg_analysis() {
auto temporary = []() { return std::vector<std::pair<int, std::string>>{{1, "1"}}; };
const char* x = temporary().begin()->second.data(); // cfg-warning {{temporary object does not live long enough}} cfg-note {{destroyed here}} \
- // cfg-note 3 {{expression aliases the storage of temporary object}}
+ // cfg-note {{result of call to 'begin' aliases the storage of temporary object}} \
+ // cfg-note {{expression aliases the storage of temporary object}} \
+ // cfg-note {{result of call to 'data' aliases the storage of temporary object}}
const char* y = (*temporary().begin()).second.data(); // cfg-warning {{temporary object does not live long enough}} cfg-note {{destroyed here}} \
- // cfg-note 3 {{expression aliases the storage of temporary object}}
+ // cfg-note {{result of call to 'begin' aliases the storage of temporary object}} \
+ // cfg-note {{expression aliases the storage of temporary object}} \
+ // cfg-note {{result of call to 'data' aliases the storage of temporary object}}
const std::string& z = (*temporary().begin()).second; // cfg-warning {{temporary object does not live long enough}} cfg-note {{destroyed here}} \
- // cfg-note 2 {{expression aliases the storage of temporary object}}
+ // cfg-note {{result of call to 'begin' aliases the storage of temporary object}} \
+ // cfg-note {{expression aliases the storage of temporary object}}
use(p, q, r, x, y, z); // cfg-note 3 {{later used here}}
}
@@ -1126,15 +1136,19 @@ void test1() {
std::string_view k3 = Q().get()->sv; // OK
std::string_view k4 = Q().get()->s; // expected-warning {{object backing the pointer will}} \
// cfg-warning {{temporary object does not live long enough}} cfg-note {{destroyed here}} \
- // cfg-note 2 {{expression aliases the storage of temporary object}}
+ // cfg-note {{result of call to 'get' aliases the storage of temporary object}} \
+ // cfg-note {{expression aliases the storage of temporary object}}
std::string_view lb1 = foo(S().s); // expected-warning {{object backing the pointer will}} \
...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/203606
More information about the llvm-branch-commits
mailing list