https://github.com/suoyuan666 updated 
https://github.com/llvm/llvm-project/pull/199345

>From 02bbdc2c415f3364c7b27057758c10a9f594f03d Mon Sep 17 00:00:00 2001
From: Yuan Suo <[email protected]>
Date: Fri, 22 May 2026 15:10:28 +0800
Subject: [PATCH 1/3] [LifetimeSafety] Introduce buildOriginFlowChain for
 use-after-scope

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.

Signed-off-by: Yuan Suo <[email protected]>
---
 .../Analyses/LifetimeSafety/LifetimeSafety.h  |  7 ++-
 .../clang/Basic/DiagnosticSemaKinds.td        |  1 +
 clang/lib/Analysis/LifetimeSafety/Checker.cpp | 56 ++++++++++++++++++-
 clang/lib/Sema/SemaLifetimeSafety.h           | 25 ++++++++-
 clang/test/Sema/warn-lifetime-safety.cpp      |  6 +-
 5 files changed, 86 insertions(+), 9 deletions(-)

diff --git 
a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h 
b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
index 398cce1395854..42f7d80f90a02 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
@@ -61,9 +61,10 @@ class LifetimeSafetySemaHelper {
   LifetimeSafetySemaHelper() = default;
   virtual ~LifetimeSafetySemaHelper() = default;
 
-  virtual void reportUseAfterScope(const Expr *IssueExpr, const Expr *UseExpr,
-                                   const Expr *MovedExpr,
-                                   SourceLocation FreeLoc) {}
+  virtual void
+  reportUseAfterScope(const Expr *IssueExpr, const Expr *UseExpr,
+                      const Expr *MovedExpr, SourceLocation FreeLoc,
+                      llvm::SmallVector<const Expr *> OriginExprChain) {}
 
   virtual void reportUseAfterReturn(const Expr *IssueExpr,
                                     const Expr *ReturnExpr,
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 077aace321264..54fb4c2fbc6c8 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -11047,6 +11047,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_note_alias_chain : 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 d6d4ec6b5617e..2947c70301a44 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -260,10 +260,25 @@ class LifetimeChecker {
             SemaHelper->reportUseAfterInvalidation(
                 InvalidatedPVD, UF->getUseExpr(), Warning.InvalidatedByExpr);
 
-        } else
+        } else {
           // Scope-based expiry (use-after-scope).
+
+          llvm::SmallVector<OriginID> OriginFlowChain;
+
+          for (const OriginList *Cur = UF->getUsedOrigins(); Cur;
+               Cur = Cur->peelOuterOrigin())
+            if (LoanPropagation.getLoans(Cur->getOuterOriginID(), UF)
+                    .contains(LID))
+              OriginFlowChain = LoanPropagation.buildOriginFlowChain(
+                  FactMgr, UF, Cur->getOuterOriginID(), LID);
+
+          const llvm::SmallVector<const Expr *> OriginExprChain =
+              buildExprOrDeclChain(OriginFlowChain);
           SemaHelper->reportUseAfterScope(IssueExpr, UF->getUseExpr(),
-                                          MovedExpr, ExpiryLoc);
+                                          MovedExpr, ExpiryLoc,
+                                          OriginExprChain);
+        }
+
       } else if (const auto *OEF =
                      CausingFact.dyn_cast<const OriginEscapesFact *>()) {
         if (Warning.InvalidatedByExpr) {
@@ -487,6 +502,43 @@ class LifetimeChecker {
       }
     }
   }
+
+  /// Retrieve a list of reliable expressions from OriginIFlowChain that
+  /// can be used for Sema warnings.
+  ///
+  /// Although the AST node corresponding to Origin can be either a
+  /// `const Expr *` or a `const ValueDecl *`, `buildOriginFlowChain` only
+  /// collects Origins from RHS expressions. Therefore, we do not need to
+  /// handle non-expression cases here.
+  llvm::SmallVector<const Expr *>
+  buildExprOrDeclChain(llvm::ArrayRef<OriginID> OriginFlowChain) {
+    llvm::SmallVector<const Expr *> rs;
+    const SourceManager &SM = AST.getSourceManager();
+
+    auto InsertOrReplace = [&rs, &SM](const Expr *NewNode) {
+      if (!NewNode)
+        return;
+      SourceLocation NewLocation = NewNode->getExprLoc();
+      if (NewLocation.isInvalid())
+        return;
+
+      const Expr *LastNode = rs.back();
+      SourceLocation LastLocation = LastNode->getExprLoc();
+      if (SM.getSpellingLineNumber(LastLocation) ==
+          SM.getSpellingLineNumber(NewLocation))
+        rs.back() = NewNode;
+      else
+        rs.push_back(NewNode);
+    };
+
+    for (const OriginID CurrOID : OriginFlowChain)
+      if (!rs.empty())
+        InsertOrReplace(FactMgr.getOriginMgr().getOrigin(CurrOID).getExpr());
+      else
+        rs.push_back(FactMgr.getOriginMgr().getOrigin(CurrOID).getExpr());
+
+    return rs;
+  }
 };
 } // namespace
 
diff --git a/clang/lib/Sema/SemaLifetimeSafety.h 
b/clang/lib/Sema/SemaLifetimeSafety.h
index 6da4953dea56d..1ce4ddea838b7 100644
--- a/clang/lib/Sema/SemaLifetimeSafety.h
+++ b/clang/lib/Sema/SemaLifetimeSafety.h
@@ -55,6 +55,15 @@ inline bool IsLifetimeSafetyEnabled(Sema &S, const Decl *D) {
   return false;
 }
 
+inline StringRef formatExpr(const Expr *E) {
+  const Expr *PureExpr = E->IgnoreImpCasts();
+  if (const DeclRefExpr *DRExpr = dyn_cast<DeclRefExpr>(PureExpr))
+    return DRExpr->getDecl()->getName();
+
+  // TODO: Add support for more expression types.
+  return "";
+}
+
 class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper {
 
 public:
@@ -62,17 +71,31 @@ class LifetimeSafetySemaHelperImpl : public 
LifetimeSafetySemaHelper {
 
   void reportUseAfterScope(const Expr *IssueExpr, const Expr *UseExpr,
                            const Expr *MovedExpr,
-                           SourceLocation FreeLoc) override {
+                           SourceLocation FreeLoc, llvm::SmallVector<const 
Expr *> OriginExprChain) override {
     unsigned DiagID = MovedExpr
                           ? diag::warn_lifetime_safety_use_after_scope_moved
                           : diag::warn_lifetime_safety_use_after_scope;
 
     S.Diag(IssueExpr->getExprLoc(), DiagID)
         << getDiagSubjectDescription(IssueExpr) << IssueExpr->getSourceRange();
+
     if (MovedExpr)
       S.Diag(MovedExpr->getExprLoc(), diag::note_lifetime_safety_moved_here)
           << MovedExpr->getSourceRange();
     S.Diag(FreeLoc, diag::note_lifetime_safety_destroyed_here);
+
+    StringRef IssueStr;
+    for (const Expr *CurrExpr : reverse(OriginExprChain)) {
+      if (IssueStr.empty()) {
+        IssueStr = formatExpr(CurrExpr);
+        continue;
+      }
+
+      S.Diag(CurrExpr->getBeginLoc(),
+             diag::note_lifetime_safety_aliases_storage)
+          << CurrExpr->getSourceRange() << formatExpr(CurrExpr) << IssueStr;
+    }
+
     S.Diag(UseExpr->getExprLoc(), diag::note_lifetime_safety_used_here)
         << UseExpr->getSourceRange();
   }
diff --git a/clang/test/Sema/warn-lifetime-safety.cpp 
b/clang/test/Sema/warn-lifetime-safety.cpp
index 06097d4600af5..90708bd4c3e15 100644
--- a/clang/test/Sema/warn-lifetime-safety.cpp
+++ b/clang/test/Sema/warn-lifetime-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 {{p aliases the storage of s}}
   }             // expected-note {{destroyed here}}
   (void)*q;     // expected-note {{later used here}}
 }
@@ -1759,8 +1759,8 @@ void test_temporary() {
   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 {{object whose 
reference is captured does not live long enough}}
+    z = zz;                        // expected-note {{aliases the storage of 
s}}
   } // expected-note {{destroyed here}}
   (void)z; // expected-note {{later used here}}
 }

>From d6a2df274463e6490f17bf17617334328bb86c8b Mon Sep 17 00:00:00 2001
From: Yuan Suo <[email protected]>
Date: Thu, 28 May 2026 09:58:12 +0800
Subject: [PATCH 2/3] Reduce the side effects of buildExprOrDeclChain and apply
 some minor cleanups

Previously, `buildExprOrDeclChain` was responsible not only for constructing an 
expression list,
but also for filtering out expressions that should not be emitted.

However, this filtering logic does not need to be handled there.

Signed-off-by: Yuan Suo <[email protected]>
---
 .../Analyses/LifetimeSafety/LifetimeSafety.h  |  5 +-
 clang/lib/Analysis/LifetimeSafety/Checker.cpp | 36 +++-----------
 clang/lib/Sema/SemaLifetimeSafety.h           | 48 ++++++++++++++-----
 3 files changed, 48 insertions(+), 41 deletions(-)

diff --git 
a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h 
b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
index 42f7d80f90a02..d635105043b26 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
@@ -61,10 +61,13 @@ class LifetimeSafetySemaHelper {
   LifetimeSafetySemaHelper() = default;
   virtual ~LifetimeSafetySemaHelper() = default;
 
+  virtual void
+  reportAliasingChain(llvm::ArrayRef<const Expr *> OriginExprChain) {}
+
   virtual void
   reportUseAfterScope(const Expr *IssueExpr, const Expr *UseExpr,
                       const Expr *MovedExpr, SourceLocation FreeLoc,
-                      llvm::SmallVector<const Expr *> OriginExprChain) {}
+                      llvm::ArrayRef<const Expr *> OriginExprChain) {}
 
   virtual void reportUseAfterReturn(const Expr *IssueExpr,
                                     const Expr *ReturnExpr,
diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp 
b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
index 2947c70301a44..3abdf92e2989a 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -503,40 +503,18 @@ class LifetimeChecker {
     }
   }
 
-  /// Retrieve a list of reliable expressions from OriginIFlowChain that
-  /// can be used for Sema warnings.
+  /// Extract expressions from the origin flow chain for diagnostic purposes.
   ///
-  /// Although the AST node corresponding to Origin can be either a
-  /// `const Expr *` or a `const ValueDecl *`, `buildOriginFlowChain` only
-  /// collects Origins from RHS expressions. Therefore, we do not need to
-  /// handle non-expression cases here.
+  /// 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 *>
   buildExprOrDeclChain(llvm::ArrayRef<OriginID> OriginFlowChain) {
     llvm::SmallVector<const Expr *> rs;
-    const SourceManager &SM = AST.getSourceManager();
-
-    auto InsertOrReplace = [&rs, &SM](const Expr *NewNode) {
-      if (!NewNode)
-        return;
-      SourceLocation NewLocation = NewNode->getExprLoc();
-      if (NewLocation.isInvalid())
-        return;
-
-      const Expr *LastNode = rs.back();
-      SourceLocation LastLocation = LastNode->getExprLoc();
-      if (SM.getSpellingLineNumber(LastLocation) ==
-          SM.getSpellingLineNumber(NewLocation))
-        rs.back() = NewNode;
-      else
-        rs.push_back(NewNode);
-    };
-
     for (const OriginID CurrOID : OriginFlowChain)
-      if (!rs.empty())
-        InsertOrReplace(FactMgr.getOriginMgr().getOrigin(CurrOID).getExpr());
-      else
-        rs.push_back(FactMgr.getOriginMgr().getOrigin(CurrOID).getExpr());
-
+      if (const Expr *CurrExpr =
+              FactMgr.getOriginMgr().getOrigin(CurrOID).getExpr())
+        rs.push_back(CurrExpr);
     return rs;
   }
 };
diff --git a/clang/lib/Sema/SemaLifetimeSafety.h 
b/clang/lib/Sema/SemaLifetimeSafety.h
index 1ce4ddea838b7..a4f0b7db9705c 100644
--- a/clang/lib/Sema/SemaLifetimeSafety.h
+++ b/clang/lib/Sema/SemaLifetimeSafety.h
@@ -64,11 +64,47 @@ inline StringRef formatExpr(const Expr *E) {
   return "";
 }
 
+inline bool shouldShowInAliasingChain(const Expr *CurrExpr,
+                                      const Expr *LastExpr) {
+  if (isa<ImplicitCastExpr>(CurrExpr))
+    return false;
+  if (isa<ParenExpr>(CurrExpr))
+    return false;
+  if (isa<CastExpr>(CurrExpr))
+    return false;
+  if (CurrExpr->getSourceRange().isInvalid())
+    return false;
+
+  if (LastExpr && CurrExpr->getSourceRange() == LastExpr->getSourceRange())
+    return false;
+
+  return true;
+}
+
 class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper {
 
 public:
   LifetimeSafetySemaHelperImpl(Sema &S) : S(S) {}
 
+  void
+  reportAliasingChain(llvm::ArrayRef<const Expr *> OriginExprChain) override {
+    StringRef IssueStr;
+    const Expr *LastExpr = nullptr;
+    for (const Expr *CurrExpr : reverse(OriginExprChain)) {
+      if (IssueStr.empty()) {
+        IssueStr = formatExpr(CurrExpr);
+        continue;
+      }
+
+      if (shouldShowInAliasingChain(CurrExpr, LastExpr)) {
+        S.Diag(CurrExpr->getBeginLoc(),
+               diag::note_lifetime_safety_note_alias_chain)
+            << CurrExpr->getSourceRange() << formatExpr(CurrExpr) << IssueStr;
+        LastExpr = CurrExpr;
+      }
+    }
+  }
+
   void reportUseAfterScope(const Expr *IssueExpr, const Expr *UseExpr,
                            const Expr *MovedExpr,
                            SourceLocation FreeLoc, llvm::SmallVector<const 
Expr *> OriginExprChain) override {
@@ -84,17 +120,7 @@ class LifetimeSafetySemaHelperImpl : public 
LifetimeSafetySemaHelper {
           << MovedExpr->getSourceRange();
     S.Diag(FreeLoc, diag::note_lifetime_safety_destroyed_here);
 
-    StringRef IssueStr;
-    for (const Expr *CurrExpr : reverse(OriginExprChain)) {
-      if (IssueStr.empty()) {
-        IssueStr = formatExpr(CurrExpr);
-        continue;
-      }
-
-      S.Diag(CurrExpr->getBeginLoc(),
-             diag::note_lifetime_safety_aliases_storage)
-          << CurrExpr->getSourceRange() << formatExpr(CurrExpr) << IssueStr;
-    }
+    reportAliasingChain(OriginExprChain);
 
     S.Diag(UseExpr->getExprLoc(), diag::note_lifetime_safety_used_here)
         << UseExpr->getSourceRange();

>From e7ecc7869cb12e4de594e7c07f61585bd60e249d Mon Sep 17 00:00:00 2001
From: Yuan Suo <[email protected]>
Date: Thu, 28 May 2026 21:08:16 +0800
Subject: [PATCH 3/3] rebase to use getDiagSubjectDescription

Signed-off-by: Yuan Suo <[email protected]>
---
 .../Analyses/LifetimeSafety/LifetimeSafety.h  |   3 -
 .../clang/Basic/DiagnosticSemaKinds.td        |   2 +-
 clang/lib/Analysis/LifetimeSafety/Checker.cpp |   4 +-
 clang/lib/Sema/SemaLifetimeSafety.h           |  98 +++++++-------
 .../Sema/warn-lifetime-analysis-nocfg.cpp     |  32 +++--
 .../Sema/warn-lifetime-safety-suggestions.cpp |   6 +-
 clang/test/Sema/warn-lifetime-safety.cpp      | 127 ++++++++++++------
 7 files changed, 163 insertions(+), 109 deletions(-)

diff --git 
a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h 
b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
index d635105043b26..78f39f4609358 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
@@ -61,9 +61,6 @@ class LifetimeSafetySemaHelper {
   LifetimeSafetySemaHelper() = default;
   virtual ~LifetimeSafetySemaHelper() = default;
 
-  virtual void
-  reportAliasingChain(llvm::ArrayRef<const Expr *> OriginExprChain) {}
-
   virtual void
   reportUseAfterScope(const Expr *IssueExpr, const Expr *UseExpr,
                       const Expr *MovedExpr, SourceLocation FreeLoc,
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 54fb4c2fbc6c8..0e1d13653a169 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -11047,7 +11047,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_note_alias_chain : Note<"%0 aliases the storage of 
%1">;
+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 3abdf92e2989a..2f5db5bd109c8 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -268,9 +268,11 @@ class LifetimeChecker {
           for (const OriginList *Cur = UF->getUsedOrigins(); Cur;
                Cur = Cur->peelOuterOrigin())
             if (LoanPropagation.getLoans(Cur->getOuterOriginID(), UF)
-                    .contains(LID))
+                    .contains(LID)) {
               OriginFlowChain = LoanPropagation.buildOriginFlowChain(
                   FactMgr, UF, Cur->getOuterOriginID(), LID);
+              break;
+            }
 
           const llvm::SmallVector<const Expr *> OriginExprChain =
               buildExprOrDeclChain(OriginFlowChain);
diff --git a/clang/lib/Sema/SemaLifetimeSafety.h 
b/clang/lib/Sema/SemaLifetimeSafety.h
index a4f0b7db9705c..0fe439b3a8569 100644
--- a/clang/lib/Sema/SemaLifetimeSafety.h
+++ b/clang/lib/Sema/SemaLifetimeSafety.h
@@ -55,59 +55,15 @@ inline bool IsLifetimeSafetyEnabled(Sema &S, const Decl *D) 
{
   return false;
 }
 
-inline StringRef formatExpr(const Expr *E) {
-  const Expr *PureExpr = E->IgnoreImpCasts();
-  if (const DeclRefExpr *DRExpr = dyn_cast<DeclRefExpr>(PureExpr))
-    return DRExpr->getDecl()->getName();
-
-  // TODO: Add support for more expression types.
-  return "";
-}
-
-inline bool shouldShowInAliasingChain(const Expr *CurrExpr,
-                                      const Expr *LastExpr) {
-  if (isa<ImplicitCastExpr>(CurrExpr))
-    return false;
-  if (isa<ParenExpr>(CurrExpr))
-    return false;
-  if (isa<CastExpr>(CurrExpr))
-    return false;
-  if (CurrExpr->getSourceRange().isInvalid())
-    return false;
-
-  if (LastExpr && CurrExpr->getSourceRange() == LastExpr->getSourceRange())
-    return false;
-
-  return true;
-}
-
 class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper {
 
 public:
   LifetimeSafetySemaHelperImpl(Sema &S) : S(S) {}
 
   void
-  reportAliasingChain(llvm::ArrayRef<const Expr *> OriginExprChain) override {
-    StringRef IssueStr;
-    const Expr *LastExpr = nullptr;
-    for (const Expr *CurrExpr : reverse(OriginExprChain)) {
-      if (IssueStr.empty()) {
-        IssueStr = formatExpr(CurrExpr);
-        continue;
-      }
-
-      if (shouldShowInAliasingChain(CurrExpr, LastExpr)) {
-        S.Diag(CurrExpr->getBeginLoc(),
-               diag::note_lifetime_safety_note_alias_chain)
-            << CurrExpr->getSourceRange() << formatExpr(CurrExpr) << IssueStr;
-        LastExpr = CurrExpr;
-      }
-    }
-  }
-
-  void reportUseAfterScope(const Expr *IssueExpr, const Expr *UseExpr,
-                           const Expr *MovedExpr,
-                           SourceLocation FreeLoc, llvm::SmallVector<const 
Expr *> OriginExprChain) override {
+  reportUseAfterScope(const Expr *IssueExpr, const Expr *UseExpr,
+                      const Expr *MovedExpr, SourceLocation FreeLoc,
+                      llvm::ArrayRef<const Expr *> OriginExprChain) override {
     unsigned DiagID = MovedExpr
                           ? diag::warn_lifetime_safety_use_after_scope_moved
                           : diag::warn_lifetime_safety_use_after_scope;
@@ -529,6 +485,54 @@ class LifetimeSafetySemaHelperImpl : public 
LifetimeSafetySemaHelper {
     return "";
   }
 
+  const Expr *extractExpr(const Expr *E) {
+    // FIXME: Ideally, this should use IgnoreParenImpCasts().
+    // However, according to the comment on IgnoreParenImpCasts(),
+    // it is not fully equivalent to IgnoreImpCasts() + IgnoreParens().
+    // Once the FIXME in IgnoreParenImpCasts() is resolved,
+    // this can be switched to use IgnoreParenImpCasts().
+    const Expr *PureExpr = E->IgnoreImpCasts()->IgnoreParens();
+
+    if (const auto *UO = dyn_cast<UnaryOperator>(PureExpr))
+      return UO->getSubExpr();
+    // For a BinaryOperator, there is only one relevant case: assignment
+    // chains. Therefore, we only need to consider the LHS expression.
+    if (const auto *BO = dyn_cast<BinaryOperator>(PureExpr))
+      return BO->getLHS();
+
+    // TODO: Handle other expression types.
+    return PureExpr;
+  }
+
+  void reportAliasingChain(llvm::ArrayRef<const Expr *> OriginExprChain) {
+    std::string IssueStr;
+    const Expr *LastExpr = nullptr;
+    for (const Expr *CurrExpr : reverse(OriginExprChain)) {
+      if (IssueStr.empty()) {
+        IssueStr = getDiagSubjectDescription(CurrExpr);
+        LastExpr = CurrExpr;
+        continue;
+      }
+
+      const Expr *ExtractedExpr = extractExpr(CurrExpr);
+      if (LastExpr &&
+          ExtractedExpr->getSourceRange() == LastExpr->getSourceRange())
+        continue;
+
+      // FIXME: Because getDiagSubjectDescription and extractExpr is not fully
+      // implemented yet, some diagnostic that should have been issued are
+      // currently being skipped here.
+      std::string ExprName = getDiagSubjectDescription(ExtractedExpr);
+      if (ExprName.empty())
+        continue;
+
+      S.Diag(ExtractedExpr->getBeginLoc(),
+             diag::note_lifetime_safety_aliases_storage)
+          << ExtractedExpr->getSourceRange() << ExprName << IssueStr;
+      LastExpr = ExtractedExpr;
+    }
+  }
+
   Sema &S;
 };
 
diff --git a/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp 
b/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
index 41b07771c52c1..61e162f01947f 100644
--- a/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
+++ b/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
@@ -245,7 +245,8 @@ std::string_view containerWithAnnotatedElements() {
   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 {{local temporary object 
aliases the storage of local temporary object}}
   use(c1);                               // cfg-note {{later used here}}
 
   // no warning on constructing from gsl-pointer
@@ -862,7 +863,8 @@ std::string_view test1_1() {
                                             // cfg-warning {{local temporary 
object does not live long enough}} cfg-note {{destroyed here}}
   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 {{local temporary object 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}}
@@ -873,7 +875,8 @@ std::string_view test1_2() {
                                             // cfg-warning {{local temporary 
object does not live long enough}} cfg-note {{destroyed here}}
   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 {{local temporary object aliases the 
storage of local temporary object}}
   use(t2);                    // cfg-note {{later used here}}
 
   return TakeSv(std::string()); // expected-warning {{returning address}} \
@@ -885,7 +888,8 @@ std::string_view test1_3() {
                                                    // cfg-warning {{local 
temporary object does not live long enough}} cfg-note {{destroyed here}}
   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 {{local temporary object 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}}
@@ -910,7 +914,8 @@ std::string_view test2_1(Foo<std::string> r1, 
Foo<std::string_view> r2) {
                                                   // cfg-warning {{local 
temporary object does not live long enough}} cfg-note {{destroyed here}}
   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 {{local temporary object 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}}
@@ -941,7 +946,7 @@ struct [[gsl::Pointer]] Pointer {
 Pointer test3(Bar bar) {
   Pointer p = Pointer(Bar()); // expected-warning {{temporary}} cfg-warning 
{{local temporary object does not live long enough}} cfg-note {{destroyed here}}
   use(p);                     // cfg-note {{later used here}}
-  p = Pointer(Bar());         // expected-warning {{object backing}} 
cfg-warning {{local temporary object does not live long enough}} cfg-note 
{{destroyed here}}
+  p = Pointer(Bar());         // expected-warning {{object backing}} 
cfg-warning {{local temporary object does not live long enough}} cfg-note 
{{destroyed here}} cfg-note {{local temporary object aliases the storage of 
local temporary object}}
   use(p);                     // cfg-note {{later used here}}
   return bar;                 // expected-warning {{address of stack}} 
cfg-warning {{stack memory associated with parameter 'bar' is returned}} 
cfg-note {{returned here}}
 }
@@ -1028,9 +1033,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 {{local 
temporary object 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 {{local 
temporary object 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 {{local 
temporary object aliases the storage of local temporary object}}
 
   use(p, q, r, x, y, z); // cfg-note 3 {{later used here}}
 }
@@ -1042,9 +1050,9 @@ 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 {{local temporary object 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 {{local temporary object 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 {{local temporary object aliases the storage of local temporary 
object}}
 
   use(p, q, r, x, y, z); // cfg-note 3 {{later used here}}
 }
diff --git a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp 
b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
index f5a3cf89e4c8d..85b80a7af811b 100644
--- a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
+++ b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
@@ -599,7 +599,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 {{local 
temporary object aliases the storage of local variable 'local'}}
   } // expected-note {{destroyed here}}
   (void)f; // expected-note {{later used here}}
 }
@@ -622,7 +623,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 {{local temporary object 
aliases the storage of local variable 'obj'}}
   } // expected-note {{destroyed here}}
   (void)ptr; // expected-note {{later used here}}
 }
diff --git a/clang/test/Sema/warn-lifetime-safety.cpp 
b/clang/test/Sema/warn-lifetime-safety.cpp
index 90708bd4c3e15..d9fb06154c67e 100644
--- a/clang/test/Sema/warn-lifetime-safety.cpp
+++ b/clang/test/Sema/warn-lifetime-safety.cpp
@@ -92,7 +92,7 @@ void pointer_chain() {
   {
     MyObj s;
     p = &s;     // expected-warning {{does not live long enough}}
-    q = p;      // expected-note {{p aliases the storage of s}}
+    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}}
 }
@@ -138,7 +138,8 @@ void multiple_pointers_chained() {
   {
     MyObj s;
     MyObj* obj1, *obj2;
-    p = obj1 = obj2 = &s; // expected-warning {{does not live long enough}}
+    p = obj1 = obj2 = &s; // expected-warning {{does not live long enough}} \
+                          // expected-note 2 {{aliases the storage of local 
variable 's'}}
   }                       // expected-note {{destroyed here}}
   (void)*p;               // expected-note {{later used here}}
 }
@@ -696,7 +697,7 @@ 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 {{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 {{local temporary object 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 {{local temporary object aliases the 
storage of local variable 'obj1'}} \
+                      // expected-note {{local temporary object 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 {{local temporary object 
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 {{local temporary object 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 {{local temporary 
object aliases the storage of local variable 'obj'}}
   }                                        // expected-note {{destroyed here}}
   v.use();                                 // expected-note {{later used here}}
 }
@@ -913,7 +919,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 {{local variable 'obj' aliases 
the storage of local variable 's'}}
   }                         // expected-note {{destroyed here}}
   (void)*p;                 // expected-note {{later used here}}
 }
@@ -945,8 +952,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);
-    ptr = &ref;
+    const MyObj& ref = GetObject(temp_v); // expected-note {{local variable 
'temp_v' aliases the storage of local variable 'obj'}}
+    ptr = &ref;           // expected-note {{local variable 'ref' aliases the 
storage of local variable 'obj'}}
   }                       // expected-note {{destroyed here}}
   (void)*ptr;             // expected-note {{later used here}}
 }
@@ -972,7 +979,8 @@ void lifetimebound_ctor_functional_cast() {
   LifetimeBoundCtor v;
   {
     MyObj obj;
-    v = LifetimeBoundCtor(obj); // expected-warning {{local variable 'obj' 
does not live long enough}}
+    v = LifetimeBoundCtor(obj); // expected-warning {{local variable 'obj' 
does not live long enough}} \
+                                // expected-note {{local temporary object 
aliases the storage of local variable 'obj'}}
   }                             // expected-note {{destroyed here}}
   (void)v;                      // expected-note {{later used here}}
 }
@@ -981,7 +989,8 @@ void lifetimebound_ctor_c_style_cast() {
   LifetimeBoundCtor v;
   {
     MyObj obj;
-    v = (LifetimeBoundCtor)(obj); // expected-warning {{local variable 'obj' 
does not live long enough}}
+    v = (LifetimeBoundCtor)(obj); // expected-warning {{local variable 'obj' 
does not live long enough}} \
+                                  // expected-note {{local temporary object 
aliases the storage of local variable 'obj'}}
   }                               // expected-note {{destroyed here}}
   (void)v;                        // expected-note {{later used here}}
 }
@@ -990,7 +999,8 @@ void lifetimebound_ctor_static_cast() {
   LifetimeBoundCtor v;
   {
     MyObj obj;
-    v = static_cast<LifetimeBoundCtor>(obj); // expected-warning {{local 
variable 'obj' does not live long enough}}
+    v = static_cast<LifetimeBoundCtor>(obj); // expected-warning {{local 
variable 'obj' does not live long enough}} \
+                                             // expected-note {{local 
temporary object aliases the storage of local variable 'obj'}}
   }                                          // expected-note {{destroyed 
here}}
   (void)v;                                   // expected-note {{later used 
here}}
 }
@@ -999,7 +1009,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 {{local 
temporary object aliases the storage of local variable 'obj'}}
   }                                                 // tu-note {{destroyed 
here}}
   (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 {{local temporary object 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 {{local temporary object 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 {{local temporary object 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 {{local temporary object aliases the storage of local variable 
'obj_short'}}
   } // tu-note {{destroyed here}}
   (void)ptr; // tu-note {{later used here}}
 }
@@ -1235,6 +1250,16 @@ void conditional_operator_lifetimebound_nested_deep(bool 
cond) {
   (void)*p;  // expected-note 4 {{later used here}}
 }
 
+void simpleparen() {
+  MyObj* p;
+  {
+    MyObj a;
+    MyObj* b = &a;   // expected-warning {{local variable 'a' does not live 
long enough}}
+    p = (((b)));     // expected-note {{local variable 'b' aliases the storage 
of local variable 'a'}}
+  }                  // expected-note {{destroyed here}}
+  (void)*p;          // expected-note {{later used here}}
+}
+
 void parentheses(bool cond) {
   MyObj* p;
   {
@@ -1324,7 +1349,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 {{local temporary object aliases the 
storage of local variable 'string_or'}}
             value();
   }                     // expected-note {{destroyed here}}
   (void)view;           // expected-note {{later used here}}
@@ -1415,7 +1441,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 {{local temporary object aliases the 
storage of local variable 'smart_ptr'}}
   }                  // expected-note {{destroyed here}}
   v.use();           // expected-note {{later used here}}
 }
@@ -1621,7 +1648,8 @@ 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 {{local temporary object aliases the 
storage of local variable 'a'}}
   }         // expected-note {{destroyed here}}
   (void)v;  // expected-note {{later used here}}
   const int* p;
@@ -1660,7 +1688,8 @@ 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 {{local temporary object 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}}
         (void)y; // expected-note {{used here}}
@@ -1759,8 +1788,8 @@ void test_temporary() {
   std::string_view z;
   {
     S s;
-    const std::string& zz = s.x(); // expected-warning {{object whose 
reference is captured does not live long enough}}
-    z = zz;                        // expected-note {{aliases the storage of 
s}}
+    const std::string& zz = s.x(); // expected-warning {{local variable 's' 
does not live long enough}}
+    z = zz;                        // expected-note {{local temporary object 
aliases the storage of local variable 's'}}
   } // expected-note {{destroyed here}}
   (void)z; // expected-note {{later used here}}
 }
@@ -1790,7 +1819,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 {{local temporary object aliases the 
storage of local variable 'str'}}
   } // expected-note {{destroyed here}}
   (void)view;  // expected-note {{later used here}}
 }
@@ -1815,8 +1845,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 {{local temporary object aliases the 
storage of local variable 'u'}}
   } // expected-note {{destroyed here}}
   (void)view;  // expected-note {{later used here}}
 }
@@ -1833,7 +1864,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}}
 }
@@ -1937,7 +1968,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 {{local temporary object aliases the 
storage of local variable 'opt'}}
   }                      // expected-note {{destroyed here}}
   v.use();               // expected-note {{later used here}}
 }
@@ -2356,7 +2388,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 {{local temporary object aliases 
the storage of local variable 'f'}}
   }                       // expected-note {{destroyed here}}
   use(value);             // expected-note {{later used here}}
 }
@@ -2365,7 +2398,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 {{local temporary object aliases the 
storage of local variable 'str'}}
   }                // expected-note {{destroyed here}}
   use(s);          // expected-note {{later used here}}
 }
@@ -2387,8 +2421,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 {{local temporary object 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}}
 }
@@ -2398,7 +2433,7 @@ void chained_defaulted_assignment_propagation() {
   {
     std::string str{"abc"};
     S a = getS(str); // expected-warning {{local variable 'str' does not live 
long enough}}
-    c = b = a;
+    c = b = a;       // expected-note {{local variable 'a' aliases the storage 
of local variable 'str'}}
   }                  // expected-note {{destroyed here}}
   use(c);            // expected-note {{later used here}}
 }
@@ -2596,7 +2631,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 {{local temporary object aliases 
the storage of local variable 'local'}}
   } // expected-note {{destroyed here}}
   (void)ups; // expected-note {{later used here}}
 }
@@ -2619,7 +2655,8 @@ void local_pointer() {
   Pointer<int> p;
   {
     int v;
-    p = Pointer(v); // expected-warning {{local variable 'v' does not live 
long enough}}
+    p = Pointer(v); // expected-warning {{local variable 'v' does not live 
long enough}} \
+                    // expected-note {{local temporary object aliases the 
storage of local variable 'v'}}
   }                 // expected-note {{destroyed here}}
   use(*p);          // expected-note {{later used here}}
 }
@@ -2630,9 +2667,12 @@ void nested_local_pointer() {
   Pointer<Bar> p;
   {
     Bar v;
-    p = Pointer(v);     // expected-warning {{local variable 'v' does not live 
long enough}}
-    pp = Pointer(p);
-    ppp = Pointer(pp);
+    p = Pointer(v);     // expected-warning {{local variable 'v' does not live 
long enough}} \
+                        // expected-note {{local temporary object aliases the 
storage of local variable 'v'}}
+    pp = Pointer(p);    // expected-note {{local variable 'p' aliases the 
storage of local variable 'v'}} \
+                        // expected-note {{local temporary object aliases the 
storage of local variable 'v'}}
+    ppp = Pointer(pp);  // expected-note {{local variable 'pp' aliases the 
storage of local variable 'v'}} \
+                        // expected-note {{local temporary object aliases the 
storage of local variable 'v'}}
   }                     // expected-note {{destroyed here}}
   use(***ppp);          // expected-note {{later used here}}
 }
@@ -2759,7 +2799,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}}
 }
@@ -3316,7 +3356,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 {{local temporary 
object aliases the storage of local variable 'local'}}
   } // expected-note {{destroyed here}}
   (void)f; // 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