Author: Yuan Suo
Date: 2026-06-12T17:37:59+02:00
New Revision: c5654d53c008522d2da165f05b682aafa36d7189

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

LOG: [LifetimeSafety] Introduce buildOriginFlowChain for use-after-scope 
(#199345)

After adding `buildOriginFlowChain`, we need to choose a diagnostic type
that is as simple as possible to verify its feasibility during `Sema`
diagnostics.

I did not choose the annotation suggestions described in
https://github.com/llvm/llvm-project/pull/188467/#issuecomment-4359071778
as the first target to implement, because it does not seem to occur
within a single CFG block. The `IssueFact` always resides in the block
preceding the `OriginEscapesFact`, which causes me to always get an
empty `OriginFlowChain`.

Since we use `buildOriginFlowChain`, we can directly trace distinct
assignment steps that occur within a single source-level expression. For
example:

```cpp
#include <vector>
#include <string>

template<class... T> void use(T... arg);

void operator_star_arrow_of_iterators_false_positive_no_cfg_analysis() {
  std::vector<std::pair<int, std::string>> v;
  const char* p = v.begin()->second.data();
  const char* q = (*v.begin()).second.data();
  const std::string& r = (*v.begin()).second;

  auto temporary = []() { return std::vector<std::pair<int, std::string>>{{1, 
"1"}}; };
  const char* x = temporary().begin()->second.data();
  const char* y = (*temporary().begin()).second.data();
  const std::string& z = (*temporary().begin()).second;
  use(p, q, r, x, y, z);
}
```

The code above produces the following diagnostic output:

```txt
pr.cpp:13:19: warning: local temporary object does not live long enough 
[-Wlifetime-safety-use-after-scope]
   13 |   const char* x = temporary().begin()->second.data();
      |                   ^~~~~~~~~~~
pr.cpp:13:52: note: destroyed here
   13 |   const char* x = temporary().begin()->second.data();
      |                                                    ^
pr.cpp:13:19: note: expression aliases the storage of local temporary object
   13 |   const char* x = temporary().begin()->second.data();
      |                   ^~~~~~~~~~~~~~~~~~~
pr.cpp:13:19: note: expression aliases the storage of local temporary object
   13 |   const char* x = temporary().begin()->second.data();
      |                   ^~~~~~~~~~~~~~~~~~~~~
pr.cpp:13:19: note: expression aliases the storage of local temporary object
   13 |   const char* x = temporary().begin()->second.data();
      |                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
pr.cpp:16:16: note: later used here
   16 |   use(p, q, r, x, y, z);
      |                ^
pr.cpp:15:28: warning: local temporary object does not live long enough 
[-Wlifetime-safety-use-after-scope]
   15 |   const std::string& z = (*temporary().begin()).second;
      |                            ^~~~~~~~~~~
pr.cpp:15:49: note: destroyed here
   15 |   const std::string& z = (*temporary().begin()).second;
      |                                                 ^
pr.cpp:15:28: note: expression aliases the storage of local temporary object
   15 |   const std::string& z = (*temporary().begin()).second;
      |                            ^~~~~~~~~~~~~~~~~~~
pr.cpp:15:27: note: expression aliases the storage of local temporary object
   15 |   const std::string& z = (*temporary().begin()).second;
      |                           ^~~~~~~~~~~~~~~~~~~~
pr.cpp:16:22: note: later used here
   16 |   use(p, q, r, x, y, z);
      |                      ^
pr.cpp:14:21: warning: local temporary object does not live long enough 
[-Wlifetime-safety-use-after-scope]
   14 |   const char* y = (*temporary().begin()).second.data();
      |                     ^~~~~~~~~~~
pr.cpp:14:54: note: destroyed here
   14 |   const char* y = (*temporary().begin()).second.data();
      |                                                      ^
pr.cpp:14:21: note: expression aliases the storage of local temporary object
   14 |   const char* y = (*temporary().begin()).second.data();
      |                     ^~~~~~~~~~~~~~~~~~~
pr.cpp:14:20: note: expression aliases the storage of local temporary object
   14 |   const char* y = (*temporary().begin()).second.data();
      |                    ^~~~~~~~~~~~~~~~~~~~
pr.cpp:14:19: note: expression aliases the storage of local temporary object
   14 |   const char* y = (*temporary().begin()).second.data();
      |                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
pr.cpp:16:19: note: later used here
   16 |   use(p, q, r, x, y, z);
      |                   ^
3 warnings generated.
```

---------

Signed-off-by: Yuan Suo <[email protected]>

Added: 
    

Modified: 
    clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
    clang/include/clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/lib/Analysis/LifetimeSafety/Checker.cpp
    clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp
    clang/lib/Sema/SemaLifetimeSafety.h
    clang/test/Sema/LifetimeSafety/annotation-suggestions.cpp
    clang/test/Sema/LifetimeSafety/nocfg.cpp
    clang/test/Sema/LifetimeSafety/safety.cpp

Removed: 
    


################################################################################
diff  --git 
a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h 
b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
index b89e1bfe4b43e..28886b826f72f 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
@@ -63,7 +63,8 @@ class LifetimeSafetySemaHelper {
 
   virtual void reportUseAfterScope(const Expr *IssueExpr, const Expr *UseExpr,
                                    const Expr *MovedExpr,
-                                   SourceLocation FreeLoc) {}
+                                   SourceLocation FreeLoc,
+                                   llvm::ArrayRef<const Expr *> ExprChain) {}
 
   virtual void reportUseAfterReturn(const Expr *IssueExpr,
                                     const Expr *ReturnExpr,

diff  --git 
a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h 
b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h
index e46912bedeb0f..724c6eee7d3c2 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h
@@ -48,6 +48,9 @@ class LoanPropagationAnalysis {
   buildOriginFlowChain(ProgramPoint StartPoint, const OriginID StartOID,
                        const LoanID TargetLoan) const;
 
+  llvm::SmallVector<OriginID>
+  buildOriginFlowChain(const UseFact *UF, const LoanID TargetLoan) const;
+
 private:
   class Impl;
   std::unique_ptr<Impl> PImpl;

diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 583f3f9d2eff5..9691963d4fe7e 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -11061,6 +11061,7 @@ def note_lifetime_safety_escapes_to_field_here: 
Note<"escapes to this field">;
 def note_lifetime_safety_escapes_to_global_here: Note<"escapes to this global 
storage">;
 def note_lifetime_safety_escapes_to_static_storage_here: Note<"escapes to this 
static storage">;
 def note_lifetime_safety_lifetimebound_here: Note<"'lifetimebound' attribute 
appears here on the definition">;
+def note_lifetime_safety_aliases_storage : Note<"%0 aliases the storage of 
%1">;
 
 def warn_lifetime_safety_intra_tu_param_suggestion
     : Warning<"parameter in intra-TU function should be marked "

diff  --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp 
b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
index 71cf2d2d5a674..d41d6f43f837b 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -266,8 +266,10 @@ class LifetimeChecker {
 
         } else
           // Scope-based expiry (use-after-scope).
-          SemaHelper->reportUseAfterScope(IssueExpr, UF->getUseExpr(),
-                                          MovedExpr, ExpiryLoc);
+          SemaHelper->reportUseAfterScope(
+              IssueExpr, UF->getUseExpr(), MovedExpr, ExpiryLoc,
+              getExprChain(LoanPropagation.buildOriginFlowChain(UF, LID)));
+
       } else if (const auto *OEF =
                      CausingFact.dyn_cast<const OriginEscapesFact *>()) {
         if (Warning.InvalidatedByExpr) {
@@ -509,6 +511,21 @@ class LifetimeChecker {
       }
     }
   }
+
+  /// Extract expressions from the origin flow chain for diagnostic purposes.
+  ///
+  /// Given a chain of origins that shows how a loan propagates, this function
+  /// extracts the corresponding expressions for each origin. Origins that 
refer
+  /// to declarations (rather than expressions) are skipped.
+  llvm::SmallVector<const Expr *>
+  getExprChain(llvm::ArrayRef<OriginID> OriginFlowChain) {
+    llvm::SmallVector<const Expr *> rs;
+    for (const OriginID CurrOID : OriginFlowChain)
+      if (const Expr *CurrExpr =
+              FactMgr.getOriginMgr().getOrigin(CurrOID).getExpr())
+        rs.push_back(CurrExpr);
+    return rs;
+  }
 };
 } // namespace
 

diff  --git a/clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp 
b/clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp
index 8c570cd29673b..f3bb85f08e965 100644
--- a/clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp
@@ -239,6 +239,16 @@ class AnalysisImpl
     return {};
   }
 
+  llvm::SmallVector<OriginID>
+  buildOriginFlowChain(const UseFact *UF, const LoanID TargetLoan) const {
+    for (const OriginList *Cur = UF->getUsedOrigins(); Cur;
+         Cur = Cur->peelOuterOrigin())
+      if (getLoans(Cur->getOuterOriginID(), UF).contains(TargetLoan))
+        return buildOriginFlowChain(UF, Cur->getOuterOriginID(), TargetLoan);
+
+    return {};
+  }
+
 private:
   /// Returns true if the origin is persistent (referenced in multiple blocks).
   bool isPersistent(OriginID OID) const {
@@ -295,4 +305,10 @@ LoanPropagationAnalysis::buildOriginFlowChain(ProgramPoint 
StartPoint,
                                               const LoanID TargetLoan) const {
   return PImpl->buildOriginFlowChain(StartPoint, StartOID, TargetLoan);
 }
+
+llvm::SmallVector<OriginID>
+LoanPropagationAnalysis::buildOriginFlowChain(const UseFact *UF,
+                                              const LoanID TargetLoan) const {
+  return PImpl->buildOriginFlowChain(UF, TargetLoan);
+}
 } // namespace clang::lifetimes::internal

diff  --git a/clang/lib/Sema/SemaLifetimeSafety.h 
b/clang/lib/Sema/SemaLifetimeSafety.h
index 462a4ed168e24..a7c628f315d78 100644
--- a/clang/lib/Sema/SemaLifetimeSafety.h
+++ b/clang/lib/Sema/SemaLifetimeSafety.h
@@ -62,8 +62,8 @@ class LifetimeSafetySemaHelperImpl : public 
LifetimeSafetySemaHelper {
   LifetimeSafetySemaHelperImpl(Sema &S) : S(S) {}
 
   void reportUseAfterScope(const Expr *IssueExpr, const Expr *UseExpr,
-                           const Expr *MovedExpr,
-                           SourceLocation FreeLoc) override {
+                           const Expr *MovedExpr, SourceLocation FreeLoc,
+                           llvm::ArrayRef<const Expr *> ExprChain) override {
     unsigned DiagID = MovedExpr
                           ? diag::warn_lifetime_safety_use_after_scope_moved
                           : diag::warn_lifetime_safety_use_after_scope;
@@ -74,6 +74,9 @@ class LifetimeSafetySemaHelperImpl : public 
LifetimeSafetySemaHelper {
       S.Diag(MovedExpr->getExprLoc(), diag::note_lifetime_safety_moved_here)
           << MovedExpr->getSourceRange();
     S.Diag(FreeLoc, diag::note_lifetime_safety_destroyed_here);
+
+    reportAliasingChain(ExprChain);
+
     S.Diag(UseExpr->getExprLoc(), diag::note_lifetime_safety_used_here)
         << UseExpr->getSourceRange();
   }
@@ -481,13 +484,44 @@ class LifetimeSafetySemaHelperImpl : public 
LifetimeSafetySemaHelper {
   }
 
   std::string getDiagSubjectDescription(const Expr *E) {
+    E = E->IgnoreImpCasts();
     if (isa<MaterializeTemporaryExpr>(E))
       return "local temporary object";
 
     if (const auto *DRE = dyn_cast<DeclRefExpr>(E))
       return getDiagSubjectDescription(DRE->getDecl());
     // TODO: Handle other expression types.
-    return "";
+    return "expression";
+  }
+
+  bool shouldShowInAliasChain(const Expr *CurrExpr, const Expr *LastExpr) {
+    CurrExpr = CurrExpr->IgnoreImpCasts();
+    LastExpr = LastExpr->IgnoreImpCasts();
+
+    if (!isa<CallExpr, DeclRefExpr>(CurrExpr))
+      return false;
+    // Source ranges can be used to filter out many implicit expressions,
+    // because operations between class objects often involve numerous implicit
+    // conversions, yet they share the same source range.
+    return CurrExpr->getSourceRange() != LastExpr->getSourceRange();
+  }
+
+  void reportAliasingChain(llvm::ArrayRef<const Expr *> OriginExprChain) {
+    if (OriginExprChain.empty())
+      return;
+
+    const Expr *LastExpr = OriginExprChain.back();
+    std::string IssueStr = getDiagSubjectDescription(LastExpr);
+
+    for (const Expr *CurrExpr : reverse(OriginExprChain.drop_back())) {
+      if (!shouldShowInAliasChain(CurrExpr, LastExpr))
+        continue;
+      S.Diag(CurrExpr->getBeginLoc(),
+             diag::note_lifetime_safety_aliases_storage)
+          << CurrExpr->getSourceRange() << getDiagSubjectDescription(CurrExpr)
+          << IssueStr;
+      LastExpr = CurrExpr;
+    }
   }
 
   Sema &S;

diff  --git a/clang/test/Sema/LifetimeSafety/annotation-suggestions.cpp 
b/clang/test/Sema/LifetimeSafety/annotation-suggestions.cpp
index 1f6832e824e37..1f94e101fb9ef 100644
--- a/clang/test/Sema/LifetimeSafety/annotation-suggestions.cpp
+++ b/clang/test/Sema/LifetimeSafety/annotation-suggestions.cpp
@@ -278,18 +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 {{local 
temporary object does not live long enough}}.
                                                    // expected-note@-1 
{{destroyed here}}
+                                                   // expected-note@-2 
{{expression aliases the storage of local temporary object}}
   (void)s_ref;                                     // expected-note {{later 
used here}}
 }
 
 void test_get_on_temporary_ref() {
   const ReturnsSelf& s_ref = ReturnsSelf().get();  // expected-warning {{local 
temporary object does not live long enough}}.
                                                    // expected-note@-1 
{{destroyed here}}
+                                                   // expected-note@-2 
{{expression aliases the storage of local temporary object}}
   (void)s_ref;                                     // expected-note {{later 
used here}}
 }
 
 void test_getView_on_temporary() {
   View sv = ViewProvider{1}.getView();      // expected-warning {{local 
temporary object does not live long enough}}.
                                             // expected-note@-1 {{destroyed 
here}}
+                                            // expected-note@-2 {{expression 
aliases the storage of local temporary object}}
   (void)sv;                                 // expected-note {{later used 
here}}
 }
 
@@ -599,7 +602,8 @@ void uaf_via_inferred_lifetimebound() {
   std::function<void()> f = []() {};
   {
     int local;
-    f = return_lambda_capturing_param(local); // expected-warning {{local 
variable 'local' does not live long enough}}
+    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 {{destroyed here}}
   (void)f; // expected-note {{later used here}}
 }
@@ -622,7 +626,8 @@ void test_inference() {
   std::unique_ptr<LifetimeBoundCtor> ptr;
   {
     MyObj obj;
-    ptr = create_target(obj); // expected-warning {{local variable 'obj' does 
not live long enough}}
+    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 {{destroyed here}}
   (void)ptr; // expected-note {{later used here}}
 }
@@ -636,7 +641,8 @@ View* MakeView(const MyObj& in) { // expected-warning 
{{parameter in intra-TU fu
 
 void test_new_allocation() {
   View* v = MakeView(MyObj{}); // expected-warning {{local temporary object 
does not live long enough}} \
-                               // expected-note {{destroyed here}}
+                               // expected-note {{destroyed here}} \
+                               // expected-note {{expression aliases the 
storage of local 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 e2a340401ac87..49b6175d378ae 100644
--- a/clang/test/Sema/LifetimeSafety/nocfg.cpp
+++ b/clang/test/Sema/LifetimeSafety/nocfg.cpp
@@ -193,7 +193,8 @@ 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 
{{local temporary object does not live long enough}} cfg-note {{destroyed here}}
+                                                              // cfg-warning 
{{local temporary object does not live long enough}} cfg-note {{destroyed 
here}} \
+                                                              // cfg-note 
{{expression aliases the storage of local temporary object}}
   (void)it; // cfg-note {{later used here}}
 }
 
@@ -241,11 +242,13 @@ int &danglingRawPtrFromLocal3() {
 // GH100384
 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 
{{local temporary object does not live long enough}} cfg-note {{destroyed here}}
+                                                          // cfg-warning 
{{local temporary object does not live long enough}} cfg-note {{destroyed 
here}} \
+                                                          // cfg-note 
{{expression aliases the storage of local temporary object}}
   use(c1);                                                // cfg-note {{later 
used here}}
 
   c1 = std::vector<std::string>().at(0); // expected-warning {{object backing 
the pointer}} \
-                                         // cfg-warning {{local temporary 
object does not live long enough}} cfg-note {{destroyed here}}
+                                         // cfg-warning {{local temporary 
object does not live long enough}} cfg-note {{destroyed here}} \
+                                         // cfg-note {{expression aliases the 
storage of local temporary object}}
   use(c1);                               // cfg-note {{later used here}}
 
   // no warning on constructing from gsl-pointer
@@ -306,23 +309,29 @@ 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 {{local temporary 
object does not live long enough}} cfg-note {{destroyed here}}
+                                            // cfg-warning {{local temporary 
object does not live long enough}} cfg-note {{destroyed here}} \
+                                            // cfg-note {{expression aliases 
the storage of local temporary object}}
   // 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 {{local temporary 
object does not live long enough}} cfg-note {{destroyed here}}
+                                              // cfg-warning {{local temporary 
object does not live long enough}} cfg-note {{destroyed here}} \
+                                              // cfg-note {{expression aliases 
the storage of local temporary object}}
 
   // 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 {{local temporary 
object does not live long enough}} cfg-note {{destroyed here}}
+                                              // cfg-warning {{local temporary 
object does not live long enough}} cfg-note {{destroyed here}} \
+                                              // cfg-note {{expression aliases 
the storage of local 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 {{local temporary 
object does not live long enough}} cfg-note {{destroyed here}}
+                                            // cfg-warning {{local temporary 
object does not live long enough}} cfg-note {{destroyed here}} \
+                                            // cfg-note {{expression aliases 
the storage of local 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 {{local temporary 
object does not live long enough}} cfg-note {{destroyed here}}
+                                            // cfg-warning {{local temporary 
object does not live long enough}} cfg-note {{destroyed here}} \
+                                            // cfg-note {{expression aliases 
the storage of local 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}} \
-                                           // cfg-warning {{local temporary 
object does not live long enough}} cfg-note {{destroyed here}}
+                                           // cfg-warning {{local temporary 
object does not live long enough}} cfg-note {{destroyed here}} \
+                                           // cfg-note {{expression aliases 
the storage of local temporary object}}
   use(sv);                                 // cfg-note {{later used here}}
 }
 
@@ -333,7 +342,8 @@ void testLoops() {
   for (auto i : getTempVec()) // ok
     ;
   for (auto i : *getTempOptVec()) // expected-warning {{object backing the 
pointer will be destroyed at the end of the full-expression}} \
-                                  // cfg-warning {{local temporary object does 
not live long enough}} cfg-note {{destroyed here}} cfg-note {{later used here}}
+                                  // cfg-warning {{local temporary object does 
not live long enough}} cfg-note {{destroyed here}} cfg-note {{later used here}} 
\
+                                  // cfg-note {{expression aliases the storage 
of local temporary object}}
     ;
 }
 
@@ -610,7 +620,8 @@ 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 {{local temporary object does not live long enough}} cfg-note 
{{destroyed here}}
+                                                                  // 
cfg-warning {{local temporary object does not live long enough}} cfg-note 
{{destroyed here}} \
+                                                                  // cfg-note 
{{expression aliases the storage of local temporary object}}
   use(svjkk1);                                                    // cfg-note 
{{later used here}}
 }
 } // namespace GH100549
@@ -844,7 +855,8 @@ namespace GH118064{
 
 void test() {
   auto y = std::set<int>{}.begin(); // expected-warning {{object backing the 
pointer}} \
-  // cfg-warning {{local temporary object does not live long enough}} cfg-note 
{{destroyed here}}
+  // cfg-warning {{local temporary object does not live long enough}} cfg-note 
{{destroyed here}} \
+  // cfg-note {{expression aliases the storage of local temporary object}}
   use(y); // cfg-note {{later used here}}
 }
 } // namespace GH118064
@@ -859,10 +871,12 @@ 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 {{local temporary 
object does not live long enough}} cfg-note {{destroyed here}}
+                                            // cfg-warning {{local temporary 
object does not live long enough}} cfg-note {{destroyed here}} \
+                                            // cfg-note {{expression aliases 
the storage of local temporary object}}
   use(t1);                                  // cfg-note {{later used here}}
   t1 = Ref(std::string()); // expected-warning {{object backing}} \
-                           // cfg-warning {{local temporary object does not 
live long enough}} cfg-note {{destroyed here}}
+                           // cfg-warning {{local temporary object does not 
live long enough}} cfg-note {{destroyed here}} \
+                           // cfg-note {{expression aliases the storage of 
local temporary object}}
   use(t1);                 // cfg-note {{later used here}}
   return Ref(std::string()); // expected-warning {{returning address}} \
                              // cfg-warning {{stack memory associated with 
local temporary object is returned}} cfg-note {{returned here}}
@@ -870,10 +884,12 @@ std::string_view test1_1() {
 
 std::string_view test1_2() {
   std::string_view t2 = TakeSv(std::string()); // expected-warning {{object 
backing}} \
-                                            // cfg-warning {{local temporary 
object does not live long enough}} cfg-note {{destroyed here}}
+                                            // cfg-warning {{local temporary 
object does not live long enough}} cfg-note {{destroyed here}} \
+                                            // cfg-note {{expression aliases 
the storage of local temporary object}}
   use(t2);                                  // cfg-note {{later used here}}
   t2 = TakeSv(std::string()); // expected-warning {{object backing}} \
-                              // cfg-warning {{local temporary object does not 
live long enough}} cfg-note {{destroyed here}}
+                              // cfg-warning {{local temporary object does not 
live long enough}} cfg-note {{destroyed here}} \
+                              // cfg-note {{expression aliases the storage of 
local temporary object}}
   use(t2);                    // cfg-note {{later used here}}
 
   return TakeSv(std::string()); // expected-warning {{returning address}} \
@@ -882,10 +898,12 @@ std::string_view test1_2() {
 
 std::string_view test1_3() {
   std::string_view t3 = TakeStrRef(std::string()); // expected-warning 
{{temporary}} \
-                                                   // cfg-warning {{local 
temporary object does not live long enough}} cfg-note {{destroyed here}}
+                                                   // cfg-warning {{local 
temporary object does not live long enough}} cfg-note {{destroyed here}} \
+                                                   // cfg-note {{expression 
aliases the storage of local temporary object}}
   use(t3);                                         // cfg-note {{later used 
here}}
   t3 = TakeStrRef(std::string()); // expected-warning {{object backing}} \
-                                  // cfg-warning {{local temporary object does 
not live long enough}} cfg-note {{destroyed here}}
+                                  // cfg-warning {{local temporary object does 
not live long enough}} cfg-note {{destroyed here}} \
+                                  // cfg-note {{expression aliases the storage 
of local temporary object}}
   use(t3);                        // cfg-note {{later used here}}
   return TakeStrRef(std::string()); // expected-warning {{returning address}} \
                                     // cfg-warning {{stack memory associated 
with local temporary object is returned}} cfg-note {{returned here}}
@@ -907,10 +925,12 @@ 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 {{local 
temporary object does not live long enough}} cfg-note {{destroyed here}}
+                                                  // cfg-warning {{local 
temporary object does not live long enough}} cfg-note {{destroyed here}} \
+                                                  // cfg-note {{expression 
aliases the storage of local temporary object}}
   use(t1);                                        // cfg-note {{later used 
here}}
   t1 = Foo<std::string>().get(); // expected-warning {{object backing}} \
-                                 // cfg-warning {{local temporary object does 
not live long enough}} cfg-note {{destroyed here}}
+                                 // cfg-warning {{local temporary object does 
not live long enough}} cfg-note {{destroyed here}} \
+                                 // cfg-note {{expression aliases the storage 
of local 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}}
@@ -1028,9 +1048,12 @@ void operator_star_arrow_reference() {
   const std::string& r = *v.begin();
 
   auto temporary = []() { return std::vector<std::string>{{"1"}}; };
-  const char* x = temporary().begin()->data();    // cfg-warning {{local 
temporary object does not live long enough}} cfg-note {{destroyed here}}
-  const char* y = (*temporary().begin()).data();  // cfg-warning {{local 
temporary object does not live long enough}} cfg-note {{destroyed here}}
-  const std::string& z = (*temporary().begin());  // cfg-warning {{local 
temporary object does not live long enough}} cfg-note {{destroyed here}}
+  const char* x = temporary().begin()->data();    // cfg-warning {{local 
temporary object does not live long enough}} cfg-note {{destroyed here}} \
+                                                  // cfg-note 3 {{expression 
aliases the storage of local temporary object}}
+  const char* y = (*temporary().begin()).data();  // cfg-warning {{local 
temporary object does not live long enough}} cfg-note {{destroyed here}} \
+                                                  // cfg-note 3 {{expression 
aliases the storage of local temporary object}}
+  const std::string& z = (*temporary().begin());  // cfg-warning {{local 
temporary object does not live long enough}} cfg-note {{destroyed here}} \
+                                                  // cfg-note 2 {{expression 
aliases the storage of local temporary object}}
 
   use(p, q, r, x, y, z); // cfg-note 3 {{later used here}}
 }
@@ -1042,9 +1065,12 @@ void 
operator_star_arrow_of_iterators_false_positive_no_cfg_analysis() {
   const std::string& r = (*v.begin()).second;
 
   auto temporary = []() { return std::vector<std::pair<int, std::string>>{{1, 
"1"}}; };
-  const char* x = temporary().begin()->second.data();   // cfg-warning {{local 
temporary object does not live long enough}} cfg-note {{destroyed here}}
-  const char* y = (*temporary().begin()).second.data(); // cfg-warning {{local 
temporary object does not live long enough}} cfg-note {{destroyed here}}
-  const std::string& z = (*temporary().begin()).second; // cfg-warning {{local 
temporary object does not live long enough}} cfg-note {{destroyed here}}
+  const char* x = temporary().begin()->second.data();   // cfg-warning {{local 
temporary object does not live long enough}} cfg-note {{destroyed here}} \
+                                                        // cfg-note 3 
{{expression aliases the storage of local temporary object}}
+  const char* y = (*temporary().begin()).second.data(); // cfg-warning {{local 
temporary object does not live long enough}} cfg-note {{destroyed here}} \
+                                                        // cfg-note 3 
{{expression aliases the storage of local temporary object}}
+  const std::string& z = (*temporary().begin()).second; // cfg-warning {{local 
temporary object does not live long enough}} cfg-note {{destroyed here}} \
+                                                        // cfg-note 2 
{{expression aliases the storage of local temporary object}}
 
   use(p, q, r, x, y, z); // cfg-note 3 {{later used here}}
 }
@@ -1094,17 +1120,21 @@ std::string_view foo(std::string_view sv 
[[clang::lifetimebound]]);
 void test1() {
   std::string_view k1 = S().sv; // OK
   std::string_view k2 = S().s; // expected-warning {{object backing the 
pointer will}} \
-                               // cfg-warning {{local temporary object does 
not live long enough}} cfg-note {{destroyed here}}
+                               // cfg-warning {{local temporary object does 
not live long enough}} cfg-note {{destroyed here}} \
+                               // cfg-note {{expression aliases the storage of 
local temporary object}}
 
   std::string_view k3 = Q().get()->sv; // OK
   std::string_view k4  = Q().get()->s; // expected-warning {{object backing 
the pointer will}} \
-                                       // cfg-warning {{local temporary object 
does not live long enough}} cfg-note {{destroyed here}}
+                                       // cfg-warning {{local temporary object 
does not live long enough}} cfg-note {{destroyed here}} \
+                                       // cfg-note 2 {{expression aliases the 
storage of local temporary object}}
 
 
   std::string_view lb1 = foo(S().s); // expected-warning {{object backing the 
pointer will}} \
-                                     // cfg-warning {{local temporary object 
does not live long enough}} cfg-note {{destroyed here}}
+                                     // cfg-warning {{local temporary object 
does not live long enough}} cfg-note {{destroyed here}} \
+                                     // cfg-note 2 {{expression aliases the 
storage of local temporary object}}
   std::string_view lb2 = foo(Q().get()->s); // expected-warning {{object 
backing the pointer will}} \
-                                            // cfg-warning {{local temporary 
object does not live long enough}} cfg-note {{destroyed here}}
+                                            // cfg-warning {{local temporary 
object does not live long enough}} cfg-note {{destroyed here}} \
+                                            // cfg-note 3 {{expression aliases 
the storage of local temporary object}}
 
   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 580e1b2639ee1..2aa5ff43ec3bc 100644
--- a/clang/test/Sema/LifetimeSafety/safety.cpp
+++ b/clang/test/Sema/LifetimeSafety/safety.cpp
@@ -92,7 +92,7 @@ void pointer_chain() {
   {
     MyObj s;
     p = &s;     // expected-warning {{does not live long enough}}
-    q = p;
+    q = p;      // expected-note {{local variable 'p' aliases the storage of 
local variable 's'}}
   }             // expected-note {{destroyed here}}
   (void)*q;     // expected-note {{later used here}}
 }
@@ -102,7 +102,7 @@ void propagation_gsl() {
   {
     MyObj s;
     v1 = s;     // expected-warning {{local variable 's' does not live long 
enough}}
-    v2 = v1;
+    v2 = v1;    // expected-note {{local variable 'v1' aliases the storage of 
local variable 's'}}
   }             // expected-note {{destroyed here}}
   v2.use();     // expected-note {{later used here}}
 }
@@ -696,7 +696,8 @@ void test_lifetimebound_multi_level() {
     int* p = nullptr;
     int** pp = &p;  
     int*** ppp = &pp; // expected-warning {{local variable 'pp' does not live 
long enough}}
-    result = return_inner_ptr_addr(ppp);
+    result = return_inner_ptr_addr(ppp); // expected-note {{local variable 
'ppp' aliases the storage of local variable 'pp'}} \
+                                         // expected-note {{expression aliases 
the storage of local variable 'pp'}}
   }                   // expected-note {{destroyed here}}
   (void)**result;     // expected-note {{used here}}
 }
@@ -819,7 +820,8 @@ void lifetimebound_simple_function() {
   View v;
   {
     MyObj obj;
-    v = Identity(obj); // expected-warning {{local variable 'obj' does not 
live long enough}}
+    v = Identity(obj); // expected-warning {{local variable 'obj' does not 
live long enough}} \
+                       // expected-note {{expression aliases the storage of 
local variable 'obj'}}
   }                    // expected-note {{destroyed here}}
   v.use();             // expected-note {{later used here}}
 }
@@ -828,7 +830,8 @@ void lifetimebound_multiple_args_definite() {
   View v;
   {
     MyObj obj1, obj2;
-    v = Choose(true,
+    v = Choose(true,  // expected-note {{expression aliases the storage of 
local variable 'obj1'}} \
+                      // expected-note {{expression aliases the storage of 
local variable 'obj2'}}
                obj1,  // expected-warning {{local variable 'obj1' does not 
live long enough}}
                obj2); // expected-warning {{local variable 'obj2' does not 
live long enough}}
   }                              // expected-note 2 {{destroyed here}}
@@ -855,7 +858,8 @@ void lifetimebound_mixed_args() {
   View v;
   {
     MyObj obj1, obj2;
-    v = SelectFirst(obj1,        // expected-warning {{local variable 'obj1' 
does not live long enough}}
+    v = SelectFirst(obj1,        // expected-warning {{local variable 'obj1' 
does not live long enough}} \
+                                 // expected-note {{expression aliases the 
storage of local variable 'obj1'}}
                     obj2);
   }                              // expected-note {{destroyed here}}
   v.use();                       // expected-note {{later used here}}
@@ -871,7 +875,8 @@ void lifetimebound_member_function() {
   View v;
   {
     MyObj obj;
-    v  = obj.getView(); // expected-warning {{local variable 'obj' does not 
live long enough}}
+    v  = obj.getView(); // expected-warning {{local variable 'obj' does not 
live long enough}} \
+                        // expected-note {{expression aliases the storage of 
local variable 'obj'}}
   }                     // expected-note {{destroyed here}}
   v.use();              // expected-note {{later used here}}
 }
@@ -895,7 +900,8 @@ void lifetimebound_chained_calls() {
   View v;
   {
     MyObj obj;
-    v = Identity(Identity(Identity(obj))); // expected-warning {{local 
variable 'obj' does not live long enough}}
+    v = Identity(Identity(Identity(obj))); // expected-warning {{local 
variable 'obj' does not live long enough}} \
+                                           // expected-note 3 {{expression 
aliases the storage of local variable 'obj'}}
   }                                        // expected-note {{destroyed here}}
   v.use();                                 // expected-note {{later used here}}
 }
@@ -904,7 +910,8 @@ void lifetimebound_with_pointers() {
   MyObj* ptr;
   {
     MyObj obj;
-    ptr = GetPointer(obj); // expected-warning {{local variable 'obj' does not 
live long enough}}
+    ptr = GetPointer(obj); // expected-warning {{local variable 'obj' does not 
live long enough}} \
+                           // expected-note {{expression aliases the storage 
of local variable 'obj'}}
   }                        // expected-note {{destroyed here}}
   (void)*ptr;              // expected-note {{later used here}}
 }
@@ -913,7 +920,8 @@ void chained_assignment_lifetimebound_call() {
   MyObj *p, *obj;
   {
     MyObj s;
-    p = Identity(obj = &s); // expected-warning {{does not live long enough}}
+    p = Identity(obj = &s); // expected-warning {{does not live long enough}} \
+                            // expected-note {{expression aliases the storage 
of local variable 's'}}
   }                         // expected-note {{destroyed here}}
   (void)*p;                 // expected-note {{later used here}}
 }
@@ -945,7 +953,8 @@ void lifetimebound_return_reference() {
   {
     MyObj obj;
     View temp_v = obj;  // expected-warning {{local variable 'obj' does not 
live long enough}}
-    const MyObj& ref = GetObject(temp_v);
+    const MyObj& ref = GetObject(temp_v); // expected-note {{local variable 
'temp_v' aliases the storage of local variable 'obj'}} \
+                                          // expected-note {{expression 
aliases the storage of local variable 'obj'}}
     ptr = &ref;
   }                       // expected-note {{destroyed here}}
   (void)*ptr;             // expected-note {{later used here}}
@@ -999,7 +1008,8 @@ void lifetimebound_make_unique() {
   std::unique_ptr<LifetimeBoundCtor> ptr;
   {
     MyObj obj;
-    ptr = std::make_unique<LifetimeBoundCtor>(obj); // tu-warning {{local 
variable 'obj' does not live long enough}}
+    ptr = std::make_unique<LifetimeBoundCtor>(obj); // tu-warning {{local 
variable 'obj' does not live long enough}} \
+                                                    // tu-note {{expression 
aliases the storage of local variable 'obj'}}
   }                                                 // tu-note {{destroyed 
here}}
   (void)ptr;                                        // tu-note {{later used 
here}}
 }
@@ -1016,7 +1026,8 @@ void non_lifetimebound_make_unique() {
 
 void lifetimebound_make_unique_temp() {
   std::unique_ptr<LifetimeBoundCtor> ptr = 
std::make_unique<LifetimeBoundCtor>(MyObj()); // tu-warning {{local temporary 
object does not live long enough}} \
-                                                                               
          // tu-note {{destroyed here}}
+                                                                               
          // tu-note {{destroyed here}} \
+                                                                               
          // tu-note {{expression aliases the storage of local temporary 
object}}
   (void)ptr; // tu-note {{later used here}}
 }
 
@@ -1053,7 +1064,8 @@ void lifetimebound_make_unique_multi_params() {
   MyObj obj_long;
   {
     MyObj obj_short;
-    ptr = std::make_unique<MultiLifetimeBoundCtor>(obj_short, obj_long); // 
tu-warning {{local variable 'obj_short' does not live long enough}}
+    ptr = std::make_unique<MultiLifetimeBoundCtor>(obj_short, obj_long); // 
tu-warning {{local variable 'obj_short' does not live long enough}} \
+                                                                         // 
tu-note {{expression aliases the storage of local variable 'obj_short'}}
   } // tu-note {{destroyed here}}
   (void)ptr; // tu-note {{later used here}}
 }
@@ -1063,7 +1075,8 @@ void lifetimebound_make_unique_multi_params2() {
   MyObj obj_long;
   {
     MyObj obj_short;
-    ptr = std::make_unique<MultiLifetimeBoundCtor>(obj_long, obj_short, 1); // 
tu-warning {{local variable 'obj_short' does not live long enough}}
+    ptr = std::make_unique<MultiLifetimeBoundCtor>(obj_long, obj_short, 1); // 
tu-warning {{local variable 'obj_short' does not live long enough}} \
+                                                                            // 
tu-note {{expression aliases the storage of local variable 'obj_short'}}
   } // tu-note {{destroyed here}}
   (void)ptr; // tu-note {{later used here}}
 }
@@ -1083,7 +1096,8 @@ void lifetimebound_make_unique_multi_params3_1() {
   MyObj obj_long;
   {
     MyObj obj_short;
-    ptr = std::make_unique<MultiLifetimeBoundCtor>(obj_short, obj_long, 1.0); 
// tu-warning {{local variable 'obj_short' does not live long enough}}
+    ptr = std::make_unique<MultiLifetimeBoundCtor>(obj_short, obj_long, 1.0); 
// tu-warning {{local variable 'obj_short' does not live long enough}} \
+                                                                              
// tu-note {{expression aliases the storage of local variable 'obj_short'}}
   } // tu-note {{destroyed here}}
   (void)ptr; // tu-note {{later used here}}
 }
@@ -1093,7 +1107,8 @@ void lifetimebound_make_unique_multi_params3_2() {
   MyObj obj_long;
   {
     MyObj obj_short;
-    ptr = std::make_unique<MultiLifetimeBoundCtor>(obj_long, obj_short, 1.0); 
// tu-warning {{local variable 'obj_short' does not live long enough}}
+    ptr = std::make_unique<MultiLifetimeBoundCtor>(obj_long, obj_short, 1.0); 
// tu-warning {{local variable 'obj_short' does not live long enough}} \
+                                                                              
// tu-note {{expression aliases the storage of local variable 'obj_short'}}
   } // tu-note {{destroyed here}}
   (void)ptr; // tu-note {{later used here}}
 }
@@ -1245,7 +1260,8 @@ void parentheses(bool cond) {
 
   {
     MyObj a;
-    p = ((GetPointer((a))));  // expected-warning {{local variable 'a' does 
not live long enough}}
+    p = ((GetPointer((a))));  // expected-warning {{local variable 'a' does 
not live long enough}} \
+                              // expected-note {{expression aliases the 
storage of local variable 'a'}}
   }                           // expected-note {{destroyed here}}
   (void)*p;                   // expected-note {{later used here}}
 
@@ -1276,7 +1292,8 @@ void use_temporary_after_destruction() {
 
 void passing_temporary_to_lifetime_bound_function() {
   View a = construct_view(non_trivially_destructed_temporary()); // 
expected-warning {{local temporary object does not live long enough}} \
-                expected-note {{destroyed here}}
+                expected-note {{destroyed here}} \
+                expected-note {{expression aliases the storage of local 
temporary object}}
   use(a); // expected-note {{later used here}}
 }
 
@@ -1289,14 +1306,16 @@ void use_trivial_temporary_after_destruction() {
 
 namespace FullExprCleanupLoc {
 void var_initializer() {
-  View v = non_trivially_destructed_temporary() // expected-warning {{local 
temporary object does not live long enough}}
+  View v = non_trivially_destructed_temporary() // expected-warning {{local 
temporary object does not live long enough}} \
+                                                // expected-note {{expression 
aliases the storage of local temporary object}}
                .getView(); // expected-note {{destroyed here}}
   v.use(); // expected-note {{later used here}}
 }
 
 void expr_statement() {
   View v;
-  v = non_trivially_destructed_temporary() // expected-warning {{local 
temporary object does not live long enough}}
+  v = non_trivially_destructed_temporary() // expected-warning {{local 
temporary object does not live long enough}} \
+                                           // expected-note {{expression 
aliases the storage of local temporary object}}
           .getView(); // expected-note {{destroyed here}}
   v.use(); // expected-note {{later used here}}
 }
@@ -1339,7 +1358,8 @@ void foobar() {
   View view;
   {
     StatusOr<MyObj> string_or = getStringOr();
-    view = string_or. // expected-warning {{local variable 'string_or' does 
not live long enough}}
+    view = string_or. // expected-warning {{local variable 'string_or' does 
not live long enough}} \
+                      // expected-note {{expression aliases the storage of 
local variable 'string_or'}}
             value();
   }                     // expected-note {{destroyed here}}
   (void)view;           // expected-note {{later used here}}
@@ -1413,7 +1433,8 @@ 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}}
+    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'}}
   }                     // expected-note {{destroyed here}}
   (void)*p;             // expected-note {{later used here}}
 }
@@ -1430,7 +1451,8 @@ 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}}
+    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'}}
   }                  // expected-note {{destroyed here}}
   v.use();           // expected-note {{later used here}}
 }
@@ -1440,7 +1462,8 @@ 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}}
+    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'}}
   }                              // expected-note {{destroyed here}}
   (void)*p;                      // expected-note {{later used here}}
 }
@@ -1450,7 +1473,8 @@ 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}}
+    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'}}
   }                       // expected-note {{destroyed here}}
   (void)*p;               // expected-note {{later used here}}
 }
@@ -1636,13 +1660,15 @@ void wrong_use_of_move_is_permissive() {
   View v;
   {
     MyObj a;
-    v = std::move(a); // expected-warning {{local variable 'a' does not live 
long enough}}
+    v = std::move(a); // expected-warning {{local variable 'a' does not live 
long enough}} \
+                      // expected-note {{expression aliases the storage of 
local variable 'a'}}
   }         // expected-note {{destroyed here}}
   (void)v;  // expected-note {{later used here}}
   const int* p;
   {
     MyObj a;
-    p = std::move(a).getData(); // expected-warning {{local variable 'a' does 
not live long enough}}
+    p = std::move(a).getData(); // expected-warning {{local variable 'a' does 
not live long enough}} \
+                                // expected-note 2 {{expression aliases the 
storage of local variable 'a'}}
   }         // expected-note {{destroyed here}}
   (void)p;  // expected-note {{later used here}}
 }
@@ -1653,7 +1679,8 @@ void test_release_no_uaf() {
   // Calling release() marks p as moved from, so its destruction doesn't 
invalidate r.
   {
     std::unique_ptr<int> p;
-    r = p.get();        // expected-warning {{local variable 'p' may not live 
long enough. This could be a false positive as the storage may have been moved 
later}}
+    r = p.get();        // expected-warning {{local variable 'p' may not live 
long enough. This could be a false positive as the storage may have been moved 
later}} \
+                        // expected-note {{expression aliases the storage of 
local variable 'p'}}
     take(p.release());  // expected-note {{potentially moved here}}
   }                     // expected-note {{destroyed here}}
   (void)*r;             // expected-note {{later used here}}
@@ -1675,9 +1702,11 @@ void bar() {
     View x;
     {
         S s;
-        x = s.x(); // expected-warning {{local variable 's' does not live long 
enough}}
+        x = s.x(); // expected-warning {{local variable 's' does not live long 
enough}} \
+                   // expected-note {{expression aliases the storage of local 
variable 's'}}
         View y = S().x(); // expected-warning {{local temporary object does 
not live long enough}} \
-                             expected-note {{destroyed here}}
+                             expected-note {{destroyed here}} \
+                             expected-note {{expression aliases the storage of 
local temporary object}}
         (void)y; // expected-note {{used here}}
     } // expected-note {{destroyed here}}
     (void)x; // expected-note {{used here}}
@@ -1765,17 +1794,20 @@ const std::string& identity(const std::string& in 
[[clang::lifetimebound]]);
 const S& identity(const S& in [[clang::lifetimebound]]);
 
 void test_temporary() {
-  const std::string& x = S().x(); // expected-warning {{local temporary object 
does not live long enough}} expected-note {{destroyed here}}
+  const std::string& x = S().x(); // expected-warning {{local temporary object 
does not live long enough}} expected-note {{destroyed here}} \
+                                  // expected-note {{expression aliases the 
storage of local temporary object}}
   (void)x; // expected-note {{later used here}}
 
-  const std::string& y = identity(S().x()); // expected-warning {{local 
temporary object does not live long enough}} expected-note {{destroyed here}}
+  const std::string& y = identity(S().x()); // expected-warning {{local 
temporary object does not live long enough}} expected-note {{destroyed here}} \
+                                            // expected-note 2 {{expression 
aliases the storage of local temporary object}}
   (void)y; // expected-note {{later used here}}
 
   std::string_view z;
   {
     S s;
-    const std::string& zz = s.x(); // expected-warning {{local variable 's' 
does not live long enough}}
-    z = zz;
+    const std::string& zz = s.x(); // expected-warning {{local variable 's' 
does not live long enough}} \
+                                   // expected-note {{expression aliases the 
storage of local variable 's'}}
+    z = zz;                        // expected-note {{expression aliases the 
storage of local variable 's'}}
   } // expected-note {{destroyed here}}
   (void)z; // expected-note {{later used here}}
 }
@@ -1783,12 +1815,14 @@ void test_temporary() {
 void test_lifetime_extension_ok() {
   const S& x = S();
   (void)x;
-  const S& y = identity(S()); // expected-warning {{local temporary object 
does not live long enough}} expected-note {{destroyed here}}
+  const S& y = identity(S()); // expected-warning {{local temporary object 
does not live long enough}} expected-note {{destroyed here}} \
+                              // expected-note {{expression aliases the 
storage of local temporary object}}
   (void)y; // expected-note {{later used here}}
 }
 
 const std::string& test_return() {
-  const std::string& x = S().x(); // expected-warning {{local temporary object 
does not live long enough}} expected-note {{destroyed here}}
+  const std::string& x = S().x(); // expected-warning {{local temporary object 
does not live long enough}} expected-note {{destroyed here}} \
+                                  // expected-note {{expression aliases the 
storage of local temporary object}}
   return x; // expected-note {{later used here}}
 }
 } // namespace reference_type_decl_ref_expr
@@ -1805,7 +1839,8 @@ void uaf() {
   {
     S str;
     S* p = &str;  // expected-warning {{local variable 'str' does not live 
long enough}}
-    view = p->s;
+    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'}}
   } // expected-note {{destroyed here}}
   (void)view;  // expected-note {{later used here}}
 }
@@ -1830,8 +1865,9 @@ void uaf_union() {
   std::string_view view;
   {
     U u = U{"hello"};
-    U* up = &u;  // expected-warning {{local variable 'u' does not live long 
enough}}
-    view = up->s;
+    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'}}
   } // expected-note {{destroyed here}}
   (void)view;  // expected-note {{later used here}}
 }
@@ -1848,7 +1884,7 @@ void uaf_anonymous_union() {
   {
     AnonymousUnion au;
     AnonymousUnion* up = &au;  // expected-warning {{local variable 'au' does 
not live long enough}}
-    ip = &up->x;
+    ip = &up->x;               // expected-note {{local variable 'up' aliases 
the storage of local variable 'au'}}
   } // expected-note {{destroyed here}}
   (void)ip;  // expected-note {{later used here}}
 }
@@ -1906,9 +1942,12 @@ const T* MemberFuncsTpl<T>::memberC(const T& x 
[[clang::lifetimebound]]) {
 
 void test() {
   MemberFuncsTpl<MyObj> mtf;
-  const MyObj* pTMA = mtf.memberA(MyObj()); // expected-warning {{local 
temporary object does not live long enough}} // expected-note {{destroyed here}}
-  const MyObj* pTMB = mtf.memberB(MyObj()); // tu-warning {{local temporary 
object does not live long enough}} // tu-note {{destroyed here}}
-  const MyObj* pTMC = mtf.memberC(MyObj()); // expected-warning {{local 
temporary object does not live long enough}} // expected-note {{destroyed here}}
+  const MyObj* pTMA = mtf.memberA(MyObj()); // expected-warning {{local 
temporary object does not live long enough}} // expected-note {{destroyed 
here}} \
+                                            // expected-note {{expression 
aliases the storage of local temporary object}}
+  const MyObj* pTMB = mtf.memberB(MyObj()); // tu-warning {{local temporary 
object does not live long enough}} // tu-note {{destroyed here}} \
+                                            // tu-note {{expression aliases 
the storage of local temporary object}}
+  const MyObj* pTMC = mtf.memberC(MyObj()); // expected-warning {{local 
temporary object does not live long enough}} // expected-note {{destroyed 
here}} \
+                                            // expected-note {{expression 
aliases the storage of local temporary object}}
   (void)pTMA; // expected-note {{later used here}}
   (void)pTMB; // tu-note {{later used here}}
   (void)pTMC; // expected-note {{later used here}}
@@ -1943,7 +1982,8 @@ void test_optional_arrow() {
   const char* p;
   {
     std::optional<std::string> opt;
-    p = opt->data();  // expected-warning {{local variable 'opt' does not live 
long enough}}
+    p = opt->data();  // expected-warning {{local variable 'opt' does not live 
long enough}} \
+                      // expected-note 2 {{expression aliases the storage of 
local variable 'opt'}}
   }                   // expected-note {{destroyed here}}
   (void)*p;           // expected-note {{later used here}}
 }
@@ -1952,7 +1992,8 @@ void test_optional_arrow_lifetimebound() {
   View v;
   {
     std::optional<MyObj> opt;
-    v = opt->getView();  // expected-warning {{local variable 'opt' does not 
live long enough}}
+    v = opt->getView();  // expected-warning {{local variable 'opt' does not 
live long enough}} \
+                         // expected-note 2 {{expression aliases the storage 
of local variable 'opt'}}
   }                      // expected-note {{destroyed here}}
   v.use();               // expected-note {{later used here}}
 }
@@ -1961,7 +2002,8 @@ void test_unique_ptr_arrow() {
   const char* p;
   {
     std::unique_ptr<std::string> up;
-    p = up->data();  // expected-warning {{local variable 'up' does not live 
long enough}}
+    p = up->data();  // expected-warning {{local variable 'up' does not live 
long enough}} \
+                     // expected-note 2 {{expression aliases the storage of 
local variable 'up'}}
   }                  // expected-note {{destroyed here}}
   (void)*p;          // expected-note {{later used here}}
 }
@@ -2313,9 +2355,9 @@ struct S {
 
 void indexing_with_static_operator() {
   S()(1, 2);
-  S& x = S()("1",
-             2,  // expected-warning {{local temporary object does not live 
long enough}}
-             3); // expected-warning {{local temporary object does not live 
long enough}} expected-note 2 {{destroyed here}}
+  S& x = S()("1", // expected-note 2 {{expression aliases the storage of local 
temporary object}}
+             2,   // expected-warning {{local temporary object does not live 
long enough}}
+             3);  // expected-warning {{local temporary object does not live 
long enough}} expected-note 2 {{destroyed here}}
 
   (void)x; // expected-note 2 {{later used here}}
 
@@ -2338,7 +2380,8 @@ S getS(const std::string &s [[clang::lifetimebound]]);
 
 void from_free_function() {
   S s = getS(std::string("temp")); // expected-warning {{local temporary 
object does not live long enough}} \
-                                   // expected-note {{destroyed here}}
+                                   // expected-note {{destroyed here}} \
+                                   // expected-note {{expression aliases the 
storage of local temporary object}}
   use(s);                          // expected-note {{later used here}}
 }
 
@@ -2357,13 +2400,15 @@ struct Factory {
 void from_method() {
   Factory f;
   S s = f.make(std::string("temp")); // expected-warning {{local temporary 
object does not live long enough}} \
-                                     // expected-note {{destroyed here}}
+                                     // expected-note {{destroyed here}} \
+                                     // expected-note {{expression aliases the 
storage of local temporary object}}
   use(s);                            // expected-note {{later used here}}
 }
 
 void from_static_method() {
   S s = Factory::create(std::string("temp")); // expected-warning {{local 
temporary object does not live long enough}} \
-                                              // expected-note {{destroyed 
here}}
+                                              // expected-note {{destroyed 
here}} \
+                                              // expected-note {{expression 
aliases the storage of local temporary object}}
   use(s);                                     // expected-note {{later used 
here}}
 }
 
@@ -2371,7 +2416,8 @@ void from_lifetimebound_this_method() {
   S value;
   {
     Factory f;
-    value = f.makeThis(); // expected-warning {{local variable 'f' does not 
live long enough}}
+    value = f.makeThis(); // expected-warning {{local variable 'f' does not 
live long enough}} \
+                          // expected-note {{expression aliases the storage of 
local variable 'f'}}
   }                       // expected-note {{destroyed here}}
   use(value);             // expected-note {{later used here}}
 }
@@ -2380,7 +2426,8 @@ void across_scope() {
   S s{};
   {
     std::string str{"abc"};
-    s = getS(str); // expected-warning {{local variable 'str' does not live 
long enough}}
+    s = getS(str); // expected-warning {{local variable 'str' does not live 
long enough}} \
+                   // expected-note {{expression aliases the storage of local 
variable 'str'}}
   }                // expected-note {{destroyed here}}
   use(s);          // expected-note {{later used here}}
 }
@@ -2402,8 +2449,9 @@ void assignment_propagation() {
   S a, b;
   {
     std::string str{"abc"};
-    a = getS(str); // expected-warning {{local variable 'str' does not live 
long enough}}
-    b = a;
+    a = getS(str); // expected-warning {{local variable 'str' does not live 
long enough}} \
+                   // expected-note {{expression aliases the storage of local 
variable 'str'}}
+    b = a;         // expected-note {{local variable 'a' aliases the storage 
of local variable 'str'}}
   }                // expected-note {{destroyed here}}
   use(b);          // expected-note {{later used here}}
 }
@@ -2412,8 +2460,10 @@ void chained_defaulted_assignment_propagation() {
   S b, c;
   {
     std::string str{"abc"};
-    S a = getS(str); // expected-warning {{local variable 'str' does not live 
long enough}}
-    c = b = a;
+    S a = getS(str); // expected-warning {{local variable 'str' does not live 
long enough}} \
+                     // expected-note {{expression aliases the storage of 
local variable 'str'}}
+    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 {{destroyed here}}
   use(c);            // expected-note {{later used here}}
 }
@@ -2427,7 +2477,8 @@ void no_annotation() {
 
 void mix_annotated_and_not() {
   S s1 = getS(std::string("temp")); // expected-warning {{local temporary 
object does not live long enough}} \
-                                    // expected-note {{destroyed here}}
+                                    // expected-note {{destroyed here}} \
+                                    // expected-note {{expression aliases the 
storage of local temporary object}}
   S s2 = getSNoAnnotation(std::string("temp"));
   use(s1); // expected-note {{later used here}}
   use(s2);
@@ -2439,6 +2490,7 @@ S multiple_lifetimebound_params() {
   std::string str{"abc"};
   S s = getS2(str, std::string("temp")); // expected-warning {{stack memory 
associated with local variable 'str' is returned}} \
                                          // expected-warning {{local temporary 
object does not live long enough}} \
+                                         // expected-note {{expression aliases 
the storage of local temporary object}} \
                                          // expected-note {{destroyed here}}
   return s;                              // expected-note {{returned here}} \
                                          // expected-note {{later used here}}
@@ -2458,7 +2510,8 @@ T make(const std::string &s [[clang::lifetimebound]]);
 
 void from_template_instantiation() {
   S s = make<S>(std::string("temp")); // expected-warning {{local temporary 
object does not live long enough}} \
-                                      // expected-note {{destroyed here}}
+                                      // expected-note {{destroyed here}} \
+                                      // expected-note {{expression aliases 
the storage of local temporary object}}
   use(s);                             // expected-note {{later used here}}
 }
 
@@ -2521,7 +2574,8 @@ SAlias getSAlias(const std::string &s 
[[clang::lifetimebound]]);
 
 void from_typedef_return() {
   SAlias s = getSAlias(std::string("temp")); // expected-warning {{local 
temporary object does not live long enough}} \
-                                             // expected-note {{destroyed 
here}}
+                                             // expected-note {{destroyed 
here}} \
+                                             // expected-note {{expression 
aliases the storage of local temporary object}}
   use(s);                                    // expected-note {{later used 
here}}
 }
 
@@ -2595,7 +2649,8 @@ std::unique_ptr<S> getUniqueS(const std::string &s 
[[clang::lifetimebound]]);
 
 void owner_return_unique_ptr_s() {
   auto ptr = getUniqueS(std::string("temp")); // expected-warning {{local 
temporary object does not live long enough}} \
-                                              // expected-note {{destroyed 
here}}
+                                              // expected-note {{destroyed 
here}} \
+                                              // expected-note {{expression 
aliases the storage of local temporary object}}
   (void)ptr;                                  // expected-note {{later used 
here}}
 }
 
@@ -2611,7 +2666,8 @@ void owner_outlives_lifetimebound_source() {
   std::unique_ptr<S> ups;
   {
     std::string local;
-    ups = getUniqueS(local); // expected-warning {{local variable 'local' does 
not live long enough}}
+    ups = getUniqueS(local); // expected-warning {{local variable 'local' does 
not live long enough}} \
+                             // expected-note {{expression aliases the storage 
of local variable 'local'}}
   } // expected-note {{destroyed here}}
   (void)ups; // expected-note {{later used here}}
 }
@@ -2646,8 +2702,8 @@ void nested_local_pointer() {
   {
     Bar v;
     p = Pointer(v);     // expected-warning {{local variable 'v' does not live 
long enough}}
-    pp = Pointer(p);
-    ppp = Pointer(pp);
+    pp = Pointer(p);    // expected-note {{local variable 'p' aliases the 
storage of local variable 'v'}}
+    ppp = Pointer(pp);  // expected-note {{local variable 'pp' aliases the 
storage of local variable 'v'}}
   }                     // expected-note {{destroyed here}}
   use(***ppp);          // expected-note {{later used here}}
 }
@@ -2792,7 +2848,7 @@ void new_pointer_from_pointer() {
   {
     MyObj obj;
     MyObj *q = &obj;    // expected-warning {{local variable 'obj' does not 
live long enough}}
-    p = new MyObj *(q); 
+    p = new MyObj *(q); // expected-note {{local variable 'q' aliases the 
storage of local variable 'obj'}}
   }                     // expected-note {{destroyed here}}
   (void)**p;            // expected-note {{later used here}}
 }
@@ -3387,7 +3443,8 @@ void uaf_via_lifetimebound() {
   std::function<void()> f = []() {};
   {
     int local;
-    f = capture_lifetimebound_param(local); // expected-warning {{local 
variable 'local' does not live long enough}}
+    f = capture_lifetimebound_param(local); // expected-warning {{local 
variable 'local' does not live long enough}} \
+                                            // expected-note {{expression 
aliases the storage of local variable 'local'}}
   } // expected-note {{destroyed here}}
   (void)f; // expected-note {{later used here}}
 }
@@ -3450,7 +3507,8 @@ void deref_use_after_scope() {
   const MyObj* p;
   {
     optional<MyObj> opt;
-    p = &*opt; // expected-warning {{local variable 'opt' does not live long 
enough}}
+    p = &*opt; // expected-warning {{local variable 'opt' does not live long 
enough}} \
+               // expected-note {{expression aliases the storage of local 
variable 'opt'}}
   }            // expected-note {{destroyed here}}
   (void)p->id; // expected-note {{later used here}}
 }
@@ -3520,7 +3578,7 @@ void transitive_capture() {
   {
     MyObj local;
     setCaptureBy(v1, local); // expected-warning {{local variable 'local' does 
not live long enough}}
-    setCaptureBy(v2, v1);   
+    setCaptureBy(v2, v1);    // expected-note {{local variable 'v1' aliases 
the storage of local variable 'local'}}
   }                 // expected-note {{destroyed here}}
   (void)v2;         // expected-note {{later used here}}   
 }


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to