[clang] a91c739 - [Lifetime Safety] Name operator calls in alias-chain diagnostics (#221803)

via cfe-commits cfe-commits at lists.llvm.org
Thu Sep 10 00:04:39 PDT 2026


Author: PushkarSingh
Date: 2026-09-10T08:04:35+01:00
New Revision: a91c7395c3fb1a37f69f7d8fb0e78c048faf6cb7

URL: https://github.com/llvm/llvm-project/commit/a91c7395c3fb1a37f69f7d8fb0e78c048faf6cb7
DIFF: https://github.com/llvm/llvm-project/commit/a91c7395c3fb1a37f69f7d8fb0e78c048faf6cb7.diff

LOG: [Lifetime Safety] Name operator calls in alias-chain diagnostics (#221803)

This updates Lifetime Safety alias-chain diagnostics to identify
overloaded operator and conversion calls instead of describing them
generically as an `expression`.

Previously, these calls were reported as `expression aliases the storage
of ...`, which could make it unclear which operation introduced the
alias. The diagnostic now reports the callee using the existing
diagnostic name printer, producing descriptions such as:

- `result of call to 'operator->'`
- `result of call to 'operator()'`
- `result of call to 'operator basic_string_view'`

Template arguments are preserved for operator function-template
specializations. For example:

- `result of call to 'operator+<const int>'`
- `result of call to 'operator-<__gnu_cxx::basic_iterator<const int>>'`

This makes each aliasing step explicit and identifies the particular
call responsible for propagating the alias.

References to
[#220248#discussion_r3905817437](https://github.com/llvm/llvm-project/pull/220248#discussion_r3905817437)

Added: 
    

Modified: 
    clang/lib/Sema/SemaLifetimeSafety.h
    clang/test/Sema/LifetimeSafety/invalidations.cpp
    clang/test/Sema/LifetimeSafety/nocfg.cpp
    clang/test/Sema/LifetimeSafety/safety.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Sema/SemaLifetimeSafety.h b/clang/lib/Sema/SemaLifetimeSafety.h
index 0fd3486bcee46..620032c27f955 100644
--- a/clang/lib/Sema/SemaLifetimeSafety.h
+++ b/clang/lib/Sema/SemaLifetimeSafety.h
@@ -687,8 +687,6 @@ class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper {
       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(),

diff  --git a/clang/test/Sema/LifetimeSafety/invalidations.cpp b/clang/test/Sema/LifetimeSafety/invalidations.cpp
index 127e375bc023c..593ba92cf7443 100644
--- a/clang/test/Sema/LifetimeSafety/invalidations.cpp
+++ b/clang/test/Sema/LifetimeSafety/invalidations.cpp
@@ -271,7 +271,7 @@ void IteratorUsedAfterPreIncrement() {
   std::vector<int> v;
   auto it = v.begin();      // expected-warning {{local variable 'v' is later invalidated}} \
                             // expected-note {{result of call to 'begin' aliases the storage of local variable 'v'}}
-  auto next = ++it;         // expected-note {{expression aliases the storage of local variable 'v'}}
+  auto next = ++it;         // expected-note {{result of call to 'operator++' aliases the storage of local variable 'v'}}
   v.push_back(1);           // expected-note {{local variable 'v' is invalidated here}}
   (void)*next;              // expected-note {{later used here}}
 }
@@ -279,7 +279,7 @@ void IteratorUsedAfterPreIncrement() {
 void IteratorUsedAfterPostDecrement(std::vector<int> v) {
   auto it = v.rbegin();     // expected-warning {{parameter 'v' is later invalidated}} \
                             // expected-note {{result of call to 'rbegin' aliases the storage of parameter 'v'}}
-  auto prev = it--;         // expected-note {{expression aliases the storage of parameter 'v'}}
+  auto prev = it--;         // expected-note {{result of call to 'operator--' aliases the storage of parameter 'v'}}
   v.push_back(1);           // expected-note {{parameter 'v' is invalidated here}}
   (void)*prev;              // expected-note {{later used here}}
 }
@@ -288,7 +288,7 @@ void IteratorUsedAfterAddition() {
   std::vector<int> v;
   auto it = v.cbegin();     // expected-warning {{local variable 'v' is later invalidated}} \
                             // expected-note {{result of call to 'cbegin' aliases the storage of local variable 'v'}}
-  auto next = it + 5;       // expected-note {{expression aliases the storage of local variable 'v'}}
+  auto next = it + 5;       // expected-note {{result of call to 'operator+' aliases the storage of local variable 'v'}}
   v.push_back(1);           // expected-note {{local variable 'v' is invalidated here}}
   (void)*next;              // expected-note {{later used here}}
 }
@@ -297,7 +297,7 @@ void IteratorUsedAfterReverseSubtraction(std::vector<int> v) {
   auto it = v.crbegin();    // expected-warning {{parameter 'v' is later invalidated}} \
                             // expected-note {{result of call to 'crbegin' aliases the storage of parameter 'v'}}
   auto prev = 5 - it;       // expected-note {{local variable 'it' aliases the storage of parameter 'v'}} \
-                            // expected-note {{expression aliases the storage of parameter 'v'}}
+                            // expected-note {{result of call to 'operator-<__gnu_cxx::basic_iterator<const int>>' aliases the storage of parameter 'v'}}
   v.push_back(1);           // expected-note {{parameter 'v' is invalidated here}}
   (void)*prev;              // expected-note {{later used here}}
 }
@@ -305,7 +305,7 @@ void IteratorUsedAfterReverseSubtraction(std::vector<int> v) {
 void IteratorUsedAfterAddAdd(std::vector<int> v) {
   auto it = v.cbegin();     // expected-warning {{parameter 'v' is later invalidated}} \
                             // expected-note {{result of call to 'cbegin' aliases the storage of parameter 'v'}}
-  auto next = (it + 5) + 5; // expected-note 2 {{expression aliases the storage of parameter 'v'}}
+  auto next = (it + 5) + 5; // expected-note 2 {{result of call to 'operator+' aliases the storage of parameter 'v'}}
   v.push_back(1);           // expected-note {{parameter 'v' is invalidated here}}
   (void)*next;              // expected-note {{later used here}}
 }
@@ -314,7 +314,8 @@ void IteratorUsedAfterMixedAddition() {
   std::vector<int> v;
   auto it = v.cbegin();         // expected-warning {{local variable 'v' is later invalidated}} \
                                 // expected-note {{result of call to 'cbegin' aliases the storage of local variable 'v'}}
-  auto next = 1 + it + 2 + 3;   // expected-note 3 {{expression aliases the storage of local variable 'v'}} \
+  auto next = 1 + it + 2 + 3;   // expected-note {{result of call to 'operator+<const int>' aliases the storage of local variable 'v'}} \
+                                // expected-note 2 {{result of call to 'operator+' aliases the storage of local variable 'v'}} \
                                 // expected-note {{local variable 'it' aliases the storage of local variable 'v'}}
   v.push_back(1);               // expected-note {{local variable 'v' is invalidated here}}
   (void)*next;                  // expected-note {{later used here}}
@@ -323,7 +324,8 @@ void IteratorUsedAfterMixedAddition() {
 void IteratorUsedAfterPreIncrementAddAssign(std::vector<int> v) {
   auto it = v.begin();          // expected-warning {{parameter 'v' is later invalidated}} \
                                 // expected-note {{result of call to 'begin' aliases the storage of parameter 'v'}}
-  it = ++it + 1 + 2;            // expected-note 3 {{expression aliases the storage of parameter 'v'}}
+  it = ++it + 1 + 2;            // expected-note {{result of call to 'operator++' aliases the storage of parameter 'v'}} \
+                                // expected-note 2 {{result of call to 'operator+' aliases the storage of parameter 'v'}}
   v.push_back(1);               // expected-note {{parameter 'v' is invalidated here}}
   (void)*it;                    // expected-note {{later used here}}
 }
@@ -331,7 +333,7 @@ void IteratorUsedAfterPreIncrementAddAssign(std::vector<int> v) {
 void IteratorUsedAfterBeginAddAssign() {
   std::vector<int> v;
   auto it = v.begin() + 1;      // expected-warning {{local variable 'v' is later invalidated}} \
-                                // expected-note {{expression aliases the storage of local variable 'v'}} \
+                                // expected-note {{result of call to 'operator+' aliases the storage of local variable 'v'}} \
                                 // expected-note {{result of call to 'begin' aliases the storage of local variable 'v'}}
   v.push_back(1);               // expected-note {{local variable 'v' is invalidated here}}
   (void)*it;                    // expected-note {{later used here}}
@@ -341,7 +343,7 @@ void IteratorUsedAfterStdBeginAddAssign() {
   std::vector<int> v;
   std::vector<int>::iterator it;
   it = std::begin(v) + 1;       // expected-warning {{local variable 'v' is later invalidated}} \
-                                // expected-note {{expression aliases the storage of local variable 'v'}} \
+                                // expected-note {{result of call to 'operator+' aliases the storage of local variable 'v'}} \
                                 // expected-note {{result of call to 'begin<std::vector<int>>' aliases the storage of local variable 'v'}}
   v.push_back(1);               // expected-note {{local variable 'v' is invalidated here}}
   (void)*it;                    // expected-note {{later used here}}
@@ -404,7 +406,7 @@ namespace ElementReferences {
 void ReferenceToVectorElement() {
   std::vector<int> v = {1, 2, 3};
   int& ref = v[0]; // expected-warning {{local variable 'v' is later invalidated}} \
-                   // expected-note {{expression aliases the storage of local variable 'v'}}
+                   // expected-note {{result of call to 'operator[]' aliases the storage of local variable 'v'}}
   v.push_back(4);  // expected-note {{local variable 'v' is invalidated here}}
   ref = 10;        // expected-note {{later used here}}
   (void)ref;
@@ -413,7 +415,7 @@ void ReferenceToVectorElement() {
 void PointerRefToVectorElement() {
   std::vector<int*> v = {nullptr, nullptr};
   int*& ref = v[0];     // expected-warning {{local variable 'v' is later invalidated}} \
-                        // expected-note {{expression aliases the storage of local variable 'v'}}
+                        // expected-note {{result of call to 'operator[]' aliases the storage of local variable 'v'}}
   v.push_back(nullptr); // expected-note {{local variable 'v' is invalidated here}}
   ref = nullptr;        // expected-note {{later used here}}
 }
@@ -421,7 +423,7 @@ void PointerRefToVectorElement() {
 void PointerToVectorElement() {
   std::vector<int> v = {1, 2, 3};
   int* ptr = &v[0];  // expected-warning {{local variable 'v' is later invalidated}} \
-                     // expected-note {{expression aliases the storage of local variable 'v'}}
+                     // expected-note {{result of call to 'operator[]' aliases the storage of local variable 'v'}}
   v.resize(100);     // expected-note {{local variable 'v' is invalidated here}}
   *ptr = 10;         // expected-note {{later used here}}
 }
@@ -447,7 +449,7 @@ void SelfInvalidatingMap() {
                  // expected-note {{local variable 'mp' is invalidated here}} \
                  // expected-note {{later used here}} \
                  // expected-note {{local variable 'mp' is invalidated here}} \
-                 // expected-note {{expression aliases the storage of local variable 'mp'}} \
+                 // expected-note {{result of call to 'operator[]' aliases the storage of local variable 'mp'}} \
                  // expected-note {{later used here}}
 }
 
@@ -798,7 +800,7 @@ void FlatMapSubscriptMultipleCallsInvalidate(std::flat_map<int, int> mp, int a,
                             // expected-note {{parameter 'mp' is invalidated here}} \
                             // expected-note {{later used here}} \
                             // expected-note {{parameter 'mp' is invalidated here}} \
-                            // expected-note 2 {{expression aliases the storage of parameter 'mp'}} \
+                            // expected-note 2 {{result of call to 'operator[]' aliases the storage of parameter 'mp'}} \
                             // expected-note {{later used here}}
 }
 
@@ -851,7 +853,7 @@ struct S {
   void baz(){
     std::vector<std::string> vec = {"42"};
     v = vec[0];         // expected-warning {{local variable 'vec' is later invalidated}} \
-                        // expected-note {{expression aliases the storage of local variable 'vec'}}
+                        // expected-note {{result of call to 'operator[]' aliases the storage of local variable 'vec'}}
     vec.push_back("1"); // expected-note {{local variable 'vec' is invalidated here}}
     bar();              // expected-note {{later used here}}
     v = nullptr;
@@ -865,7 +867,7 @@ void function_captured_ref_invalidated() {
   std::vector<int> v;
   v.push_back(1);
   std::function<void()> f = [&r = v[0]]() { (void)r; }; // expected-warning {{local variable 'v' is later invalidated}} \
-                                                        // expected-note {{expression aliases the storage of local variable 'v'}}
+                                                        // expected-note {{result of call to 'operator[]' aliases the storage of local variable 'v'}}
   v.push_back(2); // expected-note {{local variable 'v' is invalidated here}}
   (void)f; // expected-note {{later used here}}
 }

diff  --git a/clang/test/Sema/LifetimeSafety/nocfg.cpp b/clang/test/Sema/LifetimeSafety/nocfg.cpp
index 5c5f0e6f7ce52..7ef209572c437 100644
--- a/clang/test/Sema/LifetimeSafety/nocfg.cpp
+++ b/clang/test/Sema/LifetimeSafety/nocfg.cpp
@@ -310,11 +310,11 @@ std::string_view danglingRefToOptionalFromTemp4() {
 void danglingReferenceFromTempOwner() {
   int &&r = *std::optional<int>();          // 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 because the implicit object parameter is inferred as lifetimebound}}
+                                            // cfg-note {{result of call to 'operator*' aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}}
   // https://github.com/llvm/llvm-project/issues/175893
   int &&r2 = *std::optional<int>(5);        // 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 because the implicit object parameter is inferred as lifetimebound}}
+                                              // cfg-note {{result of call to 'operator*' aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}}
 
   // 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}} \
@@ -331,7 +331,7 @@ void danglingReferenceFromTempOwner() {
 
   std::string_view sv = *getTempOptStr();  // 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 because the implicit object parameter is inferred as lifetimebound}}
+                                           // cfg-note {{result of call to 'operator*' aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}}
   use(sv);                                 // cfg-note {{later used here}}
 }
 
@@ -343,7 +343,7 @@ void testLoops() {
     ;
   for (auto i : *getTempOptVec()) // 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 {{later used here}} \
-                                  // cfg-note {{expression aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}}
+                                  // cfg-note {{result of call to 'operator*' aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}}
     ;
 }
 
@@ -1050,15 +1050,15 @@ 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 {{result of call to 'begin' aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} \
-  // cfg-note {{expression aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} \
+  // cfg-note {{result of call to 'operator->' aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} \
   // cfg-note {{result of call to 'data' aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}}
   const char* y = (*temporary().begin()).data();  // cfg-warning {{temporary object does not live long enough}} cfg-note {{destroyed here}} \
                                                   // cfg-note {{result of call to 'begin' aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} \
-  // cfg-note {{expression aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} \
+  // cfg-note {{result of call to 'operator*' aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} \
   // cfg-note {{result of call to 'data' aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}}
   const std::string& z = (*temporary().begin());  // cfg-warning {{temporary object does not live long enough}} cfg-note {{destroyed here}} \
                                                   // cfg-note {{result of call to 'begin' aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} \
-                                                   // cfg-note {{expression aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}}
+                                                   // cfg-note {{result of call to 'operator*' aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}}
 
   use(p, q, r, x, y, z); // cfg-note 3 {{later used here}}
 }
@@ -1072,15 +1072,15 @@ 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 {{result of call to 'begin' aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} \
-                                                        // cfg-note {{expression aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} \
+                                                        // cfg-note {{result of call to 'operator->' aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} \
                                                         // cfg-note {{result of call to 'data' aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}}
   const char* y = (*temporary().begin()).second.data(); // cfg-warning {{temporary object does not live long enough}} cfg-note {{destroyed here}} \
                                                         // cfg-note {{result of call to 'begin' aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} \
-                                                        // cfg-note {{expression aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} \
+                                                        // cfg-note {{result of call to 'operator*' aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} \
                                                         // cfg-note {{result of call to 'data' aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}}
   const std::string& z = (*temporary().begin()).second; // cfg-warning {{temporary object does not live long enough}} cfg-note {{destroyed here}} \
                                                        // cfg-note {{result of call to 'begin' aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} \
-                                                        // cfg-note {{expression aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}}
+                                                        // cfg-note {{result of call to 'operator*' aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}}
 
   use(p, q, r, x, y, z); // cfg-note 3 {{later used here}}
 }
@@ -1131,23 +1131,23 @@ void test1() {
   std::string_view k1 = S().sv; // OK
   std::string_view k2 = S().s; // expected-warning {{object backing the pointer will}} \
                                // cfg-warning {{temporary object does not live long enough}} cfg-note {{destroyed here}} \
-                               // cfg-note {{expression aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}}
+                               // cfg-note {{result of call to 'operator basic_string_view' aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}}
 
   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 {{result of call to 'get' aliases the storage of temporary object because the implicit object parameter is marked as lifetimebound}} \
-                                       // cfg-note {{expression aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}}
+                                       // cfg-note {{result of call to 'operator basic_string_view' aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}}
 
 
   std::string_view lb1 = foo(S().s); // expected-warning {{object backing the pointer will}} \
                                      // cfg-warning {{temporary object does not live long enough}} cfg-note {{destroyed here}} \
-                                     // cfg-note {{expression aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} \
+                                     // cfg-note {{result of call to 'operator basic_string_view' aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} \
                                      // cfg-note {{result of call to 'foo' aliases the storage of temporary object because parameter 'sv' is marked as lifetimebound}}
   std::string_view lb2 = foo(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 {{result of call to 'get' aliases the storage of temporary object because the implicit object parameter is marked as lifetimebound}} \
-                                            // cfg-note {{expression aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} \
+                                            // cfg-note {{result of call to 'operator basic_string_view' aliases the storage of temporary object because the implicit object parameter is inferred as lifetimebound}} \
                                             // cfg-note {{result of call to 'foo' aliases the storage of temporary object because parameter 'sv' is marked as lifetimebound}}
 
   use(k1, k2, k3, k4, lb1, lb2);  // cfg-note 4 {{later used here}}

diff  --git a/clang/test/Sema/LifetimeSafety/safety.cpp b/clang/test/Sema/LifetimeSafety/safety.cpp
index 1b269b265acb1..851f558c85dcd 100644
--- a/clang/test/Sema/LifetimeSafety/safety.cpp
+++ b/clang/test/Sema/LifetimeSafety/safety.cpp
@@ -1677,7 +1677,7 @@ void test_user_defined_deref_uaf() {
     MyObj obj;
     SmartPtr<MyObj> smart_ptr(&obj);
     p = &(*smart_ptr);  // expected-warning {{local variable 'smart_ptr' does not live long enough}} \
-                        // expected-note {{expression aliases the storage of local variable 'smart_ptr' because the implicit object parameter is marked as lifetimebound}}
+                        // expected-note {{result of call to 'operator*' aliases the storage of local variable 'smart_ptr' because the implicit object parameter is marked as lifetimebound}}
   }                     // expected-note {{local variable 'smart_ptr' is destroyed here}}
   (void)*p;             // expected-note {{later used here}}
 }
@@ -1695,7 +1695,7 @@ void test_user_defined_deref_with_view() {
     MyObj obj;
     SmartPtr<MyObj> smart_ptr(&obj);
     v = *smart_ptr;  // expected-warning {{local variable 'smart_ptr' does not live long enough}} \
-                     // expected-note {{expression aliases the storage of local variable 'smart_ptr' because the implicit object parameter is marked as lifetimebound}}
+                     // expected-note {{result of call to 'operator*' aliases the storage of local variable 'smart_ptr' because the implicit object parameter is marked as lifetimebound}}
   }                  // expected-note {{local variable 'smart_ptr' is destroyed here}}
   v.use();           // expected-note {{later used here}}
 }
@@ -1706,7 +1706,7 @@ void test_user_defined_deref_arrow() {
     MyObj obj;
     SmartPtr<MyObj> smart_ptr(&obj);
     p = smart_ptr.operator->();  // expected-warning {{local variable 'smart_ptr' does not live long enough}} \
-                                 // expected-note {{expression aliases the storage of local variable 'smart_ptr' because the implicit object parameter is marked as lifetimebound}}
+                                 // expected-note {{result of call to 'operator->' aliases the storage of local variable 'smart_ptr' because the implicit object parameter is marked as lifetimebound}}
   }                              // expected-note {{local variable 'smart_ptr' is destroyed here}}
   (void)*p;                      // expected-note {{later used here}}
 }
@@ -1717,7 +1717,7 @@ void test_user_defined_deref_chained() {
     MyObj obj;
     SmartPtr<SmartPtr<MyObj>> double_ptr;
     p = &(**double_ptr);  // expected-warning {{local variable 'double_ptr' does not live long enough}} \
-                          // expected-note 2 {{expression aliases the storage of local variable 'double_ptr' because the implicit object parameter is marked as lifetimebound}}
+                          // expected-note 2 {{result of call to 'operator*' aliases the storage of local variable 'double_ptr' because the implicit object parameter is marked as lifetimebound}}
   }                       // expected-note {{local variable 'double_ptr' is destroyed here}}
   (void)*p;               // expected-note {{later used here}}
 }
@@ -2052,7 +2052,7 @@ void test_temporary() {
     S s;
     const std::string& zz = s.x(); // expected-warning {{local variable 's' does not live long enough}} \
                                    // expected-note {{result of call to 'x' aliases the storage of local variable 's' because the implicit object parameter is marked as lifetimebound}}
-    z = zz;                        // expected-note {{expression aliases the storage of local variable 's'}}
+    z = zz;                        // expected-note {{result of call to 'operator basic_string_view' aliases the storage of local variable 's'}}
   } // expected-note {{local variable 's' is destroyed here}}
   (void)z; // expected-note {{later used here}}
 }
@@ -2085,7 +2085,7 @@ void uaf() {
     S str;
     S* p = &str;  // expected-warning {{local variable 'str' does not live long enough}}
     view = p->s;  // expected-note {{local variable 'p' aliases the storage of local variable 'str'}} \
-                  // expected-note {{expression aliases the storage of local variable 'str' because the implicit object parameter is inferred as lifetimebound}}
+                  // expected-note {{result of call to 'operator basic_string_view' aliases the storage of local variable 'str' because the implicit object parameter is inferred as lifetimebound}}
   } // expected-note {{local variable 'str' is destroyed here}}
   (void)view;  // expected-note {{later used here}}
 }
@@ -2112,7 +2112,7 @@ void uaf_union() {
     U u = U{"hello"};
     U* up = &u;   // expected-warning {{local variable 'u' does not live long enough}}
     view = up->s; // expected-note {{local variable 'up' aliases the storage of local variable 'u'}} \
-                  // expected-note {{expression aliases the storage of local variable 'u' because the implicit object parameter is inferred as lifetimebound}}
+                  // expected-note {{result of call to 'operator basic_string_view' aliases the storage of local variable 'u' because the implicit object parameter is inferred as lifetimebound}}
   } // expected-note {{local variable 'u' is destroyed here}}
   (void)view;  // expected-note {{later used here}}
 }
@@ -2288,7 +2288,7 @@ void test_optional_arrow() {
   {
     std::optional<std::string> opt;
     p = opt->data();  // expected-warning {{local variable 'opt' does not live long enough}} \
-                      // expected-note {{expression aliases the storage of local variable 'opt' because the implicit object parameter is inferred as lifetimebound}} \
+                      // expected-note {{result of call to 'operator->' aliases the storage of local variable 'opt' because the implicit object parameter is inferred as lifetimebound}} \
                       // expected-note {{result of call to 'data' aliases the storage of local variable 'opt' because the implicit object parameter is inferred as lifetimebound}}
   }                   // expected-note {{local variable 'opt' is destroyed here}}
   (void)*p;           // expected-note {{later used here}}
@@ -2299,7 +2299,7 @@ void test_optional_arrow_lifetimebound() {
   {
     std::optional<MyObj> opt;
     v = opt->getView();  // expected-warning {{local variable 'opt' does not live long enough}} \
-                         // expected-note {{expression aliases the storage of local variable 'opt' because the implicit object parameter is inferred as lifetimebound}} \
+                         // expected-note {{result of call to 'operator->' aliases the storage of local variable 'opt' because the implicit object parameter is inferred as lifetimebound}} \
                          // expected-note {{result of call to 'getView' aliases the storage of local variable 'opt' because the implicit object parameter is marked as lifetimebound}}
   }                      // expected-note {{local variable 'opt' is destroyed here}}
   v.use();               // expected-note {{later used here}}
@@ -2310,7 +2310,7 @@ void test_unique_ptr_arrow() {
   {
     std::unique_ptr<std::string> up;
     p = up->data();  // expected-warning {{local variable 'up' does not live long enough}} \
-                     // expected-note {{expression aliases the storage of local variable 'up' because the implicit object parameter is inferred as lifetimebound}} \
+                     // expected-note {{result of call to 'operator->' aliases the storage of local variable 'up' because the implicit object parameter is inferred as lifetimebound}} \
                      // expected-note {{result of call to 'data' aliases the storage of local variable 'up' because the implicit object parameter is inferred as lifetimebound}}
   }                  // expected-note {{local variable 'up' is destroyed here}}
   (void)*p;          // expected-note {{later used here}}
@@ -2701,8 +2701,8 @@ struct S {
 
 void indexing_with_static_operator() {
   S()(1, 2);
-  S& x = S()("1", // expected-note {{expression aliases the storage of temporary object because parameter 'a' is marked as lifetimebound}} \
-             // expected-note {{expression aliases the storage of temporary object because parameter 'b' is marked as lifetimebound}}
+  S& x = S()("1", // expected-note {{result of call to 'operator()' aliases the storage of temporary object because parameter 'a' is marked as lifetimebound}} \
+             // expected-note {{result of call to 'operator()' aliases the storage of temporary object because parameter 'b' is marked as lifetimebound}}
              2,   // expected-warning {{temporary object does not live long enough}}
              3);  // expected-warning {{temporary object does not live long enough}} expected-note 2 {{temporary object is destroyed here}}
 
@@ -2810,7 +2810,7 @@ void chained_defaulted_assignment_propagation() {
     S a = getS(str); // expected-warning {{local variable 'str' does not live long enough}} \
                      // expected-note {{result of call to 'getS' aliases the storage of local variable 'str' because parameter 's' is marked as lifetimebound}}
     c = b = a;       // expected-note {{local variable 'a' aliases the storage of local variable 'str'}} \
-                     // expected-note {{expression aliases the storage of local variable 'str'}}
+                     // expected-note {{result of call to 'operator=' aliases the storage of local variable 'str'}}
   }                  // expected-note {{local variable 'str' is destroyed here}}
   use(c);            // expected-note {{later used here}}
 }
@@ -3873,7 +3873,7 @@ void deref_use_after_scope() {
   {
     optional<MyObj> opt;
     p = &*opt; // expected-warning {{local variable 'opt' does not live long enough}} \
-               // expected-note {{expression aliases the storage of local variable 'opt' because the implicit object parameter is inferred as lifetimebound}}
+               // expected-note {{result of call to 'operator*' aliases the storage of local variable 'opt' because the implicit object parameter is inferred as lifetimebound}}
   }            // expected-note {{local variable 'opt' is destroyed here}}
   (void)p->id; // expected-note {{later used here}}
 }


        


More information about the cfe-commits mailing list