[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