[clang] [LifetimeSafety] Trace assignment history for use-after-scope errors (PR #188467)

Yuan Suo via cfe-commits cfe-commits at lists.llvm.org
Thu Apr 2 23:28:39 PDT 2026


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

>From e8380ea6b6c1906be0290bc1221ba0c544071511 Mon Sep 17 00:00:00 2001
From: suoyuan666 <suoyuan666 at s5n.xyz>
Date: Mon, 16 Mar 2026 09:55:36 +0800
Subject: [PATCH 01/12] [LifetimeSafety] Trace assignment history for
 use-after-scope errors

Currently, when the compiler detects a use-after-scope error, it only emits notes for the point of use, the destruction point, and the initial declaration of the destroyed variable. In complex control flows, it can be difficult for users to figure out how the dangling pointer/reference reached the use point.

This patch introduces reverse tracing at the CFGBlock corresponding to UseFact->getUseExpr, using BFS to trace the assignment history of dangling variables. It adds extra comments to the assignment statements, clearly showing the event chain that led to the use-after-scope error.

Fixes #177986

Signed-off-by: suoyuan666 <suoyuan666 at s5n.xyz>
---
 .../Analyses/LifetimeSafety/LifetimeSafety.h  |  13 +-
 .../clang/Basic/DiagnosticSemaKinds.td        |   1 +
 clang/lib/Analysis/LifetimeSafety/Checker.cpp | 212 +++++++++-
 clang/lib/Sema/SemaLifetimeSafety.h           |  47 +++
 .../Sema/warn-lifetime-analysis-nocfg.cpp     |  85 ++--
 .../Sema/warn-lifetime-safety-cfg-bailout.cpp |   4 +-
 .../Sema/warn-lifetime-safety-suggestions.cpp |   9 +-
 clang/test/Sema/warn-lifetime-safety.cpp      | 369 ++++++++++++------
 8 files changed, 576 insertions(+), 164 deletions(-)

diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
index 08038dd096685..f1298ec528957 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
@@ -45,6 +45,11 @@ enum class SuggestionScope {
   IntraTU  // For suggestions on definitions local to a Translation Unit.
 };
 
+using OriginSrcExpr =
+    llvm::PointerUnion<const DeclRefExpr *, const CXXTemporaryObjectExpr *,
+                       const CallExpr *>;
+using AssignmentPair = std::pair<OriginSrcExpr, const ValueDecl *>;
+
 /// Abstract interface for operations requiring Sema access.
 ///
 /// This class exists to break a circular dependency: the LifetimeSafety
@@ -60,9 +65,11 @@ class LifetimeSafetySemaHelper {
   LifetimeSafetySemaHelper() = default;
   virtual ~LifetimeSafetySemaHelper() = default;
 
-  virtual void reportUseAfterFree(const Expr *IssueExpr, const Expr *UseExpr,
-                                  const Expr *MovedExpr,
-                                  SourceLocation FreeLoc) {}
+  virtual void
+  reportUseAfterFree(const Expr *IssueExpr, const Expr *UseExpr,
+                     const Expr *MovedExpr,
+                     const llvm::SmallVector<AssignmentPair> AliasList,
+                     SourceLocation FreeLoc) {}
 
   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 7c65fc15f2836..a54e6770b517c 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -11005,6 +11005,7 @@ def note_lifetime_safety_dangling_static_here: Note<"this static storage dangles
 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_note_alias_chain : Note<"variable `%0` is now an alias 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 36477c6f67b52..55617469a410a 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -56,6 +56,13 @@ using AnnotationTarget =
 using EscapingTarget =
     llvm::PointerUnion<const Expr *, const FieldDecl *, const VarDecl *>;
 
+struct AliasAssignmentSearchResult {
+  const llvm::SmallVector<AssignmentPair> Payload;
+  bool SearchComplete;
+  const ValueDecl *LastDestDecl;
+  std::optional<OriginID> LastOrigin;
+};
+
 class LifetimeChecker {
 private:
   llvm::DenseMap<LoanID, PendingWarning> FinalWarningsMap;
@@ -67,6 +74,7 @@ class LifetimeChecker {
   FactManager &FactMgr;
   LifetimeSafetySemaHelper *SemaHelper;
   ASTContext &AST;
+  AnalysisDeclContext &ADC;
 
   static SourceLocation
   GetFactLoc(llvm::PointerUnion<const UseFact *, const OriginEscapesFact *> F) {
@@ -89,7 +97,7 @@ class LifetimeChecker {
                   LifetimeSafetySemaHelper *SemaHelper)
       : LoanPropagation(LoanPropagation), MovedLoans(MovedLoans),
         LiveOrigins(LiveOrigins), FactMgr(FM), SemaHelper(SemaHelper),
-        AST(ADC.getASTContext()) {
+        AST(ADC.getASTContext()), ADC(ADC) {
     for (const CFGBlock *B : *ADC.getAnalysis<PostOrderCFGView>())
       for (const Fact *F : FactMgr.getFacts(B))
         if (const auto *EF = F->getAs<ExpireFact>())
@@ -219,6 +227,194 @@ class LifetimeChecker {
     }
   }
 
+  std::optional<llvm::SmallVector<AssignmentPair>>
+  getAliasListInMultiBlock(const CFGBlock *StartBlock, const LoanID EndLoanID,
+                           OriginID *StartOID) {
+    const ValueDecl *LastDestDecl = nullptr;
+    llvm::SmallVector<const CFGBlock *> PendingBlocks;
+    std::optional<AssignmentPair> StartStmt = std::nullopt;
+    std::optional<AssignmentPair> EndStmt = std::nullopt;
+    std::optional<OriginID> LastOriginID = std::nullopt;
+    llvm::SmallPtrSet<const CFGBlock *, 32> VistedBlocks;
+    llvm::DenseMap<AssignmentPair, AssignmentPair> VistedExprs;
+
+    const auto AliasStmtFilter = [&VistedExprs](const AssignmentPair StartStmt,
+                                                const AssignmentPair EndStmt) {
+      llvm::SmallVector<AssignmentPair> AliasStmts;
+      for (auto Stmt = StartStmt; Stmt != EndStmt;
+           Stmt = VistedExprs.at(Stmt)) {
+        AliasStmts.push_back(Stmt);
+      }
+      AliasStmts.push_back(EndStmt);
+      return AliasStmts;
+    };
+
+    PendingBlocks.push_back(StartBlock);
+
+    for (size_t i = 0; i < PendingBlocks.size(); ++i) {
+      const CFGBlock *CurrBlock = PendingBlocks[i];
+
+      const auto [BlockAliasList, Success, CurrLastDestDecl, CurrLastOriginID] =
+          getAliasListCore(CurrBlock, EndLoanID, StartOID, LastDestDecl,
+                           LastOriginID);
+      if (CurrLastDestDecl)
+        LastDestDecl = CurrLastDestDecl;
+      if (CurrLastOriginID.has_value())
+        LastOriginID = CurrLastOriginID;
+
+      if (!BlockAliasList.empty()) {
+        if (VistedExprs.empty()) {
+          StartStmt = BlockAliasList[0];
+        }
+
+        for (size_t i = 0; i < BlockAliasList.size() - 1; ++i) {
+          VistedExprs.insert({BlockAliasList[i], BlockAliasList[i + 1]});
+        }
+
+        if (EndStmt.has_value())
+          VistedExprs.insert({EndStmt.value(), BlockAliasList[0]});
+
+        EndStmt = BlockAliasList[BlockAliasList.size() - 1];
+      }
+
+      if (Success && StartStmt.has_value() && EndStmt.has_value()) {
+        return AliasStmtFilter(StartStmt.value(), EndStmt.value());
+      }
+
+      for (const auto Block : CurrBlock->preds()) {
+        if (Block && VistedBlocks.insert(Block).second)
+          PendingBlocks.push_back(Block);
+      }
+
+      if (VistedBlocks.size() >= 32 && StartStmt.has_value() &&
+          EndStmt.has_value()) {
+        return AliasStmtFilter(StartStmt.value(), EndStmt.value());
+      }
+    }
+
+    if (StartStmt.has_value() && EndStmt.has_value()) {
+      return AliasStmtFilter(StartStmt.value(), EndStmt.value());
+    }
+
+    return std::nullopt;
+  }
+
+  std::optional<OriginSrcExpr> GetPureSrcExpr(const Expr *TargetExpr) {
+    if (!TargetExpr)
+      return std::nullopt;
+    const Expr *SExpr = TargetExpr->IgnoreParenCasts();
+    if (!SExpr)
+      return std::nullopt;
+
+    if (const auto *SDRExpr = llvm::dyn_cast<DeclRefExpr>(SExpr)) {
+      return SDRExpr;
+    }
+    if (const auto *STMExpr = llvm::dyn_cast<CXXTemporaryObjectExpr>(SExpr)) {
+      return STMExpr;
+    }
+    if (const auto *SCExpr = llvm::dyn_cast<CallExpr>(SExpr)) {
+      return SCExpr;
+    }
+
+    if (const auto *SCCExpr = llvm::dyn_cast<CXXConstructExpr>(SExpr)) {
+      if (SCCExpr->getNumArgs() > 0)
+        return GetPureSrcExpr(SCCExpr->getArg(0));
+    }
+    if (const auto *SUOExpr = llvm::dyn_cast<UnaryOperator>(SExpr)) {
+      return GetPureSrcExpr(SUOExpr->getSubExpr());
+    }
+    if (const auto *SCBExpr = llvm::dyn_cast<CXXBindTemporaryExpr>(SExpr)) {
+      return GetPureSrcExpr(SCBExpr->getSubExpr());
+    }
+
+    return std::nullopt;
+  }
+
+  /// Retrieves a list of assignment chains for use-after-scope analysis.
+  ///
+  /// To help users understand the data flow, we track where the problematic
+  /// address originated.
+  AliasAssignmentSearchResult
+  getAliasListCore(const CFGBlock *Block, const LoanID EndLoanID,
+                   OriginID *TargetOID, const ValueDecl *LastDestDecl = nullptr,
+                   const std::optional<OriginID> LastOriginID = std::nullopt) {
+    llvm::SmallVector<AssignmentPair> AliasStmts;
+    const ValueDecl *DestDecl = LastDestDecl;
+    const auto Facts = FactMgr.getFacts(Block);
+    bool FetchLoan = false;
+    auto IssueOriginID = LastOriginID;
+
+    for (auto F = Facts.rbegin(); F != Facts.rend(); ++F) {
+      if (const auto *OFF = (*F)->getAs<OriginFlowFact>()) {
+        if (IssueOriginID.has_value() &&
+            OFF->getDestOriginID() == IssueOriginID.value()) {
+          FetchLoan = true;
+        }
+        if (OFF->getDestOriginID() == *TargetOID) {
+          const auto HeldLoans =
+              LoanPropagation.getLoans(OFF->getSrcOriginID(), OFF);
+
+          if (HeldLoans.contains(EndLoanID)) {
+            const auto TargetOrigin =
+                FactMgr.getOriginMgr().getOrigin(OFF->getDestOriginID());
+
+            if (DestDecl == nullptr) {
+              if (const ValueDecl *DDecl = TargetOrigin.getDecl()) {
+                DestDecl = DDecl;
+              }
+            } else {
+              auto SExpr = GetPureSrcExpr(TargetOrigin.getExpr());
+              if (!SExpr.has_value()) {
+                const auto SrcOrigin =
+                    FactMgr.getOriginMgr().getOrigin(OFF->getSrcOriginID());
+                SExpr = GetPureSrcExpr(SrcOrigin.getExpr());
+              }
+
+              if (SExpr.has_value()) {
+                AliasStmts.push_back({SExpr.value(), DestDecl});
+                DestDecl = nullptr;
+              }
+            }
+            *TargetOID = OFF->getSrcOriginID();
+          }
+        }
+      } else if (const auto *IF = (*F)->getAs<IssueFact>()) {
+        if (IF->getLoanID() == EndLoanID) {
+          IssueOriginID = IF->getOriginID();
+        }
+      }
+
+      if (FetchLoan) {
+        return {AliasStmts, true, DestDecl, IssueOriginID};
+      }
+    }
+    return {AliasStmts, false, DestDecl, IssueOriginID};
+  }
+
+  std::optional<llvm::SmallVector<AssignmentPair>>
+  getAliasList(const UseFact *UF, const LoanID End, const bool InOneBlock) {
+    const CFGBlock *IssueBlock =
+        ADC.getCFGStmtMap()->getBlock(UF->getUseExpr());
+    assert(IssueBlock && "Searching CFGBlock failed");
+
+    for (const OriginList *Cur = UF->getUsedOrigins(); Cur;
+         Cur = Cur->peelOuterOrigin()) {
+      auto TargetOID = Cur->getOuterOriginID();
+      if (InOneBlock) {
+        AliasAssignmentSearchResult Result =
+            getAliasListCore(IssueBlock, End, &TargetOID);
+        if (!Result.Payload.empty())
+          return Result.Payload;
+      } else {
+        auto Result = getAliasListInMultiBlock(IssueBlock, End, &TargetOID);
+        if (Result.has_value())
+          return Result.value();
+      }
+    }
+
+    return std::nullopt;
+  }
+
   void issuePendingWarnings() {
     if (!SemaHelper)
       return;
@@ -243,10 +439,20 @@ class LifetimeChecker {
             SemaHelper->reportUseAfterInvalidation(
                 InvalidatedPVD, UF->getUseExpr(), Warning.InvalidatedByExpr);
 
-        } else
+        } else {
           // Scope-based expiry (use-after-scope).
+          const CFGStmtMap *CurrCFGStmtMap = ADC.getCFGStmtMap();
+          const auto AliasExprs =
+              getAliasList(UF, LID,
+                           CurrCFGStmtMap->getBlock(UF->getUseExpr()) ==
+                               CurrCFGStmtMap->getBlock(IssueExpr));
+          if (!AliasExprs.has_value()) {
+            llvm::dbgs() << "Search variable assignment chain failed\n";
+          }
+
           SemaHelper->reportUseAfterFree(IssueExpr, UF->getUseExpr(), MovedExpr,
-                                         ExpiryLoc);
+                                         AliasExprs.value_or({}), ExpiryLoc);
+        }
       } else if (const auto *OEF =
                      CausingFact.dyn_cast<const OriginEscapesFact *>()) {
         if (const auto *RetEscape = dyn_cast<ReturnEscapeFact>(OEF))
diff --git a/clang/lib/Sema/SemaLifetimeSafety.h b/clang/lib/Sema/SemaLifetimeSafety.h
index e6f7e3d929f61..5c564ea603089 100644
--- a/clang/lib/Sema/SemaLifetimeSafety.h
+++ b/clang/lib/Sema/SemaLifetimeSafety.h
@@ -45,6 +45,7 @@ class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper {
 
   void reportUseAfterFree(const Expr *IssueExpr, const Expr *UseExpr,
                           const Expr *MovedExpr,
+                          const llvm::SmallVector<AssignmentPair> AliasList,
                           SourceLocation FreeLoc) override {
     S.Diag(IssueExpr->getExprLoc(),
            MovedExpr ? diag::warn_lifetime_safety_use_after_scope_moved
@@ -54,6 +55,52 @@ 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);
+
+    for (auto AliasStmt = AliasList.rbegin(); AliasStmt != AliasList.rend();
+         ++AliasStmt) {
+      if (const auto *CurrDeclExpr =
+              llvm::dyn_cast<const DeclRefExpr *>((*AliasStmt).first)) {
+        S.Diag(CurrDeclExpr->getExprLoc(),
+               diag::note_lifetime_safety_note_alias_chain)
+            << (*AliasStmt).second->getNameAsString()
+            << CurrDeclExpr->getDecl()->getNameAsString();
+      } else if (const auto *CurrDeclExpr =
+                     llvm::dyn_cast<const CXXTemporaryObjectExpr *>(
+                         (*AliasStmt).first)) {
+        S.Diag(CurrDeclExpr->getExprLoc(),
+               diag::note_lifetime_safety_note_alias_chain)
+            << (*AliasStmt).second->getNameAsString()
+            << CurrDeclExpr->getConstructor()->getNameAsString() + "()";
+      } else if (const auto *CurrCallExpr =
+                     llvm::dyn_cast<const CallExpr *>((*AliasStmt).first)) {
+        std::string OutStr;
+        llvm::raw_string_ostream OutStream(OutStr);
+        LangOptions Lo;
+        PrintingPolicy Policy(Lo);
+
+        if (const Expr *Callee = CurrCallExpr->getCallee()) {
+          Callee->IgnoreParenCasts()->printPretty(OutStream, nullptr, Policy);
+        }
+
+        OutStream << "(";
+        for (size_t i = 0; i < CurrCallExpr->getNumArgs(); ++i) {
+          const Expr *CurrArg = CurrCallExpr->getArg(i);
+          if (CurrArg) {
+            CurrArg->printPretty(OutStream, nullptr, Policy);
+          }
+
+          if (i < CurrCallExpr->getNumArgs() - 1) {
+            OutStream << ", ";
+          }
+        }
+        OutStream << ")";
+
+        S.Diag(CurrCallExpr->getExprLoc(),
+               diag::note_lifetime_safety_note_alias_chain)
+            << (*AliasStmt).second->getNameAsString() << OutStream.str();
+      }
+    }
+
     S.Diag(UseExpr->getExprLoc(), diag::note_lifetime_safety_used_here)
         << UseExpr->getSourceRange();
   }
diff --git a/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp b/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
index d58f23e4b554c..f0c7306d124a5 100644
--- a/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
+++ b/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
@@ -147,14 +147,16 @@ MyLongPointerFromConversion global2;
 
 void initLocalGslPtrWithTempOwner() {
   MyIntPointer p = MyIntOwner{}; // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}} \
-                                 // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
+                                 // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}} \
+                                 // cfg-note {{variable `p` is now an alias of `MyIntOwner()`}}
   use(p);                        // cfg-note {{later used here}}
 
   MyIntPointer pp = p = MyIntOwner{}; // expected-warning {{object backing the pointer 'p' will be}} \
-                                      // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
+                                      // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}} \
+                                      // cfg-note {{variable `p` is now an alias of `MyIntOwner()`}}
   use(p, pp);                         // cfg-note {{later used here}}
 
-  p = MyIntOwner{}; // expected-warning {{object backing the pointer 'p' }} \
+  p = MyIntOwner{}; // expected-warning {{object backing the pointer 'p' }} cfg-note {{variable `p` is now an alias of `MyIntOwner()`}} \
                     // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
   use(p);           // cfg-note {{later used here}}
 
@@ -162,16 +164,20 @@ void initLocalGslPtrWithTempOwner() {
   use(p, pp);
 
   global = MyIntOwner{}; // expected-warning {{object backing the pointer 'global' }} \
+                         // cfg-note {{variable `global` is now an alias of `MyIntOwner()`}} \
                          // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
   use(global);           // cfg-note {{later used here}}
 
   MyLongPointerFromConversion p2 = MyLongOwnerWithConversion{}; // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}} \
-                                                                // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
+                                                                // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}} \
+                                                                // cfg-note {{variable `p2` is now an alias of `MyLongOwnerWithConversion{}.operator MyLongPointerFromConversion()`}}
   use(p2);                                                      // cfg-note {{later used here}}
 
   p2 = MyLongOwnerWithConversion{}; // expected-warning {{object backing the pointer 'p2' }} \
+                                    // cfg-note {{variable `p2` is now an alias of `MyLongOwnerWithConversion{}.operator MyLongPointerFromConversion()`}} \
                                     // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
   global2 = MyLongOwnerWithConversion{};  // expected-warning {{object backing the pointer 'global2' }} \
+                                          // cfg-note {{variable `global2` is now an alias of `MyLongOwnerWithConversion{}.operator MyLongPointerFromConversion()`}} \
                                           // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
   use(global2, p2);                       // cfg-note 2 {{later used here}}
 }
@@ -185,6 +191,7 @@ struct Unannotated {
 
 void modelIterators() {
   std::vector<int>::iterator it = std::vector<int>().begin(); // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}} \
+                                                              // cfg-note {{variable `it` is now an alias of `std::vector<int>().begin()`}} \
                                                               // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
   (void)it; // cfg-note {{later used here}}
 }
@@ -233,11 +240,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-note {{variable `c1` is now an alias of `std::vector<std::string>().at(0).operator basic_string_view()`}} \
                                                           // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
   use(c1);                                                // cfg-note {{later used here}}
 
   c1 = std::vector<std::string>().at(0); // expected-warning {{object backing the pointer}} \
-                                         // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
+                                         // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}} \
+                                         // cfg-note {{variable `c1` is now an alias of `std::vector<std::string>().at(0).operator basic_string_view()`}}
   use(c1);                               // cfg-note {{later used here}}
 
   // no warning on constructing from gsl-pointer
@@ -298,22 +307,28 @@ 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-note {{variable `r` is now an alias of `operator*(std::optional<int>())`}} \
                                             // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
   // 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 {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
+                                            // cfg-note {{variable `r2` is now an alias of `operator*(std::optional<int>(5))`}} \
+                                            // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
 
   // 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 {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
+                                            // cfg-note {{variable `r3` is now an alias of `std::optional<int>(5).value()`}} \
+                                            // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
 
   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-note {{variable `r4` is now an alias of `std::vector<int>().at(3)`}} \
                                             // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
   int &&r5 = std::vector<int>().at(3);      // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}} \
+                                            // cfg-note {{variable `r5` is now an alias of `std::vector<int>().at(3)`}} \
                                             // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
   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-note {{variable `sv` is now an alias of `* getTempOptStr().operator basic_string_view()`}} \
                                            // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
   use(sv);                                 // cfg-note {{later used here}}
 }
@@ -325,6 +340,7 @@ 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-note {{variable `__range1` is now an alias of `operator*(getTempOptVec())`}} \
                                   // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}} cfg-note {{later used here}}
     ;
 }
@@ -387,6 +403,7 @@ void handleGslPtrInitsThroughReference2() {
 void handleTernaryOperator(bool cond) {
     std::basic_string<char> def;
     std::basic_string_view<char> v = cond ? def : ""; // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}} \
+                                                      // cfg-note {{variable `v` is now an alias of `cond ? def : "".operator basic_string_view()`}} \
                                                       // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
     use(v); // cfg-note {{later used here}}
 }
@@ -394,11 +411,13 @@ void handleTernaryOperator(bool cond) {
 std::string operator+(std::string_view s1, std::string_view s2);
 void danglingStringviewAssignment(std::string_view a1, std::string_view a2) {
   a1 = std::string(); // expected-warning {{object backing}} \
-                      // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
+                      // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}} \
+                      // cfg-note {{variable `a1` is now an alias of `std::string().operator basic_string_view()`}}
   use(a1);            // cfg-note {{later used here}}
 
   a2 = a1 + a1; // expected-warning {{object backing}} \
-                // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
+                // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}} \
+                // cfg-note {{variable `a2` is now an alias of `a1 + a1.operator basic_string_view()`}}
   use(a2);      // cfg-note {{later used here}}
 }
 
@@ -602,7 +621,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 {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
+                                                                  // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}} \
+                                                                  // cfg-note {{variable `svjkk1` is now an alias of `ReturnStringView(StrCat("bar", "x"))`}}
   use(svjkk1);                                                    // cfg-note {{later used here}}
 }
 } // namespace GH100549
@@ -836,7 +856,8 @@ namespace GH118064{
 
 void test() {
   auto y = std::set<int>{}.begin(); // expected-warning {{object backing the pointer}} \
-  // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
+  // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}} \
+  // cfg-note {{variable `y` is now an alias of `std::set<int>{}.begin()`}}
   use(y); // cfg-note {{later used here}}
 }
 } // namespace GH118064
@@ -851,10 +872,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 {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
+                                            // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}} \
+                                            // cfg-note {{variable `t1` is now an alias of `Ref(std::string()).operator basic_string_view()`}}
   use(t1);                                  // cfg-note {{later used here}}
   t1 = Ref(std::string()); // expected-warning {{object backing}} \
-                           // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
+                           // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}} \
+                           // cfg-note {{variable `t1` is now an alias of `Ref(std::string()).operator basic_string_view()`}}
   use(t1);                 // cfg-note {{later used here}}
   return Ref(std::string()); // expected-warning {{returning address}} \
                              // cfg-warning {{address of stack memory is returned later}} cfg-note {{returned here}}
@@ -862,10 +885,12 @@ std::string_view test1_1() {
 
 std::string_view test1_2() {
   std::string_view t2 = TakeSv(std::string()); // expected-warning {{object backing}} \
-                                            // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
+                                            // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}} \
+                                            // cfg-note {{variable `t2` is now an alias of `TakeSv(std::string())`}}
   use(t2);                                  // cfg-note {{later used here}}
   t2 = TakeSv(std::string()); // expected-warning {{object backing}} \
-                              // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
+                              // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}} \
+                              // cfg-note {{variable `t2` is now an alias of `TakeSv(std::string())`}}
   use(t2);                    // cfg-note {{later used here}}
 
   return TakeSv(std::string()); // expected-warning {{returning address}} \
@@ -874,9 +899,11 @@ std::string_view test1_2() {
 
 std::string_view test1_3() {
   std::string_view t3 = TakeStrRef(std::string()); // expected-warning {{temporary}} \
+                                                   // cfg-note {{variable `t3` is now an alias of `TakeStrRef(std::string())`}} \
                                                    // cfg-warning {{object whose reference is captured 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-note {{variable `t3` is now an alias of `TakeStrRef(std::string())`}} \
                                   // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
   use(t3);                        // cfg-note {{later used here}}
   return TakeStrRef(std::string()); // expected-warning {{returning address}} \
@@ -899,10 +926,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-note {{variable `t1` is now an alias of `Foo<std::string>().get().operator basic_string_view()`}} \
                                                   // cfg-warning {{object whose reference is captured 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 {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
+                                 // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}} \
+                                 // cfg-note {{variable `t1` is now an alias of `Foo<std::string>().get().operator basic_string_view()`}}
   use(t1);                       // cfg-note {{later used here}}
   return r1.get(); // expected-warning {{address of stack}} \
                    // cfg-warning {{address of stack memory is returned later}} cfg-note {{returned here}}
@@ -1022,9 +1051,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 {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
-  const char* y = (*temporary().begin()).data();  // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
-  const std::string& z = (*temporary().begin());  // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
+  const char* x = temporary().begin()->data();    // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}} \
+                                                  // cfg-note {{variable `x` is now an alias of `temporary().begin()->data()`}}
+  const char* y = (*temporary().begin()).data();  // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}} \
+                                                  // cfg-note {{variable `y` is now an alias of `(* temporary().begin()).data()`}}
+  const std::string& z = (*temporary().begin());  // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}} \
+                                                  // cfg-note {{variable `z` is now an alias of `operator*(temporary().begin())`}}
 
   use(p, q, r, x, y, z); // cfg-note 3 {{later used here}}
 }
@@ -1036,9 +1068,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 {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
-  const char* y = (*temporary().begin()).second.data(); // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
-  const std::string& z = (*temporary().begin()).second; // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
+  const char* x = temporary().begin()->second.data();   // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}} \
+                                                        // cfg-note {{variable `x` is now an alias of `temporary().begin()->second.data()`}}
+  const char* y = (*temporary().begin()).second.data(); // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}} \
+                                                        // cfg-note {{variable `y` is now an alias of `(* temporary().begin()).second.data()`}}
+  const std::string& z = (*temporary().begin()).second; // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}} \
+                                                        // cfg-note {{variable `z` is now an alias of `operator*(temporary().begin())`}}
 
   use(p, q, r, x, y, z); // cfg-note 3 {{later used here}}
 }
@@ -1088,16 +1123,20 @@ 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-note {{variable `k2` is now an alias of `S().s.operator basic_string_view()`}} \
                                // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
 
   std::string_view k3 = Q().get()->sv; // OK
   std::string_view k4  = Q().get()->s; // expected-warning {{object backing the pointer will}} \
-                                       // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
+                                       // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}} \
+                                       // cfg-note {{variable `k4` is now an alias of `Q().get()->s.operator basic_string_view()`}}
 
 
   std::string_view lb1 = foo(S().s); // expected-warning {{object backing the pointer will}} \
+                                     // cfg-note {{variable `lb1` is now an alias of `foo(S().s)`}} \
                                      // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
   std::string_view lb2 = foo(Q().get()->s); // expected-warning {{object backing the pointer will}} \
+                                            // cfg-note {{variable `lb2` is now an alias of `foo(Q().get()->s)`}} \
                                             // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
 
   use(k1, k2, k3, k4, lb1, lb2);  // cfg-note 4 {{later used here}}
diff --git a/clang/test/Sema/warn-lifetime-safety-cfg-bailout.cpp b/clang/test/Sema/warn-lifetime-safety-cfg-bailout.cpp
index 7c5d61e23e710..51cd8a6e5b349 100644
--- a/clang/test/Sema/warn-lifetime-safety-cfg-bailout.cpp
+++ b/clang/test/Sema/warn-lifetime-safety-cfg-bailout.cpp
@@ -27,7 +27,7 @@ void single_block_cfg() {
   MyObj* p;
   {
     MyObj s;
-    p = &s;     // bailout-warning {{object whose reference is captured does not live long enough}}
+    p = &s;     // bailout-warning {{object whose reference is captured does not live long enough}} bailout-note {{variable `p` is now an alias of `s`}}
   }             // bailout-note {{destroyed here}}
   (void)*p;     // bailout-note {{later used here}}
 }
@@ -39,7 +39,7 @@ void multiple_block_cfg() {
   {
     if (a > 5) {
       MyObj s;
-      p = &s;    // nobailout-warning {{object whose reference is captured does not live long enough}}
+      p = &s;    // nobailout-warning {{object whose reference is captured does not live long enough}} nobailout-note {{variable `p` is now an alias of `s`}}
     } else {     // nobailout-note {{destroyed here}}
       p = &safe;
     }     
diff --git a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
index 19c3251b9c296..dcf3b7719ce1c 100644
--- a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
+++ b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
@@ -220,19 +220,22 @@ View return_view_field(const ViewProvider& v) {    // expected-warning {{paramet
 
 void test_get_on_temporary_pointer() {
   const ReturnsSelf* s_ref = &ReturnsSelf().get(); // expected-warning {{object whose reference is captured does not live long enough}}.
-                                                   // expected-note at -1 {{destroyed here}}
+                                                   // expected-note at -1 {{destroyed here}}.
+                                                   // expected-note at -2 {{variable `s_ref` is now an alias of `ReturnsSelf().get()`}}
   (void)s_ref;                                     // expected-note {{later used here}}
 }
 
 void test_get_on_temporary_ref() {
   const ReturnsSelf& s_ref = ReturnsSelf().get();  // expected-warning {{object whose reference is captured does not live long enough}}.
-                                                   // expected-note at -1 {{destroyed here}}
+                                                   // expected-note at -1 {{destroyed here}}.
+                                                   // expected-note at -2 {{variable `s_ref` is now an alias of `ReturnsSelf().get()`}}
   (void)s_ref;                                     // expected-note {{later used here}}
 }
 
 void test_getView_on_temporary() {
   View sv = ViewProvider{1}.getView();      // expected-warning {{object whose reference is captured does not live long enough}}.
-                                            // expected-note at -1 {{destroyed here}}
+                                            // expected-note at -1 {{destroyed here}}.
+                                            // expected-note at -2 {{variable `sv` is now an alias of `ViewProvider{1}.getView()`}}
   (void)sv;                                 // expected-note {{later used here}}
 }
 
diff --git a/clang/test/Sema/warn-lifetime-safety.cpp b/clang/test/Sema/warn-lifetime-safety.cpp
index 9b867e0fe1567..8b62f0779a92d 100644
--- a/clang/test/Sema/warn-lifetime-safety.cpp
+++ b/clang/test/Sema/warn-lifetime-safety.cpp
@@ -53,7 +53,8 @@ void simple_case() {
   MyObj* p;
   {
     MyObj s;
-    p = &s;     // expected-warning {{object whose reference is captured does not live long enough}}
+    p = &s;     // expected-warning {{object whose reference is captured does not live long enough}} \
+                // expected-note {{variable `p` is now an alias of `s`}}
   }             // expected-note {{destroyed here}}
   (void)*p;     // expected-note {{later used here}}
 }
@@ -62,7 +63,8 @@ void simple_case_gsl() {
   View v;
   {
     MyObj s;
-    v = s;      // expected-warning {{object whose reference is captured does not live long enough}}
+    v = s;      // expected-warning {{object whose reference is captured does not live long enough}} \
+                // expected-note {{variable `v` is now an alias of `s`}}
   }             // expected-note {{destroyed here}}
   v.use();      // expected-note {{later used here}}
 }
@@ -90,8 +92,9 @@ void pointer_chain() {
   MyObj* q;
   {
     MyObj s;
-    p = &s;     // expected-warning {{does not live long enough}}
-    q = p;
+    p = &s;     // expected-warning {{does not live long enough}} \
+                // expected-note {{variable `p` is now an alias of `s`}}
+    q = p;      // expected-note {{variable `q` is now an alias of `p`}}
   }             // expected-note {{destroyed here}}
   (void)*q;     // expected-note {{later used here}}
 }
@@ -100,8 +103,9 @@ void propagation_gsl() {
   View v1, v2;
   {
     MyObj s;
-    v1 = s;     // expected-warning {{object whose reference is captured does not live long enough}}
-    v2 = v1;
+    v1 = s;     // expected-warning {{object whose reference is captured does not live long enough}} \
+                // expected-note {{variable `v1` is now an alias of `s`}}
+    v2 = v1;    // expected-note {{`v2` is now an alias of `v1`}}
   }             // expected-note {{destroyed here}}
   v2.use();     // expected-note {{later used here}}
 }
@@ -110,7 +114,8 @@ void multiple_uses_one_warning() {
   MyObj* p;
   {
     MyObj s;
-    p = &s;     // expected-warning {{does not live long enough}}
+    p = &s;     // expected-warning {{does not live long enough}} \
+                // expected-note {{variable `p` is now an alias of `s`}}
   }             // expected-note {{destroyed here}}
   (void)*p;     // expected-note {{later used here}}
   // No second warning for the same loan.
@@ -123,9 +128,12 @@ void multiple_pointers() {
   MyObj *p, *q, *r;
   {
     MyObj s;
-    p = &s;     // expected-warning {{does not live long enough}}
-    q = &s;     // expected-warning {{does not live long enough}}
-    r = &s;     // expected-warning {{does not live long enough}}
+    p = &s;     // expected-warning {{does not live long enough}} \
+                // expected-note {{variable `p` is now an alias of `s`}}
+    q = &s;     // expected-warning {{does not live long enough}} \
+                // expected-note {{variable `q` is now an alias of `s`}}
+    r = &s;     // expected-warning {{does not live long enough}} \
+                // expected-note {{variable `r` is now an alias of `s`}}
   }             // expected-note 3 {{destroyed here}}
   (void)*p;     // expected-note {{later used here}}
   (void)*q;     // expected-note {{later used here}}
@@ -136,11 +144,13 @@ void single_pointer_multiple_loans(bool cond) {
   MyObj *p;
   if (cond){
     MyObj s;
-    p = &s;     // expected-warning {{does not live long enough}}
+    p = &s;     // expected-warning {{does not live long enough}} \
+                // expected-note {{`p` is now an alias of `s`}}
   }             // expected-note {{destroyed here}}
   else {
     MyObj t;
-    p = &t;     // expected-warning {{does not live long enough}}
+    p = &t;     // expected-warning {{does not live long enough}} \
+                // expected-note {{variable `p` is now an alias of `t`}}
   }             // expected-note {{destroyed here}}
   (void)*p;     // expected-note 2  {{later used here}}
 }
@@ -149,11 +159,13 @@ void single_pointer_multiple_loans_gsl(bool cond) {
   View v;
   if (cond){
     MyObj s;
-    v = s;      // expected-warning {{object whose reference is captured does not live long enough}}
+    v = s;      // expected-warning {{object whose reference is captured does not live long enough}} \
+                // expected-note {{variable `v` is now an alias of `s`}}
   }             // expected-note {{destroyed here}}
   else {
     MyObj t;
-    v = t;      // expected-warning {{object whose reference is captured does not live long enough}}
+    v = t;      // expected-warning {{object whose reference is captured does not live long enough}} \
+                // expected-note {{variable `v` is now an alias of `t`}}
   }             // expected-note {{destroyed here}}
   v.use();      // expected-note 2 {{later used here}}
 }
@@ -163,7 +175,8 @@ void if_branch(bool cond) {
   MyObj* p = &safe;
   if (cond) {
     MyObj temp;
-    p = &temp;  // expected-warning {{object whose reference is captured does not live long enough}}
+    p = &temp;  // expected-warning {{object whose reference is captured does not live long enough}} \
+                // expected-note {{variable `p` is now an alias of `temp`}}
   }             // expected-note {{destroyed here}}
   (void)*p;     // expected-note {{later used here}}
 }
@@ -173,7 +186,8 @@ void if_branch_potential(bool cond) {
   MyObj* p = &safe;
   if (cond) {
     MyObj temp;
-    p = &temp;  // expected-warning {{object whose reference is captured does not live long enough}}
+    p = &temp;  // expected-warning {{object whose reference is captured does not live long enough}} \
+                // expected-note {{variable `p` is now an alias of `temp`}}
   }             // expected-note {{destroyed here}}
   if (!cond)
     (void)*p;   // expected-note {{later used here}}
@@ -186,7 +200,8 @@ void if_branch_gsl(bool cond) {
   View v = safe;
   if (cond) {
     MyObj temp;
-    v = temp;   // expected-warning {{object whose reference is captured does not live long enough}}
+    v = temp;   // expected-warning {{object whose reference is captured does not live long enough}} \
+                // expected-note {{variable `v` is now an alias of `temp`}}
   }             // expected-note {{destroyed here}}
   v.use();      // expected-note {{later used here}}
 }
@@ -199,9 +214,11 @@ void potential_together(bool cond) {
   {
     MyObj s;
     if (cond)
-      p_definite = &s;  // expected-warning {{does not live long enough}}
+      p_definite = &s;  // expected-warning {{does not live long enough}} \
+                        // expected-note {{variable `p_definite` is now an alias of `s`}}
     if (cond)
-      p_maybe = &s;     // expected-warning {{does not live long enough}}         
+      p_maybe = &s;     // expected-warning {{does not live long enough}} \
+                        // expected-note {{variable `p_maybe` is now an alias of `s`}}
   }                     // expected-note 2 {{destroyed here}}
   (void)*p_definite;    // expected-note {{later used here}}
   if (!cond)
@@ -214,8 +231,9 @@ void overrides_potential(bool cond) {
   MyObj* q;
   {
     MyObj s;
-    q = &s;       // expected-warning {{does not live long enough}}
-    p = q;
+    q = &s;       // expected-warning {{does not live long enough}} \
+                  // expected-note {{variable `q` is now an alias of `s`}}
+    p = q;        // expected-note {{variable `p` is now an alias of `q`}}
   }               // expected-note {{destroyed here}}
 
   if (cond) {
@@ -234,7 +252,8 @@ void due_to_conditional_killing(bool cond) {
   MyObj* q;
   {
     MyObj s;
-    q = &s;       // expected-warning {{does not live long enough}}
+    q = &s;       // expected-warning {{does not live long enough}} \
+                  // expected-note {{variable `q` is now an alias of `s`}}
   }               // expected-note {{destroyed here}}
   if (cond) {
     // 'q' is conditionally "rescued". 'p' is not.
@@ -247,7 +266,8 @@ void for_loop_use_after_loop_body(MyObj safe) {
   MyObj* p = &safe;
   for (int i = 0; i < 1; ++i) {
     MyObj s;
-    p = &s;     // expected-warning {{does not live long enough}}
+    p = &s;     // expected-warning {{does not live long enough}} \
+                // expected-note {{variable `p` is now an alias of `s`}}
   }             // expected-note {{destroyed here}}
   (void)*p;     // expected-note {{later used here}}
 }
@@ -267,7 +287,8 @@ void for_loop_gsl() {
   View v = safe;
   for (int i = 0; i < 1; ++i) {
     MyObj s;
-    v = s;      // expected-warning {{object whose reference is captured does not live long enough}}
+    v = s;      // expected-warning {{object whose reference is captured does not live long enough}} \
+                // expected-note {{variable `v` is now an alias of `s`}}
   }             // expected-note {{destroyed here}}
   v.use();      // expected-note {{later used here}}
 }
@@ -278,7 +299,8 @@ void for_loop_use_before_loop_body(MyObj safe) {
   for (int i = 0; i < 1; ++i) {
     (void)*p;   // expected-note {{later used here}}
     MyObj s;
-    p = &s;     // expected-warning {{does not live long enough}}
+    p = &s;     // expected-warning {{does not live long enough}} \
+                // expected-note {{variable `p` is now an alias of `s`}}
   }             // expected-note {{destroyed here}}
   (void)*p;
 }
@@ -289,7 +311,8 @@ void loop_with_break(bool cond) {
   for (int i = 0; i < 10; ++i) {
     if (cond) {
       MyObj temp;
-      p = &temp; // expected-warning {{does not live long enough}}
+      p = &temp; // expected-warning {{does not live long enough}} \
+                 // expected-note {{variable `p` is now an alias of `temp`}}
       break;     // expected-note {{destroyed here}}
     }           
   } 
@@ -302,7 +325,8 @@ void loop_with_break_gsl(bool cond) {
   for (int i = 0; i < 10; ++i) {
     if (cond) {
       MyObj temp;
-      v = temp;   // expected-warning {{object whose reference is captured does not live long enough}}
+      v = temp;   // expected-warning {{object whose reference is captured does not live long enough}} \
+                  // expected-note {{variable `v` is now an alias of `temp`}}
       break;      // expected-note {{destroyed here}}
     }
   }
@@ -316,8 +340,9 @@ void multiple_expiry_of_same_loan(bool cond) {
   for (int i = 0; i < 10; ++i) {
     MyObj unsafe;
     if (cond) {
-      p = &unsafe; // expected-warning {{does not live long enough}}
-      break;       // expected-note {{destroyed here}} 
+      p = &unsafe; // expected-warning {{does not live long enough}} \
+                   // expected-note {{variable `p` is now an alias of `unsafe`}}
+      break;       // expected-note {{destroyed here}}
     }
   }
   (void)*p;       // expected-note {{later used here}}
@@ -326,7 +351,8 @@ void multiple_expiry_of_same_loan(bool cond) {
   for (int i = 0; i < 10; ++i) {
     MyObj unsafe;
     if (cond) {
-      p = &unsafe;    // expected-warning {{does not live long enough}}
+      p = &unsafe;    // expected-warning {{does not live long enough}} \
+                      // expected-note {{variable `p` is now an alias of `unsafe`}}
       if (cond)
         break;        // expected-note {{destroyed here}}
     }
@@ -337,7 +363,8 @@ void multiple_expiry_of_same_loan(bool cond) {
   for (int i = 0; i < 10; ++i) {
     if (cond) {
       MyObj unsafe2;
-      p = &unsafe2;   // expected-warning {{does not live long enough}}
+      p = &unsafe2;   // expected-warning {{does not live long enough}} \
+                      // expected-note {{variable `p` is now an alias of `unsafe2`}}
       break;          // expected-note {{destroyed here}}
     }
   }
@@ -347,7 +374,8 @@ void multiple_expiry_of_same_loan(bool cond) {
   for (int i = 0; i < 10; ++i) {
     MyObj unsafe;
     if (cond)
-      p = &unsafe;    // expected-warning {{does not live long enough}}
+      p = &unsafe;    // expected-warning {{does not live long enough}} \
+                      // expected-note {{variable `p` is now an alias of `unsafe`}}
     if (cond)
       break;          // expected-note {{destroyed here}}
   }
@@ -360,7 +388,8 @@ void switch_potential(int mode) {
   switch (mode) {
   case 1: {
     MyObj temp;
-    p = &temp;  // expected-warning {{object whose reference is captured does not live long enough}}
+    p = &temp;  // expected-warning {{object whose reference is captured does not live long enough}} \
+                // expected-note {{variable `p` is now an alias of `temp`}}
     break;      // expected-note {{destroyed here}}
   }
   case 2: {
@@ -379,17 +408,20 @@ void switch_uaf(int mode) {
   switch (mode) {
   case 1: {
     MyObj temp1;
-    p = &temp1; // expected-warning {{does not live long enough}}
+    p = &temp1; // expected-warning {{does not live long enough}} \
+                // expected-note {{variable `p` is now an alias of `temp1`}}
     break;      // expected-note {{destroyed here}}
   }
   case 2: {
     MyObj temp2;
-    p = &temp2; // expected-warning {{does not live long enough}}
+    p = &temp2; // expected-warning {{does not live long enough}} \
+                // expected-note {{variable `p` is now an alias of `temp2`}}
     break;      // expected-note {{destroyed here}}
   }
   default: {
     MyObj temp2;
-    p = &temp2; // expected-warning {{does not live long enough}}
+    p = &temp2; // expected-warning {{does not live long enough}} \
+                // expected-note {{variable `p` is now an alias of `temp2`}}
     break;      // expected-note {{destroyed here}}
   }
   }
@@ -401,17 +433,20 @@ void switch_gsl(int mode) {
   switch (mode) {
   case 1: {
     MyObj temp1;
-    v = temp1;  // expected-warning {{object whose reference is captured does not live long enough}}
+    v = temp1;  // expected-warning {{object whose reference is captured does not live long enough}} \
+                // expected-note {{variable `v` is now an alias of `temp1`}}
     break;      // expected-note {{destroyed here}}
   }
   case 2: {
     MyObj temp2;
-    v = temp2;  // expected-warning {{object whose reference is captured does not live long enough}}
+    v = temp2;  // expected-warning {{object whose reference is captured does not live long enough}} \
+                // expected-note {{variable `v` is now an alias of `temp2`}}
     break;      // expected-note {{destroyed here}}
   }
   default: {
     MyObj temp3;
-    v = temp3;  // expected-warning {{object whose reference is captured does not live long enough}}
+    v = temp3;  // expected-warning {{object whose reference is captured does not live long enough}} \
+                // expected-note {{variable `v` is now an alias of `temp3`}}
     break;      // expected-note {{destroyed here}}
   }
   }
@@ -424,7 +459,8 @@ void loan_from_previous_iteration(MyObj safe, bool condition) {
 
   while (condition) {
     MyObj x;
-    p = &x;     // expected-warning {{does not live long enough}}
+    p = &x;     // expected-warning {{does not live long enough}} \
+                // expected-note {{variable `p` is now an alias of `x`}}
 
     if (condition)
       q = p;
@@ -437,7 +473,8 @@ void trivial_int_uaf() {
   int * a;
   {
       int b = 1;
-      a = &b;  // expected-warning {{object whose reference is captured does not live long enough}}
+      a = &b;  // expected-warning {{object whose reference is captured does not live long enough}} \
+               // expected-note {{variable `a` is now an alias of `b`}}
   }            // expected-note {{destroyed here}}
   (void)*a;    // expected-note {{later used here}}
 }
@@ -446,7 +483,8 @@ void trivial_class_uaf() {
   TriviallyDestructedClass* ptr;
   {
       TriviallyDestructedClass s;
-      ptr = &s; // expected-warning {{object whose reference is captured does not live long enough}}
+      ptr = &s; // expected-warning {{object whose reference is captured does not live long enough}} \
+                // expected-note {{variable `ptr` is now an alias of `s`}}
   }             // expected-note {{destroyed here}}
   (void)ptr;    // expected-note {{later used here}}
 }
@@ -638,7 +676,8 @@ void test_view_pointer() {
   View* vp;
   {
     View v;
-    vp = &v;     // expected-warning {{object whose reference is captured does not live long enough}}
+    vp = &v;     // expected-warning {{object whose reference is captured does not live long enough}} \
+                 // expected-note {{variable `vp` is now an alias of `v`}}
   }              // expected-note {{destroyed here}}
   vp->use();     // expected-note {{later used here}}
 }
@@ -647,7 +686,8 @@ void test_view_double_pointer() {
   View** vpp;
   {
     View* vp = nullptr;
-    vpp = &vp;   // expected-warning {{object whose reference is captured does not live long enough}}
+    vpp = &vp;   // expected-warning {{object whose reference is captured does not live long enough}} \
+                 // expected-note {{variable `vpp` is now an alias of `vp`}}
   }              // expected-note {{destroyed here}}
   (**vpp).use(); // expected-note {{later used here}}
 }
@@ -673,9 +713,10 @@ void test_lifetimebound_multi_level() {
   int** result;
   {
     int* p = nullptr;
-    int** pp = &p;  
-    int*** ppp = &pp; // expected-warning {{object whose reference is captured does not live long enough}}
-    result = return_inner_ptr_addr(ppp);
+    int** pp = &p;
+    int*** ppp = &pp; // expected-warning {{object whose reference is captured does not live long enough}} \
+                      // expected-note {{variable `ppp` is now an alias of `pp`}}
+    result = return_inner_ptr_addr(ppp); // expected-note {{variable `result` is now an alias of `return_inner_ptr_addr(ppp)`}}
   }                   // expected-note {{destroyed here}}
   (void)**result;     // expected-note {{used here}}
 }
@@ -707,8 +748,9 @@ int** test_ternary_double_ptr(bool cond) {
 MyObj* uaf_before_uar() {
   MyObj* p;
   {
-    MyObj local_obj; 
-    p = &local_obj;  // expected-warning {{object whose reference is captured does not live long enough}}
+    MyObj local_obj;
+    p = &local_obj;  // expected-warning {{object whose reference is captured does not live long enough}} \
+                     // expected-note {{variable `p` is now an alias of `local_obj`}}
   }                  // expected-note {{destroyed here}}
   return p;          // expected-note {{later used here}}
 }
@@ -786,7 +828,8 @@ void lifetimebound_simple_function() {
   View v;
   {
     MyObj obj;
-    v = Identity(obj); // expected-warning {{object whose reference is captured does not live long enough}}
+    v = Identity(obj); // expected-warning {{object whose reference is captured does not live long enough}} \
+                       // expected-note {{variable `v` is now an alias of `Identity(obj)`}}
   }                    // expected-note {{destroyed here}}
   v.use();             // expected-note {{later used here}}
 }
@@ -795,7 +838,8 @@ void lifetimebound_multiple_args_definite() {
   View v;
   {
     MyObj obj1, obj2;
-    v = Choose(true,
+    v = Choose(true,  // expected-note {{variable `v` is now an alias of `Choose(true, obj1, obj2)`}} \
+                      // expected-note {{variable `v` is now an alias of `Choose(true, obj1, obj2)`}}
                obj1,  // expected-warning {{object whose reference is captured does not live long enough}}
                obj2); // expected-warning {{object whose reference is captured does not live long enough}}
   }                              // expected-note 2 {{destroyed here}}
@@ -809,7 +853,8 @@ void lifetimebound_multiple_args_potential(bool cond) {
     MyObj obj1;
     if (cond) {
       MyObj obj2;
-      v = Choose(true,
+      v = Choose(true,             // expected-note {{variable `v` is now an alias of `Choose(true, obj1, obj2)`}} \
+                                   // expected-note {{variable `v` is now an alias of `Choose(true, obj1, obj2)`}}
                  obj1,             // expected-warning {{object whose reference is captured does not live long enough}}
                  obj2);            // expected-warning {{object whose reference is captured does not live long enough}}
     }                              // expected-note {{destroyed here}}
@@ -822,7 +867,8 @@ void lifetimebound_mixed_args() {
   View v;
   {
     MyObj obj1, obj2;
-    v = SelectFirst(obj1,        // expected-warning {{object whose reference is captured does not live long enough}}
+    v = SelectFirst(obj1,        // expected-warning {{object whose reference is captured does not live long enough}} \
+                                 // expected-note {{variable `v` is now an alias of `SelectFirst(obj1, obj2)`}}
                     obj2);
   }                              // expected-note {{destroyed here}}
   v.use();                       // expected-note {{later used here}}
@@ -838,7 +884,8 @@ void lifetimebound_member_function() {
   View v;
   {
     MyObj obj;
-    v  = obj.getView(); // expected-warning {{object whose reference is captured does not live long enough}}
+    v  = obj.getView(); // expected-warning {{object whose reference is captured does not live long enough}} \
+                        // expected-note {{variable `v` is now an alias of `obj.getView()`}}
   }                     // expected-note {{destroyed here}}
   v.use();              // expected-note {{later used here}}
 }
@@ -853,7 +900,8 @@ void lifetimebound_conversion_operator() {
   View v;
   {
     LifetimeBoundConversionView obj;
-    v = obj;  // expected-warning {{object whose reference is captured does not live long enough}}
+    v = obj;  // expected-warning {{object whose reference is captured does not live long enough}} \
+              // expected-note {{variable `v` is now an alias of `obj.operator View()`}}
   }           // expected-note {{destroyed here}}
   v.use();    // expected-note {{later used here}}
 }
@@ -862,7 +910,8 @@ void lifetimebound_chained_calls() {
   View v;
   {
     MyObj obj;
-    v = Identity(Identity(Identity(obj))); // expected-warning {{object whose reference is captured does not live long enough}}
+    v = Identity(Identity(Identity(obj))); // expected-warning {{object whose reference is captured does not live long enough}} \
+                                           // expected-note {{variable `v` is now an alias of `Identity(Identity(Identity(obj)))`}}
   }                                        // expected-note {{destroyed here}}
   v.use();                                 // expected-note {{later used here}}
 }
@@ -871,7 +920,8 @@ void lifetimebound_with_pointers() {
   MyObj* ptr;
   {
     MyObj obj;
-    ptr = GetPointer(obj); // expected-warning {{object whose reference is captured does not live long enough}}
+    ptr = GetPointer(obj); // expected-warning {{object whose reference is captured does not live long enough}} \
+                           // expected-note {{variable `ptr` is now an alias of `GetPointer(obj)`}}
   }                        // expected-note {{destroyed here}}
   (void)*ptr;              // expected-note {{later used here}}
 }
@@ -889,7 +939,7 @@ void lifetimebound_partial_safety(bool cond) {
   
   if (cond) {
     MyObj temp_obj;
-    v = Choose(true, 
+    v = Choose(true,       // expected-note {{variable `v` is now an alias of `Choose(true, safe_obj, temp_obj)`}}
                safe_obj,
                temp_obj); // expected-warning {{object whose reference is captured does not live long enough}}
   }                       // expected-note {{destroyed here}}
@@ -902,9 +952,10 @@ void lifetimebound_return_reference() {
   const MyObj* ptr;
   {
     MyObj obj;
-    View temp_v = obj;  // expected-warning {{object whose reference is captured does not live long enough}}
-    const MyObj& ref = GetObject(temp_v);
-    ptr = &ref;
+    View temp_v = obj;     // expected-warning {{object whose reference is captured does not live long enough}} \
+                           // expected-note {{variable `temp_v` is now an alias of `obj`}}
+    const MyObj& ref = GetObject(temp_v); // expected-note {{variable `ref` is now an alias of `GetObject(temp_v)`}}
+    ptr = &ref;           // expected-note {{variable `ptr` is now an alias of `ref`}}
   }                       // expected-note {{destroyed here}}
   (void)*ptr;             // expected-note {{later used here}}
 }
@@ -994,7 +1045,8 @@ void conditional_operator_one_unsafe_branch(bool cond) {
   MyObj* p = &safe;
   {
     MyObj temp;
-    p = cond ? &temp  // expected-warning {{object whose reference is captured does not live long enough}}
+    p = cond ? &temp  // expected-warning {{object whose reference is captured does not live long enough}} \
+                      // expected-note {{variable `p` is now an alias of `temp`}}
              : &safe;
   }  // expected-note {{destroyed here}}
 
@@ -1010,8 +1062,10 @@ void conditional_operator_two_unsafe_branches(bool cond) {
   MyObj* p;
   {
     MyObj a, b;
-    p = cond ? &a   // expected-warning {{object whose reference is captured does not live long enough}}
-             : &b;  // expected-warning {{object whose reference is captured does not live long enough}}
+    p = cond ? &a   // expected-warning {{object whose reference is captured does not live long enough}} \
+                    // expected-note {{variable `p` is now an alias of `a`}}
+             : &b;  // expected-warning {{object whose reference is captured does not live long enough}} \
+                    // expected-note {{variable `p` is now an alias of `b`}}
   }  // expected-note 2 {{destroyed here}}
   (void)*p;  // expected-note 2 {{later used here}}
 }
@@ -1020,10 +1074,14 @@ void conditional_operator_nested(bool cond) {
   MyObj* p;
   {
     MyObj a, b, c, d;
-    p = cond ? cond ? &a    // expected-warning {{object whose reference is captured does not live long enough}}.
-                    : &b    // expected-warning {{object whose reference is captured does not live long enough}}.
-             : cond ? &c    // expected-warning {{object whose reference is captured does not live long enough}}.
-                    : &d;   // expected-warning {{object whose reference is captured does not live long enough}}.
+    p = cond ? cond ? &a    // expected-warning {{object whose reference is captured does not live long enough}}. \
+                            // expected-note {{variable `p` is now an alias of `a`}}
+                    : &b    // expected-warning {{object whose reference is captured does not live long enough}}. \
+                            // expected-note {{variable `p` is now an alias of `b`}}
+             : cond ? &c    // expected-warning {{object whose reference is captured does not live long enough}}. \
+                            // expected-note {{variable `p` is now an alias of `c`}}
+                    : &d;   // expected-warning {{object whose reference is captured does not live long enough}}. \
+                            // expected-note {{variable `p` is now an alias of `d`}}
   }  // expected-note 4 {{destroyed here}}
   (void)*p;  // expected-note 4 {{later used here}}
 }
@@ -1032,7 +1090,9 @@ void conditional_operator_lifetimebound(bool cond) {
   MyObj* p;
   {
     MyObj a, b;
-    p = Identity(cond ? &a    // expected-warning {{object whose reference is captured does not live long enough}}
+    p = Identity(cond ? &a    // expected-warning {{object whose reference is captured does not live long enough}} \
+                              // expected-note {{variable `p` is now an alias of `Identity(cond ? &a : &b)`}} \
+                              // expected-note {{variable `p` is now an alias of `Identity(cond ? &a : &b)`}}
                       : &b);  // expected-warning {{object whose reference is captured does not live long enough}}
   }  // expected-note 2 {{destroyed here}}
   (void)*p;  // expected-note 2 {{later used here}}
@@ -1042,7 +1102,9 @@ void conditional_operator_lifetimebound_nested(bool cond) {
   MyObj* p;
   {
     MyObj a, b;
-    p = Identity(cond ? Identity(&a)    // expected-warning {{object whose reference is captured does not live long enough}}
+    p = Identity(cond ? Identity(&a)    // expected-warning {{object whose reference is captured does not live long enough}} \
+                                        // expected-note {{variable `p` is now an alias of `Identity(cond ? Identity(&a) : Identity(&b))`}} \
+                                        // expected-note {{variable `p` is now an alias of `Identity(cond ? Identity(&a) : Identity(&b))`}}
                       : Identity(&b));  // expected-warning {{object whose reference is captured does not live long enough}}
   }  // expected-note 2 {{destroyed here}}
   (void)*p;  // expected-note 2 {{later used here}}
@@ -1052,7 +1114,11 @@ void conditional_operator_lifetimebound_nested_deep(bool cond) {
   MyObj* p;
   {
     MyObj a, b, c, d;
-    p = Identity(cond ? Identity(cond ? &a     // expected-warning {{object whose reference is captured does not live long enough}}
+    p = Identity(cond ? Identity(cond ? &a     // expected-warning {{object whose reference is captured does not live long enough}} \
+                                               // expected-note {{variable `p` is now an alias of `Identity(cond ? Identity(cond ? &a : &b) : Identity(cond ? &c : &d))`}} \
+                                               // expected-note {{variable `p` is now an alias of `Identity(cond ? Identity(cond ? &a : &b) : Identity(cond ? &c : &d))`}} \
+                                               // expected-note {{variable `p` is now an alias of `Identity(cond ? Identity(cond ? &a : &b) : Identity(cond ? &c : &d))`}} \
+                                               // expected-note {{variable `p` is now an alias of `Identity(cond ? Identity(cond ? &a : &b) : Identity(cond ? &c : &d))`}}
                                       : &b)    // expected-warning {{object whose reference is captured does not live long enough}}
                       : Identity(cond ? &c     // expected-warning {{object whose reference is captured does not live long enough}}
                                       : &d));  // expected-warning {{object whose reference is captured does not live long enough}}
@@ -1064,29 +1130,31 @@ void parentheses(bool cond) {
   MyObj* p;
   {
     MyObj a;
-    p = &((((a))));  // expected-warning {{object whose reference is captured does not live long enough}}
+    p = &((((a))));  // expected-warning {{object whose reference is captured does not live long enough}} \
+                     // expected-note {{variable `p` is now an alias of `a`}}
   }                  // expected-note {{destroyed here}}
   (void)*p;          // expected-note {{later used here}}
 
   {
     MyObj a;
-    p = ((GetPointer((a))));  // expected-warning {{object whose reference is captured does not live long enough}}
+    p = ((GetPointer((a))));  // expected-warning {{object whose reference is captured does not live long enough}} \
+                              // expected-note {{variable `p` is now an alias of `GetPointer((a))`}}
   }                           // expected-note {{destroyed here}}
   (void)*p;                   // expected-note {{later used here}}
 
   {
     MyObj a, b, c, d;
-    p = &(cond ? (cond ? a     // expected-warning {{object whose reference is captured does not live long enough}}.
-                       : b)    // expected-warning {{object whose reference is captured does not live long enough}}.
-               : (cond ? c     // expected-warning {{object whose reference is captured does not live long enough}}.
-                       : d));  // expected-warning {{object whose reference is captured does not live long enough}}.
+    p = &(cond ? (cond ? a     // expected-warning {{object whose reference is captured does not live long enough}}. expected-note {{variable `p` is now an alias of `a`}}
+                       : b)    // expected-warning {{object whose reference is captured does not live long enough}}. expected-note {{variable `p` is now an alias of `b`}}
+               : (cond ? c     // expected-warning {{object whose reference is captured does not live long enough}}. expected-note {{variable `p` is now an alias of `c`}}
+                       : d));  // expected-warning {{object whose reference is captured does not live long enough}}. expected-note {{variable `p` is now an alias of `d`}}
   }  // expected-note 4 {{destroyed here}}
   (void)*p;  // expected-note 4 {{later used here}}
 
   {
     MyObj a, b, c, d;
-    p = ((cond ? (((cond ? &a : &b)))   // expected-warning 2 {{object whose reference is captured does not live long enough}}.
-              : &(((cond ? c : d)))));  // expected-warning 2 {{object whose reference is captured does not live long enough}}.
+    p = ((cond ? (((cond ? &a : &b)))   // expected-warning 2 {{object whose reference is captured does not live long enough}}. expected-note {{variable `p` is now an alias of `b`}} expected-note {{variable `p` is now an alias of `a`}}
+              : &(((cond ? c : d)))));  // expected-warning 2 {{object whose reference is captured does not live long enough}}. expected-note {{variable `p` is now an alias of `d`}} expected-note {{variable `p` is now an alias of `c`}}
   }  // expected-note 4 {{destroyed here}}
   (void)*p;  // expected-note 4 {{later used here}}
 
@@ -1095,20 +1163,20 @@ void parentheses(bool cond) {
 void use_temporary_after_destruction() {
   View a;
   a = non_trivially_destructed_temporary(); // expected-warning {{object whose reference is captured does not live long enough}} \
-                  expected-note {{destroyed here}}
+                  expected-note {{destroyed here}} expected-note {{variable `a` is now an alias of `non_trivially_destructed_temporary()`}}
   use(a); // expected-note {{later used here}}
 }
 
 void passing_temporary_to_lifetime_bound_function() {
   View a = construct_view(non_trivially_destructed_temporary()); // expected-warning {{object whose reference is captured does not live long enough}} \
-                expected-note {{destroyed here}}
+                expected-note {{destroyed here}} expected-note {{variable `a` is now an alias of `construct_view(non_trivially_destructed_temporary())`}}
   use(a); // expected-note {{later used here}}
 }
 
 void use_trivial_temporary_after_destruction() {
   View a;
   a = trivially_destructed_temporary(); // expected-warning {{object whose reference is captured does not live long enough}} \
-                expected-note {{destroyed here}}
+                expected-note {{destroyed here}} expected-note {{variable `a` is now an alias of `trivially_destructed_temporary()`}}
   use(a); // expected-note {{later used here}}
 }
 
@@ -1150,7 +1218,7 @@ void foobar() {
   {
     StatusOr<MyObj> string_or = getStringOr();
     view = string_or. // expected-warning {{object whose reference is captured does not live long enough}}
-            value();
+            value();  // expected-note {{variable `view` is now an alias of `string_or.value()`}}
   }                     // expected-note {{destroyed here}}
   (void)view;           // expected-note {{later used here}}
 }
@@ -1169,8 +1237,9 @@ void range_based_for_use_after_scope() {
   View v;
   {
     MyObjStorage s;
-    for (const MyObj &o : s) { // expected-warning {{object whose reference is captured does not live long enough}}
-      v = o;
+    for (const MyObj &o : s) { // expected-warning {{object whose reference is captured does not live long enough}} \
+                               // expected-note {{variable `o` is now an alias of `__begin2`}}
+      v = o;                  // expected-note {{variable `v` is now an alias of `o`}}
     }
   } // expected-note {{destroyed here}}
   v.use(); // expected-note {{later used here}}
@@ -1190,7 +1259,8 @@ void range_based_for_not_reference() {
   {
     MyObjStorage s;
     for (MyObj o : s) { // expected-note {{destroyed here}}
-      v = o; // expected-warning {{object whose reference is captured does not live long enough}}
+      v = o; // expected-warning {{object whose reference is captured does not live long enough}} \
+             // expected-note {{variable `v` is now an alias of `o`}}
     }
   }
   v.use();  // expected-note {{later used here}}
@@ -1223,7 +1293,8 @@ void test_user_defined_deref_uaf() {
   {
     MyObj obj;
     SmartPtr<MyObj> smart_ptr(&obj);
-    p = &(*smart_ptr);  // expected-warning {{object whose reference is captured does not live long enough}}
+    p = &(*smart_ptr);  // expected-warning {{object whose reference is captured does not live long enough}} \
+                        // expected-note {{variable `p` is now an alias of `operator*(smart_ptr)`}}
   }                     // expected-note {{destroyed here}}
   (void)*p;             // expected-note {{later used here}}
 }
@@ -1240,7 +1311,8 @@ void test_user_defined_deref_with_view() {
   {
     MyObj obj;
     SmartPtr<MyObj> smart_ptr(&obj);
-    v = *smart_ptr;  // expected-warning {{object whose reference is captured does not live long enough}}
+    v = *smart_ptr;  // expected-warning {{object whose reference is captured does not live long enough}} \
+                     // expected-note {{variable `v` is now an alias of `operator*(smart_ptr)`}}
   }                  // expected-note {{destroyed here}}
   v.use();           // expected-note {{later used here}}
 }
@@ -1250,7 +1322,8 @@ void test_user_defined_deref_arrow() {
   {
     MyObj obj;
     SmartPtr<MyObj> smart_ptr(&obj);
-    p = smart_ptr.operator->();  // expected-warning {{object whose reference is captured does not live long enough}}
+    p = smart_ptr.operator->();  // expected-warning {{object whose reference is captured does not live long enough}} \
+                                 // expected-note {{variable `p` is now an alias of `smart_ptr.operator->()`}}
   }                              // expected-note {{destroyed here}}
   (void)*p;                      // expected-note {{later used here}}
 }
@@ -1260,7 +1333,8 @@ void test_user_defined_deref_chained() {
   {
     MyObj obj;
     SmartPtr<SmartPtr<MyObj>> double_ptr;
-    p = &(**double_ptr);  // expected-warning {{object whose reference is captured does not live long enough}}
+    p = &(**double_ptr);  // expected-warning {{object whose reference is captured does not live long enough}} \
+                          // expected-note {{variable `p` is now an alias of `operator*(* double_ptr)`}}
   }                       // expected-note {{destroyed here}}
   (void)*p;               // expected-note {{later used here}}
 }
@@ -1294,15 +1368,15 @@ T&& MaxT(T&& a [[clang::lifetimebound]], T&& b [[clang::lifetimebound]]);
 
 const MyObj& call_max_with_obj() {
   MyObj oa, ob;
-  return  MaxT(oa,    // expected-warning {{address of stack memory is returned later}}          
+  return  MaxT(oa,    // expected-warning {{address of stack memory is returned later}}
                       // expected-note at -1 2 {{returned here}}
                ob);   // expected-warning {{address of stack memory is returned later}}
-                    
+
 }
 
 MyObj* call_max_with_obj_error() {
   MyObj oa, ob;
-  return  &MaxT(oa,   // expected-warning {{address of stack memory is returned later}}          
+  return  &MaxT(oa,   // expected-warning {{address of stack memory is returned later}}
                       // expected-note at -1 2 {{returned here}}
                 ob);  // expected-warning {{address of stack memory is returned later}}
 }
@@ -1411,7 +1485,8 @@ void strict_warn_on_move() {
   View v;
   {
     MyObj a;
-    v = a;            // expected-warning-re {{object whose reference {{.*}} may have been moved}}
+    v = a;            // expected-warning-re {{object whose reference {{.*}} may have been moved}} \
+                      // expected-note {{variable `v` is now an alias of `a`}}
     b = std::move(a); // expected-note {{potentially moved here}}
   }                   // expected-note {{destroyed here}}
   (void)v;            // expected-note {{later used here}}
@@ -1425,7 +1500,7 @@ void flow_sensitive(bool c) {
       MyObj b = std::move(a);
       return;
     }
-    v = a;  // expected-warning {{object whose reference}}
+    v = a;  // expected-warning {{object whose reference}} expected-note {{variable `v` is now an alias of `a`}}
   }         // expected-note {{destroyed here}}
   (void)v;  // expected-note {{later used here}}
 }
@@ -1435,7 +1510,9 @@ void detect_conditional(bool cond) {
   View v;
   {
     MyObj a, b;
-    v = cond ? a : b; // expected-warning-re 2 {{object whose reference {{.*}} may have been moved}}
+    v = cond ? a : b; // expected-warning-re 2 {{object whose reference {{.*}} may have been moved}} \
+                      // expected-note {{variable `v` is now an alias of `b`}} \
+                      // expected-note {{variable `v` is now an alias of `a`}}
     take(std::move(cond ? a : b)); // expected-note 2 {{potentially moved here}}
   }         // expected-note 2 {{destroyed here}}
   (void)v;  // expected-note 2 {{later used here}}
@@ -1445,13 +1522,15 @@ void wrong_use_of_move_is_permissive() {
   View v;
   {
     MyObj a;
-    v = std::move(a); // expected-warning {{object whose reference is captured does not live long enough}}
+    v = std::move(a); // expected-warning {{object whose reference is captured does not live long enough}} \
+                      // expected-note {{variable `v` is now an alias of `std::move(a)`}}
   }         // expected-note {{destroyed here}}
   (void)v;  // expected-note {{later used here}}
   const int* p;
   {
     MyObj a;
-    p = std::move(a).getData(); // expected-warning {{object whose reference is captured does not live long enough}}
+    p = std::move(a).getData(); // expected-warning {{object whose reference is captured does not live long enough}} \
+                                // expected-note {{variable `p` is now an alias of `std::move(a).getData()`}}
   }         // expected-note {{destroyed here}}
   (void)p;  // expected-note {{later used here}}
 }
@@ -1462,7 +1541,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-re {{object whose reference {{.*}} may have been moved}}
+    r = p.get();        // expected-warning-re {{object whose reference {{.*}} may have been moved}} \
+                        // expected-note {{variable `r` is now an alias of `p.get()`}}
     take(p.release());  // expected-note {{potentially moved here}}
   }                     // expected-note {{destroyed here}}
   (void)*r;             // expected-note {{later used here}}
@@ -1484,9 +1564,10 @@ void bar() {
     View x;
     {
         S s;
-        x = s.x(); // expected-warning {{object whose reference is captured does not live long enough}}
+        x = s.x();        // expected-warning {{object whose reference is captured does not live long enough}} \
+                          // expected-note {{variable `x` is now an alias of `s.x()`}}
         View y = S().x(); // expected-warning {{object whose reference is captured does not live long enough}} \
-                             expected-note {{destroyed here}}
+                             expected-note {{destroyed here}} expected-note {{variable `y` is now an alias of `S().x()`}}
         (void)y; // expected-note {{used here}}
     } // expected-note {{destroyed here}}
     (void)x; // expected-note {{used here}}
@@ -1574,17 +1655,22 @@ 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 {{object whose reference is captured does not live long enough}} expected-note {{destroyed here}}
+  const std::string& x = S().x(); // expected-warning {{object whose reference is captured does not live long enough}} \
+                                  // expected-note {{destroyed here}} \
+                                  // expected-note {{variable `x` is now an alias of `S().x()`}}
   (void)x; // expected-note {{later used here}}
 
-  const std::string& y = identity(S().x()); // expected-warning {{object whose reference is captured does not live long enough}} expected-note {{destroyed here}}
+  const std::string& y = identity(S().x()); // expected-warning {{object whose reference is captured does not live long enough}} \
+                                            // expected-note {{destroyed here}} \
+                                            // expected-note {{variable `y` is now an alias of `identity(S().x())`}}
   (void)y; // expected-note {{later used here}}
 
   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;
+    const std::string& zz = s.x(); // expected-warning {{object whose reference is captured does not live long enough}} \
+                                   // expected-note {{variable `zz` is now an alias of `s.x()`}}
+    z = zz;                        // expected-note {{variable `z` is now an alias of `zz.operator basic_string_view()`}}
   } // expected-note {{destroyed here}}
   (void)z; // expected-note {{later used here}}
 }
@@ -1592,12 +1678,16 @@ void test_temporary() {
 void test_lifetime_extension_ok() {
   const S& x = S();
   (void)x;
-  const S& y = identity(S()); // expected-warning {{object whose reference is captured does not live long enough}} expected-note {{destroyed here}}
+  const S& y = identity(S()); // expected-warning {{object whose reference is captured does not live long enough}} \
+                              // expected-note {{destroyed here}} \
+                              // expected-note {{variable `y` is now an alias of `identity(S())`}}
   (void)y; // expected-note {{later used here}}
 }
 
 const std::string& test_return() {
-  const std::string& x = S().x(); // expected-warning {{object whose reference is captured does not live long enough}} expected-note {{destroyed here}}
+  const std::string& x = S().x(); // expected-warning {{object whose reference is captured does not live long enough}} \
+                                  // expected-note {{destroyed here}} \
+                                  // expected-note {{variable `x` is now an alias of `S().x()`}}
   return x; // expected-note {{later used here}}
 }
 } // namespace reference_type_decl_ref_expr
@@ -1613,8 +1703,9 @@ void uaf() {
   std::string_view view;
   {
     S str;
-    S* p = &str;  // expected-warning {{object whose reference is captured does not live long enough}}
-    view = p->s;
+    S* p = &str;  // expected-warning {{object whose reference is captured does not live long enough}} \
+                  // expected-note {{variable `p` is now an alias of `str`}}
+    view = p->s;  // expected-note {{variable `view` is now an alias of `p->s.operator basic_string_view()`}}
   } // expected-note {{destroyed here}}
   (void)view;  // expected-note {{later used here}}
 }
@@ -1639,8 +1730,9 @@ void uaf_union() {
   std::string_view view;
   {
     U u = U{"hello"};
-    U* up = &u;  // expected-warning {{object whose reference is captured does not live long enough}}
-    view = up->s;
+    U* up = &u;  // expected-warning {{object whose reference is captured does not live long enough}} \
+                 // expected-note {{variable `up` is now an alias of `u`}}
+    view = up->s; // expected-note {{variable `view` is now an alias of `up->s.operator basic_string_view()`}}
   } // expected-note {{destroyed here}}
   (void)view;  // expected-note {{later used here}}
 }
@@ -1656,8 +1748,8 @@ void uaf_anonymous_union() {
   int* ip;
   {
     AnonymousUnion au;
-    AnonymousUnion* up = &au;  // expected-warning {{object whose reference is captured does not live long enough}}
-    ip = &up->x;
+    AnonymousUnion* up = &au;  // expected-warning {{object whose reference is captured does not live long enough}} expected-note {{variable `up` is now an alias of `au`}}
+    ip = &up->x; // expected-note {{variable `ip` is now an alias of `up`}}
   } // expected-note {{destroyed here}}
   (void)ip;  // expected-note {{later used here}}
 }
@@ -1715,9 +1807,15 @@ const T* MemberFuncsTpl<T>::memberC(const T& x [[clang::lifetimebound]]) {
 
 void test() {
   MemberFuncsTpl<MyObj> mtf;
-  const MyObj* pTMA = mtf.memberA(MyObj()); // expected-warning {{object whose reference is captured does not live long enough}} // expected-note {{destroyed here}}
-  const MyObj* pTMB = mtf.memberB(MyObj()); // tu-warning {{object whose reference is captured does not live long enough}} // tu-note {{destroyed here}}
-  const MyObj* pTMC = mtf.memberC(MyObj()); // expected-warning {{object whose reference is captured does not live long enough}} // expected-note {{destroyed here}}
+  const MyObj* pTMA = mtf.memberA(MyObj()); // expected-warning {{object whose reference is captured does not live long enough}} \
+                                            // expected-note {{destroyed here}} \
+                                            // expected-note {{variable `pTMA` is now an alias of `mtf.memberA(MyObj())`}}
+  const MyObj* pTMB = mtf.memberB(MyObj()); // tu-warning {{object whose reference is captured does not live long enough}} \
+                                            // tu-note {{destroyed here}} \
+                                            // tu-note {{variable `pTMB` is now an alias of `mtf.memberB(MyObj())`}}
+  const MyObj* pTMC = mtf.memberC(MyObj()); // expected-warning {{object whose reference is captured does not live long enough}} \
+                                            // expected-note {{destroyed here}} \
+                                            // expected-note {{variable `pTMC` is now an alias of `mtf.memberC(MyObj())`}}
   (void)pTMA; // expected-note {{later used here}}
   (void)pTMB; // tu-note {{later used here}}
   (void)pTMC; // expected-note {{later used here}}
@@ -1752,7 +1850,8 @@ void test_optional_arrow() {
   const char* p;
   {
     std::optional<std::string> opt;
-    p = opt->data();  // expected-warning {{object whose reference is captured does not live long enough}}
+    p = opt->data();  // expected-warning {{object whose reference is captured does not live long enough}} \
+                      // expected-note {{variable `p` is now an alias of `opt->data()`}}
   }                   // expected-note {{destroyed here}}
   (void)*p;           // expected-note {{later used here}}
 }
@@ -1761,7 +1860,8 @@ void test_optional_arrow_lifetimebound() {
   View v;
   {
     std::optional<MyObj> opt;
-    v = opt->getView();  // expected-warning {{object whose reference is captured does not live long enough}}
+    v = opt->getView();  // expected-warning {{object whose reference is captured does not live long enough}} \
+                         // expected-note {{variable `v` is now an alias of `opt->getView()`}}
   }                      // expected-note {{destroyed here}}
   v.use();               // expected-note {{later used here}}
 }
@@ -1770,7 +1870,8 @@ void test_unique_ptr_arrow() {
   const char* p;
   {
     std::unique_ptr<std::string> up;
-    p = up->data();  // expected-warning {{object whose reference is captured does not live long enough}}
+    p = up->data();  // expected-warning {{object whose reference is captured does not live long enough}} \
+                     // expected-note {{variable `p` is now an alias of `up->data()`}}
   }                  // expected-note {{destroyed here}}
   (void)*p;          // expected-note {{later used here}}
 }
@@ -1961,8 +2062,9 @@ void multi_level_pointer_in_loop() {
     MyObj* p;
     MyObj** pp;
     if (i > 5) {
-      p = &obj; // expected-warning {{object whose reference is captured does not live long enough}}
-      pp = &p;
+      p = &obj; // expected-warning {{object whose reference is captured does not live long enough}} \
+                // expected-note {{variable `p` is now an alias of `obj`}}
+      pp = &p;  // expected-note {{variable `pp` is now an alias of `p`}}
     }
     (void)**pp; // expected-note {{later used here}}
   }             // expected-note {{destroyed here}}
@@ -1973,7 +2075,8 @@ void outer_pointer_outlives_inner_pointee() {
   MyObj* view = &safe;
   for (int i = 0; i < 10; ++i) {
     MyObj obj;
-    view = &obj;     // expected-warning {{object whose reference is captured does not live long enough}}
+    view = &obj;     // expected-warning {{object whose reference is captured does not live long enough}} \
+                     // expected-note {{variable `view` is now an alias of `obj`}}
   }                  // expected-note {{destroyed here}}
   (void)*view;       // expected-note {{later used here}}
 }
@@ -1986,7 +2089,8 @@ void element_use_after_scope() {
   int* p;
   {
     int a[10]{};
-    p = &a[2]; // expected-warning {{object whose reference is captured does not live long enough}}
+    p = &a[2]; // expected-warning {{object whose reference is captured does not live long enough}} \
+               // expected-note {{variable `p` is now an alias of `a`}}
   }            // expected-note {{destroyed here}}
   (void)*p;    // expected-note {{later used here}}
 }
@@ -2018,7 +2122,8 @@ void multidimensional_use_after_scope() {
   int* p;
   {
     int a[3][4]{};
-    p = &a[1][2]; // expected-warning {{object whose reference is captured does not live long enough}}
+    p = &a[1][2]; // expected-warning {{object whose reference is captured does not live long enough}} \
+                  // expected-note {{variable `p` is now an alias of `a`}}
   }               // expected-note {{destroyed here}}
   (void)*p;       // expected-note {{later used here}}
 }
@@ -2031,7 +2136,8 @@ void member_array_element_use_after_scope() {
   int* p;
   {
     S s;
-    p = &s.arr[0]; // expected-warning {{object whose reference is captured does not live long enough}}
+    p = &s.arr[0]; // expected-warning {{object whose reference is captured does not live long enough}} \
+                   // expected-note {{variable `p` is now an alias of `s`}}
   }                // expected-note {{destroyed here}}
   (void)*p;        // expected-note {{later used here}}
 }
@@ -2040,7 +2146,8 @@ void array_of_pointers_use_after_scope() {
   int** p;
   {
     int* a[10]{};
-    p = a;  // expected-warning {{object whose reference is captured does not live long enough}}
+    p = a;  // expected-warning {{object whose reference is captured does not live long enough}} \
+            // expected-note {{variable `p` is now an alias of `a`}}
   }         // expected-note {{destroyed here}}
   (void)*p; // expected-note {{later used here}}
 }
@@ -2049,7 +2156,8 @@ void reversed_subscript_use_after_scope() {
   int* p;
   {
     int a[10]{};
-    p = &(0[a]); // expected-warning {{object whose reference is captured does not live long enough}}
+    p = &(0[a]); // expected-warning {{object whose reference is captured does not live long enough}} \
+                 // expected-note {{variable `p` is now an alias of `a`}}
   }              // expected-note {{destroyed here}}
   (void)*p;      // expected-note {{later used here}}
 }
@@ -2122,9 +2230,10 @@ struct S {
 
 void indexing_with_static_operator() {
   S()(1, 2);
-  S& x = S()("1",
-             2,  // expected-warning {{object whose reference is captured does not live long enough}} expected-note {{destroyed here}}
-             3); // expected-warning {{object whose reference is captured does not live long enough}} expected-note {{destroyed here}}
+  S& x = S()("1", //expected-note {{variable `x` is now an alias of `operator()(S(), "1", 2, 3)`}} \
+                  //expected-note {{variable `x` is now an alias of `operator()(S(), "1", 2, 3)`}}
+             2,   // expected-warning {{object whose reference is captured does not live long enough}} expected-note {{destroyed here}}
+             3);  // expected-warning {{object whose reference is captured does not live long enough}} expected-note {{destroyed here}}
 
   (void)x; // expected-note 2 {{later used here}}
 

>From c411a1d9d27468c32e72e5f6c8754b4be8911e9b Mon Sep 17 00:00:00 2001
From: suoyuan666 <suoyuan666 at s5n.xyz>
Date: Fri, 27 Mar 2026 19:47:01 +0800
Subject: [PATCH 02/12] [LifetimeSafety] Refactor assignment history lookup
 into AssignmentQuery

Independent AssignmentQuery now handles the logic for searching  assignment history during error reporting, decoupling it from the diagnostic logic.

Signed-off-by: suoyuan666 <suoyuan666 at s5n.xyz>
---
 .../Analyses/LifetimeSafety/AssignmentQuery.h |  52 +++++
 .../LifetimeSafety/AssignmentQuery.cpp        | 215 ++++++++++++++++++
 .../Analysis/LifetimeSafety/CMakeLists.txt    |   1 +
 clang/lib/Analysis/LifetimeSafety/Checker.cpp | 200 +---------------
 4 files changed, 272 insertions(+), 196 deletions(-)
 create mode 100644 clang/include/clang/Analysis/Analyses/LifetimeSafety/AssignmentQuery.h
 create mode 100644 clang/lib/Analysis/LifetimeSafety/AssignmentQuery.cpp

diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/AssignmentQuery.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/AssignmentQuery.h
new file mode 100644
index 0000000000000..ecae93f250b69
--- /dev/null
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/AssignmentQuery.h
@@ -0,0 +1,52 @@
+//===- AssignmentQuery.cpp - C++ Lifetime Safety Checker --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the LifetimeChecker, which detects use-after-free
+// errors by checking if live origins hold loans that have expired.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_ASSIGNMENTQUERY_H
+#define LLVM_CLANG_ANALYSIS_ANALYSES_ASSIGNMENTQUERY_H
+
+#include "clang/AST/Decl.h"
+#include "clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h"
+#include "clang/Analysis/Analyses/LifetimeSafety/Facts.h"
+#include "clang/Analysis/Analyses/LifetimeSafety/LiveOrigins.h"
+#include "clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h"
+#include "clang/Analysis/Analyses/LifetimeSafety/MovedLoans.h"
+#include "clang/Analysis/Analyses/LifetimeSafety/Origins.h"
+#include "clang/Analysis/AnalysisDeclContext.h"
+
+namespace clang::lifetimes::internal {
+
+struct AliasAssignmentSearchResult {
+  const llvm::SmallVector<AssignmentPair> Payload;
+  bool SearchComplete;
+  const ValueDecl *LastDestDecl;
+  std::optional<OriginID> LastOrigin;
+};
+
+struct AssignmentQueryContext {
+  const LoanPropagationAnalysis &LoanPropagation;
+  const MovedLoansAnalysis &MovedLoans;
+  const LiveOriginsAnalysis &LiveOrigins;
+  FactManager &FactMgr;
+  AnalysisDeclContext &ADC;
+};
+
+/// Retrieves a list of assignment chains for use-after-scope analysis.
+///
+/// To help users understand the data flow, we track where the problematic
+/// address originated.
+std::optional<llvm::SmallVector<AssignmentPair>>
+getAliasList(const AssignmentQueryContext &Context, const UseFact *UF,
+             const LoanID End, const bool InOneBlock);
+} // namespace clang::lifetimes::internal
+
+#endif
diff --git a/clang/lib/Analysis/LifetimeSafety/AssignmentQuery.cpp b/clang/lib/Analysis/LifetimeSafety/AssignmentQuery.cpp
new file mode 100644
index 0000000000000..ed19e06a12323
--- /dev/null
+++ b/clang/lib/Analysis/LifetimeSafety/AssignmentQuery.cpp
@@ -0,0 +1,215 @@
+//===- AssignmentQuery.cpp - C++ Lifetime Safety Checker --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the LifetimeChecker, which detects use-after-free
+// errors by checking if live origins hold loans that have expired.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/Analyses/LifetimeSafety/AssignmentQuery.h"
+#include "clang/AST/Decl.h"
+#include "clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h"
+#include "clang/Analysis/Analyses/LifetimeSafety/Origins.h"
+#include "clang/Analysis/AnalysisDeclContext.h"
+#include <cstddef>
+
+namespace {
+
+using namespace clang;
+using namespace clang::lifetimes;
+using namespace clang::lifetimes::internal;
+
+std::optional<OriginSrcExpr> GetPureSrcExpr(const Expr *TargetExpr) {
+  if (!TargetExpr)
+    return std::nullopt;
+  const Expr *SExpr = TargetExpr->IgnoreParenCasts();
+  if (!SExpr)
+    return std::nullopt;
+
+  if (const auto *SDRExpr = llvm::dyn_cast<DeclRefExpr>(SExpr)) {
+    return SDRExpr;
+  }
+  if (const auto *STMExpr = llvm::dyn_cast<CXXTemporaryObjectExpr>(SExpr)) {
+    return STMExpr;
+  }
+  if (const auto *SCExpr = llvm::dyn_cast<CallExpr>(SExpr)) {
+    return SCExpr;
+  }
+
+  if (const auto *SCCExpr = llvm::dyn_cast<CXXConstructExpr>(SExpr)) {
+    if (SCCExpr->getNumArgs() > 0)
+      return GetPureSrcExpr(SCCExpr->getArg(0));
+  }
+  if (const auto *SUOExpr = llvm::dyn_cast<UnaryOperator>(SExpr)) {
+    return GetPureSrcExpr(SUOExpr->getSubExpr());
+  }
+  if (const auto *SCBExpr = llvm::dyn_cast<CXXBindTemporaryExpr>(SExpr)) {
+    return GetPureSrcExpr(SCBExpr->getSubExpr());
+  }
+
+  return std::nullopt;
+}
+
+AliasAssignmentSearchResult
+getAliasListCore(const AssignmentQueryContext &Context, const CFGBlock *Block,
+                 const LoanID EndLoanID, OriginID *TargetOID,
+                 const ValueDecl *LastDestDecl = nullptr,
+                 const std::optional<OriginID> LastOriginID = std::nullopt) {
+  llvm::SmallVector<AssignmentPair> AliasStmts;
+  const ValueDecl *DestDecl = LastDestDecl;
+  const auto Facts = Context.FactMgr.getFacts(Block);
+  bool FetchLoan = false;
+  auto IssueOriginID = LastOriginID;
+
+  for (auto F = Facts.rbegin(); F != Facts.rend(); ++F) {
+    if (const auto *OFF = (*F)->getAs<OriginFlowFact>()) {
+      if (IssueOriginID.has_value() &&
+          OFF->getDestOriginID() == IssueOriginID.value()) {
+        FetchLoan = true;
+      }
+      if (OFF->getDestOriginID() == *TargetOID) {
+        const auto HeldLoans =
+            Context.LoanPropagation.getLoans(OFF->getSrcOriginID(), OFF);
+
+        if (HeldLoans.contains(EndLoanID)) {
+          const auto TargetOrigin =
+              Context.FactMgr.getOriginMgr().getOrigin(OFF->getDestOriginID());
+
+          if (DestDecl == nullptr) {
+            if (const ValueDecl *DDecl = TargetOrigin.getDecl()) {
+              DestDecl = DDecl;
+            }
+          } else {
+            auto SExpr = GetPureSrcExpr(TargetOrigin.getExpr());
+            if (!SExpr.has_value()) {
+              const auto SrcOrigin = Context.FactMgr.getOriginMgr().getOrigin(
+                  OFF->getSrcOriginID());
+              SExpr = GetPureSrcExpr(SrcOrigin.getExpr());
+            }
+
+            if (SExpr.has_value()) {
+              AliasStmts.push_back({SExpr.value(), DestDecl});
+              DestDecl = nullptr;
+            }
+          }
+          *TargetOID = OFF->getSrcOriginID();
+        }
+      }
+    } else if (const auto *IF = (*F)->getAs<IssueFact>()) {
+      if (IF->getLoanID() == EndLoanID) {
+        IssueOriginID = IF->getOriginID();
+      }
+    }
+
+    if (FetchLoan) {
+      return {AliasStmts, true, DestDecl, IssueOriginID};
+    }
+  }
+  return {AliasStmts, false, DestDecl, IssueOriginID};
+}
+
+std::optional<llvm::SmallVector<AssignmentPair>>
+getAliasListInMultiBlock(const AssignmentQueryContext &Context,
+                         const CFGBlock *StartBlock, const LoanID EndLoanID,
+                         OriginID *StartOID) {
+  const ValueDecl *LastDestDecl = nullptr;
+  llvm::SmallVector<const CFGBlock *> PendingBlocks;
+  std::optional<AssignmentPair> StartStmt = std::nullopt;
+  std::optional<AssignmentPair> EndStmt = std::nullopt;
+  std::optional<OriginID> LastOriginID = std::nullopt;
+  llvm::SmallPtrSet<const CFGBlock *, 32> VistedBlocks;
+  llvm::DenseMap<AssignmentPair, AssignmentPair> VistedExprs;
+
+  const auto AliasStmtFilter = [&VistedExprs](const AssignmentPair StartStmt,
+                                              const AssignmentPair EndStmt) {
+    llvm::SmallVector<AssignmentPair> AliasStmts;
+    for (auto Stmt = StartStmt; Stmt != EndStmt; Stmt = VistedExprs.at(Stmt)) {
+      AliasStmts.push_back(Stmt);
+    }
+    AliasStmts.push_back(EndStmt);
+    return AliasStmts;
+  };
+
+  PendingBlocks.push_back(StartBlock);
+
+  for (size_t i = 0; i < PendingBlocks.size(); ++i) {
+    const CFGBlock *CurrBlock = PendingBlocks[i];
+
+    const auto [BlockAliasList, Success, CurrLastDestDecl, CurrLastOriginID] =
+        getAliasListCore(Context, CurrBlock, EndLoanID, StartOID, LastDestDecl,
+                         LastOriginID);
+    if (CurrLastDestDecl)
+      LastDestDecl = CurrLastDestDecl;
+    if (CurrLastOriginID.has_value())
+      LastOriginID = CurrLastOriginID;
+
+    if (!BlockAliasList.empty()) {
+      if (VistedExprs.empty()) {
+        StartStmt = BlockAliasList[0];
+      }
+
+      for (size_t i = 0; i < BlockAliasList.size() - 1; ++i) {
+        VistedExprs.insert({BlockAliasList[i], BlockAliasList[i + 1]});
+      }
+
+      if (EndStmt.has_value())
+        VistedExprs.insert({EndStmt.value(), BlockAliasList[0]});
+
+      EndStmt = BlockAliasList[BlockAliasList.size() - 1];
+    }
+
+    if (Success && StartStmt.has_value() && EndStmt.has_value()) {
+      return AliasStmtFilter(StartStmt.value(), EndStmt.value());
+    }
+
+    for (const auto Block : CurrBlock->preds()) {
+      if (Block && VistedBlocks.insert(Block).second)
+        PendingBlocks.push_back(Block);
+    }
+
+    if (VistedBlocks.size() >= 32 && StartStmt.has_value() &&
+        EndStmt.has_value()) {
+      return AliasStmtFilter(StartStmt.value(), EndStmt.value());
+    }
+  }
+
+  if (StartStmt.has_value() && EndStmt.has_value()) {
+    return AliasStmtFilter(StartStmt.value(), EndStmt.value());
+  }
+
+  return std::nullopt;
+}
+} // namespace
+
+namespace clang::lifetimes::internal {
+
+std::optional<llvm::SmallVector<AssignmentPair>>
+getAliasList(const AssignmentQueryContext &Context, const UseFact *UF,
+             const LoanID End, const bool InOneBlock) {
+  const CFGBlock *IssueBlock =
+      Context.ADC.getCFGStmtMap()->getBlock(UF->getUseExpr());
+  assert(IssueBlock && "Searching CFGBlock failed");
+
+  for (const OriginList *Cur = UF->getUsedOrigins(); Cur;
+       Cur = Cur->peelOuterOrigin()) {
+    auto TargetOID = Cur->getOuterOriginID();
+    if (InOneBlock) {
+      AliasAssignmentSearchResult Result =
+          getAliasListCore(Context, IssueBlock, End, &TargetOID);
+      if (!Result.Payload.empty())
+        return Result.Payload;
+    } else {
+      auto Result =
+          getAliasListInMultiBlock(Context, IssueBlock, End, &TargetOID);
+      if (Result.has_value())
+        return Result.value();
+    }
+  }
+  return std::nullopt;
+}
+} // namespace clang::lifetimes::internal
diff --git a/clang/lib/Analysis/LifetimeSafety/CMakeLists.txt b/clang/lib/Analysis/LifetimeSafety/CMakeLists.txt
index 247377c7256d9..6c4d4e123908a 100644
--- a/clang/lib/Analysis/LifetimeSafety/CMakeLists.txt
+++ b/clang/lib/Analysis/LifetimeSafety/CMakeLists.txt
@@ -1,4 +1,5 @@
 add_clang_library(clangAnalysisLifetimeSafety
+  AssignmentQuery.cpp
   Checker.cpp
   Facts.cpp
   FactsGenerator.cpp
diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
index 55617469a410a..023496a75fc7b 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -14,6 +14,7 @@
 #include "clang/Analysis/Analyses/LifetimeSafety/Checker.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/Expr.h"
+#include "clang/Analysis/Analyses/LifetimeSafety/AssignmentQuery.h"
 #include "clang/Analysis/Analyses/LifetimeSafety/Facts.h"
 #include "clang/Analysis/Analyses/LifetimeSafety/LifetimeAnnotations.h"
 #include "clang/Analysis/Analyses/LifetimeSafety/LiveOrigins.h"
@@ -56,13 +57,6 @@ using AnnotationTarget =
 using EscapingTarget =
     llvm::PointerUnion<const Expr *, const FieldDecl *, const VarDecl *>;
 
-struct AliasAssignmentSearchResult {
-  const llvm::SmallVector<AssignmentPair> Payload;
-  bool SearchComplete;
-  const ValueDecl *LastDestDecl;
-  std::optional<OriginID> LastOrigin;
-};
-
 class LifetimeChecker {
 private:
   llvm::DenseMap<LoanID, PendingWarning> FinalWarningsMap;
@@ -227,194 +221,6 @@ class LifetimeChecker {
     }
   }
 
-  std::optional<llvm::SmallVector<AssignmentPair>>
-  getAliasListInMultiBlock(const CFGBlock *StartBlock, const LoanID EndLoanID,
-                           OriginID *StartOID) {
-    const ValueDecl *LastDestDecl = nullptr;
-    llvm::SmallVector<const CFGBlock *> PendingBlocks;
-    std::optional<AssignmentPair> StartStmt = std::nullopt;
-    std::optional<AssignmentPair> EndStmt = std::nullopt;
-    std::optional<OriginID> LastOriginID = std::nullopt;
-    llvm::SmallPtrSet<const CFGBlock *, 32> VistedBlocks;
-    llvm::DenseMap<AssignmentPair, AssignmentPair> VistedExprs;
-
-    const auto AliasStmtFilter = [&VistedExprs](const AssignmentPair StartStmt,
-                                                const AssignmentPair EndStmt) {
-      llvm::SmallVector<AssignmentPair> AliasStmts;
-      for (auto Stmt = StartStmt; Stmt != EndStmt;
-           Stmt = VistedExprs.at(Stmt)) {
-        AliasStmts.push_back(Stmt);
-      }
-      AliasStmts.push_back(EndStmt);
-      return AliasStmts;
-    };
-
-    PendingBlocks.push_back(StartBlock);
-
-    for (size_t i = 0; i < PendingBlocks.size(); ++i) {
-      const CFGBlock *CurrBlock = PendingBlocks[i];
-
-      const auto [BlockAliasList, Success, CurrLastDestDecl, CurrLastOriginID] =
-          getAliasListCore(CurrBlock, EndLoanID, StartOID, LastDestDecl,
-                           LastOriginID);
-      if (CurrLastDestDecl)
-        LastDestDecl = CurrLastDestDecl;
-      if (CurrLastOriginID.has_value())
-        LastOriginID = CurrLastOriginID;
-
-      if (!BlockAliasList.empty()) {
-        if (VistedExprs.empty()) {
-          StartStmt = BlockAliasList[0];
-        }
-
-        for (size_t i = 0; i < BlockAliasList.size() - 1; ++i) {
-          VistedExprs.insert({BlockAliasList[i], BlockAliasList[i + 1]});
-        }
-
-        if (EndStmt.has_value())
-          VistedExprs.insert({EndStmt.value(), BlockAliasList[0]});
-
-        EndStmt = BlockAliasList[BlockAliasList.size() - 1];
-      }
-
-      if (Success && StartStmt.has_value() && EndStmt.has_value()) {
-        return AliasStmtFilter(StartStmt.value(), EndStmt.value());
-      }
-
-      for (const auto Block : CurrBlock->preds()) {
-        if (Block && VistedBlocks.insert(Block).second)
-          PendingBlocks.push_back(Block);
-      }
-
-      if (VistedBlocks.size() >= 32 && StartStmt.has_value() &&
-          EndStmt.has_value()) {
-        return AliasStmtFilter(StartStmt.value(), EndStmt.value());
-      }
-    }
-
-    if (StartStmt.has_value() && EndStmt.has_value()) {
-      return AliasStmtFilter(StartStmt.value(), EndStmt.value());
-    }
-
-    return std::nullopt;
-  }
-
-  std::optional<OriginSrcExpr> GetPureSrcExpr(const Expr *TargetExpr) {
-    if (!TargetExpr)
-      return std::nullopt;
-    const Expr *SExpr = TargetExpr->IgnoreParenCasts();
-    if (!SExpr)
-      return std::nullopt;
-
-    if (const auto *SDRExpr = llvm::dyn_cast<DeclRefExpr>(SExpr)) {
-      return SDRExpr;
-    }
-    if (const auto *STMExpr = llvm::dyn_cast<CXXTemporaryObjectExpr>(SExpr)) {
-      return STMExpr;
-    }
-    if (const auto *SCExpr = llvm::dyn_cast<CallExpr>(SExpr)) {
-      return SCExpr;
-    }
-
-    if (const auto *SCCExpr = llvm::dyn_cast<CXXConstructExpr>(SExpr)) {
-      if (SCCExpr->getNumArgs() > 0)
-        return GetPureSrcExpr(SCCExpr->getArg(0));
-    }
-    if (const auto *SUOExpr = llvm::dyn_cast<UnaryOperator>(SExpr)) {
-      return GetPureSrcExpr(SUOExpr->getSubExpr());
-    }
-    if (const auto *SCBExpr = llvm::dyn_cast<CXXBindTemporaryExpr>(SExpr)) {
-      return GetPureSrcExpr(SCBExpr->getSubExpr());
-    }
-
-    return std::nullopt;
-  }
-
-  /// Retrieves a list of assignment chains for use-after-scope analysis.
-  ///
-  /// To help users understand the data flow, we track where the problematic
-  /// address originated.
-  AliasAssignmentSearchResult
-  getAliasListCore(const CFGBlock *Block, const LoanID EndLoanID,
-                   OriginID *TargetOID, const ValueDecl *LastDestDecl = nullptr,
-                   const std::optional<OriginID> LastOriginID = std::nullopt) {
-    llvm::SmallVector<AssignmentPair> AliasStmts;
-    const ValueDecl *DestDecl = LastDestDecl;
-    const auto Facts = FactMgr.getFacts(Block);
-    bool FetchLoan = false;
-    auto IssueOriginID = LastOriginID;
-
-    for (auto F = Facts.rbegin(); F != Facts.rend(); ++F) {
-      if (const auto *OFF = (*F)->getAs<OriginFlowFact>()) {
-        if (IssueOriginID.has_value() &&
-            OFF->getDestOriginID() == IssueOriginID.value()) {
-          FetchLoan = true;
-        }
-        if (OFF->getDestOriginID() == *TargetOID) {
-          const auto HeldLoans =
-              LoanPropagation.getLoans(OFF->getSrcOriginID(), OFF);
-
-          if (HeldLoans.contains(EndLoanID)) {
-            const auto TargetOrigin =
-                FactMgr.getOriginMgr().getOrigin(OFF->getDestOriginID());
-
-            if (DestDecl == nullptr) {
-              if (const ValueDecl *DDecl = TargetOrigin.getDecl()) {
-                DestDecl = DDecl;
-              }
-            } else {
-              auto SExpr = GetPureSrcExpr(TargetOrigin.getExpr());
-              if (!SExpr.has_value()) {
-                const auto SrcOrigin =
-                    FactMgr.getOriginMgr().getOrigin(OFF->getSrcOriginID());
-                SExpr = GetPureSrcExpr(SrcOrigin.getExpr());
-              }
-
-              if (SExpr.has_value()) {
-                AliasStmts.push_back({SExpr.value(), DestDecl});
-                DestDecl = nullptr;
-              }
-            }
-            *TargetOID = OFF->getSrcOriginID();
-          }
-        }
-      } else if (const auto *IF = (*F)->getAs<IssueFact>()) {
-        if (IF->getLoanID() == EndLoanID) {
-          IssueOriginID = IF->getOriginID();
-        }
-      }
-
-      if (FetchLoan) {
-        return {AliasStmts, true, DestDecl, IssueOriginID};
-      }
-    }
-    return {AliasStmts, false, DestDecl, IssueOriginID};
-  }
-
-  std::optional<llvm::SmallVector<AssignmentPair>>
-  getAliasList(const UseFact *UF, const LoanID End, const bool InOneBlock) {
-    const CFGBlock *IssueBlock =
-        ADC.getCFGStmtMap()->getBlock(UF->getUseExpr());
-    assert(IssueBlock && "Searching CFGBlock failed");
-
-    for (const OriginList *Cur = UF->getUsedOrigins(); Cur;
-         Cur = Cur->peelOuterOrigin()) {
-      auto TargetOID = Cur->getOuterOriginID();
-      if (InOneBlock) {
-        AliasAssignmentSearchResult Result =
-            getAliasListCore(IssueBlock, End, &TargetOID);
-        if (!Result.Payload.empty())
-          return Result.Payload;
-      } else {
-        auto Result = getAliasListInMultiBlock(IssueBlock, End, &TargetOID);
-        if (Result.has_value())
-          return Result.value();
-      }
-    }
-
-    return std::nullopt;
-  }
-
   void issuePendingWarnings() {
     if (!SemaHelper)
       return;
@@ -441,9 +247,11 @@ class LifetimeChecker {
 
         } else {
           // Scope-based expiry (use-after-scope).
+          const struct AssignmentQueryContext Context = {
+              LoanPropagation, MovedLoans, LiveOrigins, FactMgr, ADC};
           const CFGStmtMap *CurrCFGStmtMap = ADC.getCFGStmtMap();
           const auto AliasExprs =
-              getAliasList(UF, LID,
+              getAliasList(Context, UF, LID,
                            CurrCFGStmtMap->getBlock(UF->getUseExpr()) ==
                                CurrCFGStmtMap->getBlock(IssueExpr));
           if (!AliasExprs.has_value()) {

>From 6eddd3939da62f8ed81c502bd3ae2371e61bfbb7 Mon Sep 17 00:00:00 2001
From: suoyuan666 <suoyuan666 at s5n.xyz>
Date: Fri, 27 Mar 2026 21:54:48 +0800
Subject: [PATCH 03/12] [LifetimeSafety]: refactor AssignmentQuery to support
 other erros handling

Redesign error handling for assignment statements to match the format suggested in PR review.

Note: This commit does not yet integrate the search into other error scenarios; that will be addressed in a follow-up commit.

Signed-off-by: suoyuan666 <suoyuan666 at s5n.xyz>
---
 .../Analyses/LifetimeSafety/AssignmentQuery.h |  34 +-
 .../Analyses/LifetimeSafety/LifetimeSafety.h  |  15 +-
 .../clang/Basic/DiagnosticSemaKinds.td        |   2 +-
 .../LifetimeSafety/AssignmentQuery.cpp        | 208 +++++++---
 clang/lib/Analysis/LifetimeSafety/Checker.cpp |   8 +-
 clang/lib/Sema/SemaLifetimeSafety.h           |  87 ++---
 .../Sema/warn-lifetime-analysis-nocfg.cpp     | 123 ++++--
 .../Sema/warn-lifetime-safety-cfg-bailout.cpp |   6 +-
 .../Sema/warn-lifetime-safety-suggestions.cpp |   9 +-
 clang/test/Sema/warn-lifetime-safety.cpp      | 368 +++++++++++-------
 10 files changed, 549 insertions(+), 311 deletions(-)

diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/AssignmentQuery.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/AssignmentQuery.h
index ecae93f250b69..b0f99a8b094ce 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/AssignmentQuery.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/AssignmentQuery.h
@@ -15,7 +15,6 @@
 #define LLVM_CLANG_ANALYSIS_ANALYSES_ASSIGNMENTQUERY_H
 
 #include "clang/AST/Decl.h"
-#include "clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h"
 #include "clang/Analysis/Analyses/LifetimeSafety/Facts.h"
 #include "clang/Analysis/Analyses/LifetimeSafety/LiveOrigins.h"
 #include "clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h"
@@ -23,12 +22,39 @@
 #include "clang/Analysis/Analyses/LifetimeSafety/Origins.h"
 #include "clang/Analysis/AnalysisDeclContext.h"
 
+namespace clang::lifetimes {
+
+using OriginDestExpr =
+    llvm::PointerUnion<const DeclRefExpr *, const ValueDecl *>;
+
+using AssignmentPair = std::pair<OriginDestExpr, const Expr *>;
+
+struct ExprPrintingResult {
+  llvm::SmallString<32> Value;
+  const Expr *CurrExpr;
+};
+
+ExprPrintingResult FormatIssueExprForSema(const Expr *IssueExpr);
+llvm::SmallVector<ExprPrintingResult> FormatSrcExprForSema(const Expr *SrcExpr);
+
+inline __attribute__((always_inline)) llvm::SmallString<32>
+FormatValueDeclForSema(const ValueDecl *TargetValue) {
+  llvm::SmallString<32> Result;
+  if (TargetValue) {
+    Result += "variable '";
+    Result += TargetValue->getName();
+    Result += "'";
+  }
+  return Result;
+}
+} // namespace clang::lifetimes
+
 namespace clang::lifetimes::internal {
 
 struct AliasAssignmentSearchResult {
   const llvm::SmallVector<AssignmentPair> Payload;
   bool SearchComplete;
-  const ValueDecl *LastDestDecl;
+  const std::optional<OriginDestExpr> LastDestDecl;
   std::optional<OriginID> LastOrigin;
 };
 
@@ -45,8 +71,8 @@ struct AssignmentQueryContext {
 /// To help users understand the data flow, we track where the problematic
 /// address originated.
 std::optional<llvm::SmallVector<AssignmentPair>>
-getAliasList(const AssignmentQueryContext &Context, const UseFact *UF,
-             const LoanID End, const bool InOneBlock);
+getAliasList(const AssignmentQueryContext &Context, const Fact *CausingFact,
+             const LoanID End, const Expr *IssueExpr);
 } // namespace clang::lifetimes::internal
 
 #endif
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
index f1298ec528957..40bc24f87b357 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
@@ -21,6 +21,7 @@
 #define LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_H
 
 #include "clang/AST/Decl.h"
+#include "clang/Analysis/Analyses/LifetimeSafety/AssignmentQuery.h"
 #include "clang/Analysis/Analyses/LifetimeSafety/Facts.h"
 #include "clang/Analysis/Analyses/LifetimeSafety/LifetimeStats.h"
 #include "clang/Analysis/Analyses/LifetimeSafety/LiveOrigins.h"
@@ -45,11 +46,6 @@ enum class SuggestionScope {
   IntraTU  // For suggestions on definitions local to a Translation Unit.
 };
 
-using OriginSrcExpr =
-    llvm::PointerUnion<const DeclRefExpr *, const CXXTemporaryObjectExpr *,
-                       const CallExpr *>;
-using AssignmentPair = std::pair<OriginSrcExpr, const ValueDecl *>;
-
 /// Abstract interface for operations requiring Sema access.
 ///
 /// This class exists to break a circular dependency: the LifetimeSafety
@@ -65,11 +61,10 @@ class LifetimeSafetySemaHelper {
   LifetimeSafetySemaHelper() = default;
   virtual ~LifetimeSafetySemaHelper() = default;
 
-  virtual void
-  reportUseAfterFree(const Expr *IssueExpr, const Expr *UseExpr,
-                     const Expr *MovedExpr,
-                     const llvm::SmallVector<AssignmentPair> AliasList,
-                     SourceLocation FreeLoc) {}
+  virtual void reportUseAfterFree(
+      const Expr *IssueExpr, const Expr *UseExpr, const Expr *MovedExpr,
+      const std::optional<llvm::SmallVector<AssignmentPair>> AliasList,
+      SourceLocation FreeLoc) {}
 
   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 a54e6770b517c..45f826bb80c53 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -11005,7 +11005,7 @@ def note_lifetime_safety_dangling_static_here: Note<"this static storage dangles
 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_note_alias_chain : Note<"variable `%0` is now an alias of `%1`">;
+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/AssignmentQuery.cpp b/clang/lib/Analysis/LifetimeSafety/AssignmentQuery.cpp
index ed19e06a12323..c3506f20f57d9 100644
--- a/clang/lib/Analysis/LifetimeSafety/AssignmentQuery.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/AssignmentQuery.cpp
@@ -24,54 +24,54 @@ using namespace clang;
 using namespace clang::lifetimes;
 using namespace clang::lifetimes::internal;
 
-std::optional<OriginSrcExpr> GetPureSrcExpr(const Expr *TargetExpr) {
+std::optional<const Expr *> GetPureSrcExpr(const Expr *TargetExpr) {
   if (!TargetExpr)
     return std::nullopt;
   const Expr *SExpr = TargetExpr->IgnoreParenCasts();
   if (!SExpr)
     return std::nullopt;
 
-  if (const auto *SDRExpr = llvm::dyn_cast<DeclRefExpr>(SExpr)) {
-    return SDRExpr;
-  }
-  if (const auto *STMExpr = llvm::dyn_cast<CXXTemporaryObjectExpr>(SExpr)) {
-    return STMExpr;
-  }
-  if (const auto *SCExpr = llvm::dyn_cast<CallExpr>(SExpr)) {
+  if (llvm::isa<DeclRefExpr, CXXTemporaryObjectExpr, ConditionalOperator,
+                CXXConstructExpr>(SExpr) &&
+      !SExpr->getExprLoc().isInvalid())
+    return SExpr;
+
+  if (const auto *SCExpr = llvm::dyn_cast<CallExpr>(SExpr);
+      SCExpr && !SCExpr->getExprLoc().isInvalid() &&
+      !SCExpr->getCallee()->IgnoreParenCasts()->getExprLoc().isInvalid())
     return SCExpr;
-  }
 
-  if (const auto *SCCExpr = llvm::dyn_cast<CXXConstructExpr>(SExpr)) {
-    if (SCCExpr->getNumArgs() > 0)
-      return GetPureSrcExpr(SCCExpr->getArg(0));
-  }
-  if (const auto *SUOExpr = llvm::dyn_cast<UnaryOperator>(SExpr)) {
+  if (const auto *SMExpr = llvm::dyn_cast<MemberExpr>(SExpr))
+    return GetPureSrcExpr(SMExpr->getBase());
+  if (const auto *SCExpr = llvm::dyn_cast<CXXMemberCallExpr>(SExpr))
+    return GetPureSrcExpr(SCExpr->getCallee());
+  if (const auto *SUOExpr = llvm::dyn_cast<UnaryOperator>(SExpr))
     return GetPureSrcExpr(SUOExpr->getSubExpr());
-  }
-  if (const auto *SCBExpr = llvm::dyn_cast<CXXBindTemporaryExpr>(SExpr)) {
+  if (const auto *SCBExpr = llvm::dyn_cast<CXXBindTemporaryExpr>(SExpr))
     return GetPureSrcExpr(SCBExpr->getSubExpr());
-  }
 
   return std::nullopt;
 }
 
-AliasAssignmentSearchResult
-getAliasListCore(const AssignmentQueryContext &Context, const CFGBlock *Block,
-                 const LoanID EndLoanID, OriginID *TargetOID,
-                 const ValueDecl *LastDestDecl = nullptr,
-                 const std::optional<OriginID> LastOriginID = std::nullopt) {
+AliasAssignmentSearchResult getAliasListCore(
+    const AssignmentQueryContext &Context, const CFGBlock *Block,
+    const LoanID EndLoanID, OriginID *TargetOID,
+    const std::optional<OriginDestExpr> LastDestDecl = std::nullopt,
+    const std::optional<OriginID> LastOriginID = std::nullopt) {
+  std::optional<OriginID> CurrOrigin = std::nullopt;
+  std::optional<OriginDestExpr> DestDecl = LastDestDecl;
+  std::optional<const Expr *> SrcExpr = std::nullopt;
   llvm::SmallVector<AssignmentPair> AliasStmts;
-  const ValueDecl *DestDecl = LastDestDecl;
   const auto Facts = Context.FactMgr.getFacts(Block);
   bool FetchLoan = false;
   auto IssueOriginID = LastOriginID;
 
-  for (auto F = Facts.rbegin(); F != Facts.rend(); ++F) {
-    if (const auto *OFF = (*F)->getAs<OriginFlowFact>()) {
+  for (const auto &F : llvm::reverse(Facts)) {
+    if (const auto *OFF = F->getAs<OriginFlowFact>()) {
       if (IssueOriginID.has_value() &&
-          OFF->getDestOriginID() == IssueOriginID.value()) {
+          OFF->getDestOriginID() == IssueOriginID.value())
         FetchLoan = true;
-      }
+
       if (OFF->getDestOriginID() == *TargetOID) {
         const auto HeldLoans =
             Context.LoanPropagation.getLoans(OFF->getSrcOriginID(), OFF);
@@ -80,9 +80,11 @@ getAliasListCore(const AssignmentQueryContext &Context, const CFGBlock *Block,
           const auto TargetOrigin =
               Context.FactMgr.getOriginMgr().getOrigin(OFF->getDestOriginID());
 
-          if (DestDecl == nullptr) {
-            if (const ValueDecl *DDecl = TargetOrigin.getDecl()) {
-              DestDecl = DDecl;
+          if (!DestDecl.has_value()) {
+            if (const ValueDecl *DVecl = TargetOrigin.getDecl();
+                DVecl && !DVecl->getLocation().isInvalid()) {
+              CurrOrigin = *TargetOID;
+              DestDecl = DVecl;
             }
           } else {
             auto SExpr = GetPureSrcExpr(TargetOrigin.getExpr());
@@ -93,17 +95,36 @@ getAliasListCore(const AssignmentQueryContext &Context, const CFGBlock *Block,
             }
 
             if (SExpr.has_value()) {
-              AliasStmts.push_back({SExpr.value(), DestDecl});
-              DestDecl = nullptr;
+              AliasStmts.push_back({DestDecl.value(), SExpr.value()});
+              SrcExpr = SExpr.value();
+              DestDecl = std::nullopt;
+              CurrOrigin = std::nullopt;
             }
           }
           *TargetOID = OFF->getSrcOriginID();
         }
       }
-    } else if (const auto *IF = (*F)->getAs<IssueFact>()) {
+    } else if (const auto *IF = F->getAs<IssueFact>()) {
       if (IF->getLoanID() == EndLoanID) {
         IssueOriginID = IF->getOriginID();
       }
+    } else if (const auto *UF = F->getAs<UseFact>()) {
+      if (CurrOrigin.has_value()) {
+        for (const OriginList *Cur = UF->getUsedOrigins(); Cur;
+             Cur = Cur->peelOuterOrigin()) {
+          if (Cur->getOuterOriginID() == CurrOrigin.value() &&
+              UF->isWritten()) {
+            const auto UExpr = GetPureSrcExpr(UF->getUseExpr());
+            if (UExpr.has_value()) {
+              if (const auto *UDExpr =
+                      llvm::dyn_cast<DeclRefExpr>(UExpr.value())) {
+                DestDecl = UDExpr;
+                break;
+              }
+            }
+          }
+        }
+      }
     }
 
     if (FetchLoan) {
@@ -117,7 +138,7 @@ std::optional<llvm::SmallVector<AssignmentPair>>
 getAliasListInMultiBlock(const AssignmentQueryContext &Context,
                          const CFGBlock *StartBlock, const LoanID EndLoanID,
                          OriginID *StartOID) {
-  const ValueDecl *LastDestDecl = nullptr;
+  std::optional<OriginDestExpr> LastDestDecl = std::nullopt;
   llvm::SmallVector<const CFGBlock *> PendingBlocks;
   std::optional<AssignmentPair> StartStmt = std::nullopt;
   std::optional<AssignmentPair> EndStmt = std::nullopt;
@@ -128,9 +149,8 @@ getAliasListInMultiBlock(const AssignmentQueryContext &Context,
   const auto AliasStmtFilter = [&VistedExprs](const AssignmentPair StartStmt,
                                               const AssignmentPair EndStmt) {
     llvm::SmallVector<AssignmentPair> AliasStmts;
-    for (auto Stmt = StartStmt; Stmt != EndStmt; Stmt = VistedExprs.at(Stmt)) {
+    for (auto Stmt = StartStmt; Stmt != EndStmt; Stmt = VistedExprs.at(Stmt))
       AliasStmts.push_back(Stmt);
-    }
     AliasStmts.push_back(EndStmt);
     return AliasStmts;
   };
@@ -149,13 +169,11 @@ getAliasListInMultiBlock(const AssignmentQueryContext &Context,
       LastOriginID = CurrLastOriginID;
 
     if (!BlockAliasList.empty()) {
-      if (VistedExprs.empty()) {
+      if (VistedExprs.empty())
         StartStmt = BlockAliasList[0];
-      }
 
-      for (size_t i = 0; i < BlockAliasList.size() - 1; ++i) {
+      for (size_t i = 0; i < BlockAliasList.size() - 1; ++i)
         VistedExprs.insert({BlockAliasList[i], BlockAliasList[i + 1]});
-      }
 
       if (EndStmt.has_value())
         VistedExprs.insert({EndStmt.value(), BlockAliasList[0]});
@@ -163,49 +181,129 @@ getAliasListInMultiBlock(const AssignmentQueryContext &Context,
       EndStmt = BlockAliasList[BlockAliasList.size() - 1];
     }
 
-    if (Success && StartStmt.has_value() && EndStmt.has_value()) {
+    if (Success && StartStmt.has_value() && EndStmt.has_value())
       return AliasStmtFilter(StartStmt.value(), EndStmt.value());
-    }
 
-    for (const auto Block : CurrBlock->preds()) {
+    for (const auto &Block : CurrBlock->preds())
       if (Block && VistedBlocks.insert(Block).second)
         PendingBlocks.push_back(Block);
-    }
 
     if (VistedBlocks.size() >= 32 && StartStmt.has_value() &&
-        EndStmt.has_value()) {
+        EndStmt.has_value())
       return AliasStmtFilter(StartStmt.value(), EndStmt.value());
-    }
   }
 
-  if (StartStmt.has_value() && EndStmt.has_value()) {
+  if (StartStmt.has_value() && EndStmt.has_value())
     return AliasStmtFilter(StartStmt.value(), EndStmt.value());
-  }
 
   return std::nullopt;
 }
 } // namespace
 
+namespace clang::lifetimes {
+
+ExprPrintingResult FormatIssueExprForSema(const Expr *IssueExpr) {
+  if (!IssueExpr)
+    return {};
+  const auto *PureExpr = IssueExpr->IgnoreParenCasts();
+  if (!PureExpr)
+    return {};
+
+  if (const auto *IDeclExpr = llvm::dyn_cast<DeclRefExpr>(PureExpr))
+    return {FormatValueDeclForSema(IDeclExpr->getDecl()), IssueExpr};
+  return {{"the temporary"}, IssueExpr};
+}
+
+llvm::SmallVector<ExprPrintingResult>
+FormatSrcExprForSema(const Expr *SrcExpr) {
+  if (!SrcExpr)
+    return {};
+  const auto *PureExpr = SrcExpr->IgnoreParenCasts();
+  if (!PureExpr)
+    return {};
+
+  if (const auto *IOpCallExpr = llvm::dyn_cast<CXXOperatorCallExpr>(PureExpr);
+      IOpCallExpr && !IOpCallExpr->getExprLoc().isInvalid())
+    return {{{"expression"}, IOpCallExpr->getArg(0)}};
+  if (const auto *IDeclExpr = llvm::dyn_cast<DeclRefExpr>(PureExpr);
+      IDeclExpr && !IDeclExpr->getExprLoc().isInvalid())
+    return {{{}, IDeclExpr}};
+
+  if (const auto *ICXXCallExpr = llvm::dyn_cast<CXXMemberCallExpr>(PureExpr);
+      ICXXCallExpr && !ICXXCallExpr->getExprLoc().isInvalid()) {
+    llvm::SmallVector<ExprPrintingResult> Result;
+    if (!ICXXCallExpr->getCallee()->getExprLoc().isInvalid())
+      Result.push_back({{"function call result"}, ICXXCallExpr});
+    if (const auto *SubExpr = ICXXCallExpr->getImplicitObjectArgument();
+        SubExpr && !llvm::isa<DeclRefExpr>(SubExpr->IgnoreParenCasts())) {
+      Result.append(FormatSrcExprForSema(SubExpr));
+    }
+    return Result;
+  }
+  if (const auto *ICallExpr = llvm::dyn_cast<CallExpr>(PureExpr);
+      ICallExpr && !ICallExpr->getExprLoc().isInvalid()) {
+    llvm::SmallVector<ExprPrintingResult> Result;
+    if (!ICallExpr->getCallee()->getExprLoc().isInvalid())
+      Result.push_back({{"function call result"}, ICallExpr});
+    if (const auto *SubExpr = ICallExpr->getCallee();
+        SubExpr && !llvm::isa<DeclRefExpr>(SubExpr->IgnoreParenCasts())) {
+      Result.append(FormatSrcExprForSema(SubExpr));
+    }
+    return Result;
+  }
+  if (const auto *IMemberExpr = llvm::dyn_cast<MemberExpr>(PureExpr);
+      IMemberExpr && !IMemberExpr->getExprLoc().isInvalid()) {
+    llvm::SmallVector<ExprPrintingResult> Result;
+    Result.push_back({{"member access"}, IMemberExpr});
+    if (const auto *SubExpr = IMemberExpr->getBase();
+        SubExpr && !llvm::isa<DeclRefExpr>(SubExpr->IgnoreParenCasts())) {
+      Result.append(FormatSrcExprForSema(SubExpr));
+    }
+    return Result;
+  }
+
+  if (const auto *ICCExpr = llvm::dyn_cast<CXXConstructExpr>(PureExpr)) {
+    if (ICCExpr->getNumArgs() > 0) {
+      if (const auto *SubExpr = ICCExpr->getArg(0);
+          SubExpr && !llvm::isa<DeclRefExpr>(SubExpr->IgnoreParenCasts())) {
+        return FormatSrcExprForSema(SubExpr);
+      }
+    }
+  }
+  if (const auto *ITempExpr = llvm::dyn_cast<CXXBindTemporaryExpr>(PureExpr)) {
+    if (const auto *SubExpr = ITempExpr->getSubExpr();
+        SubExpr && !llvm::isa<DeclRefExpr>(SubExpr->IgnoreParenCasts())) {
+      return FormatSrcExprForSema(SubExpr);
+    }
+  }
+
+  return {};
+}
+} // namespace clang::lifetimes
+
 namespace clang::lifetimes::internal {
 
 std::optional<llvm::SmallVector<AssignmentPair>>
-getAliasList(const AssignmentQueryContext &Context, const UseFact *UF,
-             const LoanID End, const bool InOneBlock) {
-  const CFGBlock *IssueBlock =
+getAliasList(const AssignmentQueryContext &Context, const Fact *CausingFact,
+             const LoanID End, const Expr *IssueExpr) {
+  const auto *UF = llvm::dyn_cast<UseFact>(CausingFact);
+  const CFGBlock *StartBlock =
       Context.ADC.getCFGStmtMap()->getBlock(UF->getUseExpr());
-  assert(IssueBlock && "Searching CFGBlock failed");
+  assert(StartBlock && "Searching CFGBlock failed");
+  const CFGBlock *EndBlock = Context.ADC.getCFGStmtMap()->getBlock(IssueExpr);
+  assert(EndBlock && "Searching CFGBlock failed");
 
   for (const OriginList *Cur = UF->getUsedOrigins(); Cur;
        Cur = Cur->peelOuterOrigin()) {
     auto TargetOID = Cur->getOuterOriginID();
-    if (InOneBlock) {
+    if (StartBlock == EndBlock) {
       AliasAssignmentSearchResult Result =
-          getAliasListCore(Context, IssueBlock, End, &TargetOID);
+          getAliasListCore(Context, StartBlock, End, &TargetOID);
       if (!Result.Payload.empty())
         return Result.Payload;
     } else {
       auto Result =
-          getAliasListInMultiBlock(Context, IssueBlock, End, &TargetOID);
+          getAliasListInMultiBlock(Context, StartBlock, End, &TargetOID);
       if (Result.has_value())
         return Result.value();
     }
diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
index 023496a75fc7b..9e0c2e1ce3e67 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -249,17 +249,13 @@ class LifetimeChecker {
           // Scope-based expiry (use-after-scope).
           const struct AssignmentQueryContext Context = {
               LoanPropagation, MovedLoans, LiveOrigins, FactMgr, ADC};
-          const CFGStmtMap *CurrCFGStmtMap = ADC.getCFGStmtMap();
-          const auto AliasExprs =
-              getAliasList(Context, UF, LID,
-                           CurrCFGStmtMap->getBlock(UF->getUseExpr()) ==
-                               CurrCFGStmtMap->getBlock(IssueExpr));
+          const auto AliasExprs = getAliasList(Context, UF, LID, IssueExpr);
           if (!AliasExprs.has_value()) {
             llvm::dbgs() << "Search variable assignment chain failed\n";
           }
 
           SemaHelper->reportUseAfterFree(IssueExpr, UF->getUseExpr(), MovedExpr,
-                                         AliasExprs.value_or({}), ExpiryLoc);
+                                         AliasExprs, ExpiryLoc);
         }
       } else if (const auto *OEF =
                      CausingFact.dyn_cast<const OriginEscapesFact *>()) {
diff --git a/clang/lib/Sema/SemaLifetimeSafety.h b/clang/lib/Sema/SemaLifetimeSafety.h
index 5c564ea603089..2c3f3252d7b28 100644
--- a/clang/lib/Sema/SemaLifetimeSafety.h
+++ b/clang/lib/Sema/SemaLifetimeSafety.h
@@ -38,15 +38,47 @@ inline bool IsLifetimeSafetyDiagnosticEnabled(Sema &S, const Decl *D) {
                           D->getBeginLoc());
 }
 
+inline void reportAssignmentImpl(Sema &S, const Expr *IssueExpr,
+                                 const ValueDecl *LHS, const Expr *RHS,
+                                 const SourceLocation LHSExploc) {
+  const auto [IssueMsg, _] = FormatIssueExprForSema(IssueExpr);
+  const auto SrcMsgList = FormatSrcExprForSema(RHS);
+  if (SrcMsgList.size() == 1 &&
+      llvm::isa<DeclRefExpr>(SrcMsgList[0].CurrExpr)) {
+    S.Diag(LHSExploc, diag::note_lifetime_safety_note_alias_chain)
+        << FormatValueDeclForSema(LHS) << IssueMsg;
+  } else {
+    for (const auto &SrcMsg : llvm::reverse(SrcMsgList))
+      S.Diag(RHS->getBeginLoc(), diag::note_lifetime_safety_note_alias_chain)
+          << SrcMsg.CurrExpr->getSourceRange() << SrcMsg.Value << IssueMsg;
+    S.Diag(LHSExploc, diag::note_lifetime_safety_note_alias_chain)
+        << FormatValueDeclForSema(LHS) << IssueMsg;
+  }
+}
+
+inline void reportAssignment(Sema &S, const Expr *IssueExpr,
+                             const OriginDestExpr &LHS, const Expr *RHS) {
+  if (!LHS || !RHS) {
+    return;
+  }
+
+  if (const DeclRefExpr *LDExpr = llvm::dyn_cast<const DeclRefExpr *>(LHS)) {
+    reportAssignmentImpl(S, IssueExpr, LDExpr->getDecl(), RHS,
+                         LDExpr->getExprLoc());
+  } else if (const ValueDecl *LVDecl = llvm::dyn_cast<const ValueDecl *>(LHS)) {
+    reportAssignmentImpl(S, IssueExpr, LVDecl, RHS, LVDecl->getLocation());
+  }
+}
+
 class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper {
 
 public:
   LifetimeSafetySemaHelperImpl(Sema &S) : S(S) {}
 
-  void reportUseAfterFree(const Expr *IssueExpr, const Expr *UseExpr,
-                          const Expr *MovedExpr,
-                          const llvm::SmallVector<AssignmentPair> AliasList,
-                          SourceLocation FreeLoc) override {
+  void reportUseAfterFree(
+      const Expr *IssueExpr, const Expr *UseExpr, const Expr *MovedExpr,
+      const std::optional<llvm::SmallVector<AssignmentPair>> AliasList,
+      SourceLocation FreeLoc) override {
     S.Diag(IssueExpr->getExprLoc(),
            MovedExpr ? diag::warn_lifetime_safety_use_after_scope_moved
                      : diag::warn_lifetime_safety_use_after_scope)
@@ -56,50 +88,9 @@ class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper {
           << MovedExpr->getSourceRange();
     S.Diag(FreeLoc, diag::note_lifetime_safety_destroyed_here);
 
-    for (auto AliasStmt = AliasList.rbegin(); AliasStmt != AliasList.rend();
-         ++AliasStmt) {
-      if (const auto *CurrDeclExpr =
-              llvm::dyn_cast<const DeclRefExpr *>((*AliasStmt).first)) {
-        S.Diag(CurrDeclExpr->getExprLoc(),
-               diag::note_lifetime_safety_note_alias_chain)
-            << (*AliasStmt).second->getNameAsString()
-            << CurrDeclExpr->getDecl()->getNameAsString();
-      } else if (const auto *CurrDeclExpr =
-                     llvm::dyn_cast<const CXXTemporaryObjectExpr *>(
-                         (*AliasStmt).first)) {
-        S.Diag(CurrDeclExpr->getExprLoc(),
-               diag::note_lifetime_safety_note_alias_chain)
-            << (*AliasStmt).second->getNameAsString()
-            << CurrDeclExpr->getConstructor()->getNameAsString() + "()";
-      } else if (const auto *CurrCallExpr =
-                     llvm::dyn_cast<const CallExpr *>((*AliasStmt).first)) {
-        std::string OutStr;
-        llvm::raw_string_ostream OutStream(OutStr);
-        LangOptions Lo;
-        PrintingPolicy Policy(Lo);
-
-        if (const Expr *Callee = CurrCallExpr->getCallee()) {
-          Callee->IgnoreParenCasts()->printPretty(OutStream, nullptr, Policy);
-        }
-
-        OutStream << "(";
-        for (size_t i = 0; i < CurrCallExpr->getNumArgs(); ++i) {
-          const Expr *CurrArg = CurrCallExpr->getArg(i);
-          if (CurrArg) {
-            CurrArg->printPretty(OutStream, nullptr, Policy);
-          }
-
-          if (i < CurrCallExpr->getNumArgs() - 1) {
-            OutStream << ", ";
-          }
-        }
-        OutStream << ")";
-
-        S.Diag(CurrCallExpr->getExprLoc(),
-               diag::note_lifetime_safety_note_alias_chain)
-            << (*AliasStmt).second->getNameAsString() << OutStream.str();
-      }
-    }
+    if (AliasList.has_value())
+      for (const auto &AliasStmt : llvm::reverse(AliasList.value()))
+        reportAssignment(S, IssueExpr, AliasStmt.first, AliasStmt.second);
 
     S.Diag(UseExpr->getExprLoc(), diag::note_lifetime_safety_used_here)
         << UseExpr->getSourceRange();
diff --git a/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp b/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
index f0c7306d124a5..201a0797efdb4 100644
--- a/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
+++ b/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
@@ -78,6 +78,8 @@ struct Y {
 
 void dangligGslPtrFromTemporary() {
   MyIntPointer p = Y{}.a; // cfg-warning {{object whose reference is captured does not live long enough}} \
+                          // cfg-note {{member access aliases the storage of the temporary}} \
+                          // cfg-note {{variable 'p' aliases the storage of the temporary}} \
                           // cfg-note {{destroyed here}}
   (void)p;                // cfg-note {{later used here}}
 }
@@ -148,15 +150,15 @@ MyLongPointerFromConversion global2;
 void initLocalGslPtrWithTempOwner() {
   MyIntPointer p = MyIntOwner{}; // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}} \
                                  // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}} \
-                                 // cfg-note {{variable `p` is now an alias of `MyIntOwner()`}}
+                                 // cfg-note {{variable 'p' aliases the storage of the temporary}}
   use(p);                        // cfg-note {{later used here}}
 
   MyIntPointer pp = p = MyIntOwner{}; // expected-warning {{object backing the pointer 'p' will be}} \
                                       // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}} \
-                                      // cfg-note {{variable `p` is now an alias of `MyIntOwner()`}}
+                                      // cfg-note {{variable 'p' aliases the storage of the temporary}}
   use(p, pp);                         // cfg-note {{later used here}}
 
-  p = MyIntOwner{}; // expected-warning {{object backing the pointer 'p' }} cfg-note {{variable `p` is now an alias of `MyIntOwner()`}} \
+  p = MyIntOwner{}; // expected-warning {{object backing the pointer 'p' }} cfg-note {{variable 'p' aliases the storage of the temporary}} \
                     // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
   use(p);           // cfg-note {{later used here}}
 
@@ -164,20 +166,20 @@ void initLocalGslPtrWithTempOwner() {
   use(p, pp);
 
   global = MyIntOwner{}; // expected-warning {{object backing the pointer 'global' }} \
-                         // cfg-note {{variable `global` is now an alias of `MyIntOwner()`}} \
+                         // cfg-note {{variable 'global' aliases the storage of the temporary}} \
                          // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
   use(global);           // cfg-note {{later used here}}
 
   MyLongPointerFromConversion p2 = MyLongOwnerWithConversion{}; // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}} \
                                                                 // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}} \
-                                                                // cfg-note {{variable `p2` is now an alias of `MyLongOwnerWithConversion{}.operator MyLongPointerFromConversion()`}}
+                                                                // cfg-note {{variable 'p2' aliases the storage of the temporary}}
   use(p2);                                                      // cfg-note {{later used here}}
 
   p2 = MyLongOwnerWithConversion{}; // expected-warning {{object backing the pointer 'p2' }} \
-                                    // cfg-note {{variable `p2` is now an alias of `MyLongOwnerWithConversion{}.operator MyLongPointerFromConversion()`}} \
+                                    // cfg-note {{variable 'p2' aliases the storage of the temporary}} \
                                     // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
   global2 = MyLongOwnerWithConversion{};  // expected-warning {{object backing the pointer 'global2' }} \
-                                          // cfg-note {{variable `global2` is now an alias of `MyLongOwnerWithConversion{}.operator MyLongPointerFromConversion()`}} \
+                                          // cfg-note {{variable 'global2' aliases the storage of the temporary}} \
                                           // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
   use(global2, p2);                       // cfg-note 2 {{later used here}}
 }
@@ -191,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-note {{variable `it` is now an alias of `std::vector<int>().begin()`}} \
+                                                              // cfg-note {{function call result aliases the storage of the temporary}} \
+                                                              // cfg-note {{variable 'it' aliases the storage of the temporary}} \
                                                               // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
   (void)it; // cfg-note {{later used here}}
 }
@@ -240,13 +243,15 @@ 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-note {{variable `c1` is now an alias of `std::vector<std::string>().at(0).operator basic_string_view()`}} \
+                                                          // cfg-note {{function call result aliases the storage of the temporary}} \
+                                                          // cfg-note {{variable 'c1' aliases the storage of the temporary}} \
                                                           // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
   use(c1);                                                // cfg-note {{later used here}}
 
   c1 = std::vector<std::string>().at(0); // expected-warning {{object backing the pointer}} \
                                          // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}} \
-                                         // cfg-note {{variable `c1` is now an alias of `std::vector<std::string>().at(0).operator basic_string_view()`}}
+                                         // cfg-note {{function call result aliases the storage of the temporary}} \
+                                         // cfg-note {{variable 'c1' aliases the storage of the temporary}}
   use(c1);                               // cfg-note {{later used here}}
 
   // no warning on constructing from gsl-pointer
@@ -307,28 +312,34 @@ 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-note {{variable `r` is now an alias of `operator*(std::optional<int>())`}} \
+                                            // cfg-note {{expression aliases the storage of the temporary}} \
+                                            // cfg-note {{variable 'r' aliases the storage of the temporary}} \
                                             // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
   // 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-note {{variable `r2` is now an alias of `operator*(std::optional<int>(5))`}} \
+                                            // cfg-note {{expression aliases the storage of the temporary}} \
+                                            // cfg-note {{variable 'r2' aliases the storage of the temporary}} \
                                             // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
 
   // 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-note {{variable `r3` is now an alias of `std::optional<int>(5).value()`}} \
+                                            // cfg-note {{function call result aliases the storage of the temporary}} \
+                                            // cfg-note {{variable 'r3' aliases the storage of the temporary}} \
                                             // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
 
   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-note {{variable `r4` is now an alias of `std::vector<int>().at(3)`}} \
+                                            // cfg-note {{function call result aliases the storage of the temporary}} \
+                                            // cfg-note {{variable 'r4' aliases the storage of the temporary}} \
                                             // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
   int &&r5 = std::vector<int>().at(3);      // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}} \
-                                            // cfg-note {{variable `r5` is now an alias of `std::vector<int>().at(3)`}} \
+                                            // cfg-note {{function call result aliases the storage of the temporary}} \
+                                            // cfg-note {{variable 'r5' aliases the storage of the temporary}} \
                                             // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
   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-note {{variable `sv` is now an alias of `* getTempOptStr().operator basic_string_view()`}} \
+                                           // cfg-note {{expression aliases the storage of the temporary}} \
+                                           // cfg-note {{variable 'sv' aliases the storage of the temporary}} \
                                            // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
   use(sv);                                 // cfg-note {{later used here}}
 }
@@ -340,8 +351,10 @@ 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-note {{variable `__range1` is now an alias of `operator*(getTempOptVec())`}} \
-                                  // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}} cfg-note {{later used here}}
+                                  // cfg-note {{expression aliases the storage of the temporary}} \
+                                  // cfg-note {{variable '__range1' aliases the storage of the temporary}} \
+                                  // cfg-warning {{object whose reference is captured does not live long enough}} \
+                                  // cfg-note {{destroyed here}} cfg-note {{later used here}}
     ;
 }
 
@@ -403,7 +416,7 @@ void handleGslPtrInitsThroughReference2() {
 void handleTernaryOperator(bool cond) {
     std::basic_string<char> def;
     std::basic_string_view<char> v = cond ? def : ""; // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}} \
-                                                      // cfg-note {{variable `v` is now an alias of `cond ? def : "".operator basic_string_view()`}} \
+                                                      // cfg-note {{variable 'v' aliases the storage of the temporary}} \
                                                       // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
     use(v); // cfg-note {{later used here}}
 }
@@ -412,12 +425,13 @@ std::string operator+(std::string_view s1, std::string_view s2);
 void danglingStringviewAssignment(std::string_view a1, std::string_view a2) {
   a1 = std::string(); // expected-warning {{object backing}} \
                       // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}} \
-                      // cfg-note {{variable `a1` is now an alias of `std::string().operator basic_string_view()`}}
+                      // cfg-note {{variable 'a1' aliases the storage of the temporary}}
   use(a1);            // cfg-note {{later used here}}
 
   a2 = a1 + a1; // expected-warning {{object backing}} \
                 // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}} \
-                // cfg-note {{variable `a2` is now an alias of `a1 + a1.operator basic_string_view()`}}
+                // cfg-note {{expression aliases the storage of the temporary}} \
+                // cfg-note {{variable 'a2' aliases the storage of the temporary}}
   use(a2);      // cfg-note {{later used here}}
 }
 
@@ -613,6 +627,8 @@ std::string StrCat(std::string_view, std::string_view);
 void test1() {
   UrlAnalyzed url(StrCat("abc", "bcd")); // expected-warning {{object backing the pointer will be destroyed}} \
                                          // cfg-warning {{object whose reference is captured does not live long enough}} \
+                                         // cfg-note {{function call result aliases the storage of the temporary}} \
+                                         // cfg-note {{variable 'url' aliases the storage of the temporary}} \
                                          // cfg-note {{destroyed here}}
   use(url);                              // cfg-note {{later used here}}
 }
@@ -622,7 +638,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 {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}} \
-                                                                  // cfg-note {{variable `svjkk1` is now an alias of `ReturnStringView(StrCat("bar", "x"))`}}
+                                                                  // cfg-note {{function call result aliases the storage of the temporary}} \
+                                                                  // cfg-note {{variable 'svjkk1' aliases the storage of the temporary}}
   use(svjkk1);                                                    // cfg-note {{later used here}}
 }
 } // namespace GH100549
@@ -857,7 +874,8 @@ namespace GH118064{
 void test() {
   auto y = std::set<int>{}.begin(); // expected-warning {{object backing the pointer}} \
   // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}} \
-  // cfg-note {{variable `y` is now an alias of `std::set<int>{}.begin()`}}
+  // cfg-note {{function call result aliases the storage of the temporary}} \
+  // cfg-note {{variable 'y' aliases the storage of the temporary}}
   use(y); // cfg-note {{later used here}}
 }
 } // namespace GH118064
@@ -873,11 +891,13 @@ 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 {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}} \
-                                            // cfg-note {{variable `t1` is now an alias of `Ref(std::string()).operator basic_string_view()`}}
+                                            // cfg-note {{function call result aliases the storage of the temporary}} \
+                                            // cfg-note {{variable 't1' aliases the storage of the temporary}}
   use(t1);                                  // cfg-note {{later used here}}
   t1 = Ref(std::string()); // expected-warning {{object backing}} \
                            // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}} \
-                           // cfg-note {{variable `t1` is now an alias of `Ref(std::string()).operator basic_string_view()`}}
+                           // cfg-note {{function call result aliases the storage of the temporary}} \
+                           // cfg-note {{variable 't1' aliases the storage of the temporary}}
   use(t1);                 // cfg-note {{later used here}}
   return Ref(std::string()); // expected-warning {{returning address}} \
                              // cfg-warning {{address of stack memory is returned later}} cfg-note {{returned here}}
@@ -886,11 +906,13 @@ std::string_view test1_1() {
 std::string_view test1_2() {
   std::string_view t2 = TakeSv(std::string()); // expected-warning {{object backing}} \
                                             // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}} \
-                                            // cfg-note {{variable `t2` is now an alias of `TakeSv(std::string())`}}
+                                            // cfg-note {{function call result aliases the storage of the temporary}} \
+                                            // cfg-note {{variable 't2' aliases the storage of the temporary}}
   use(t2);                                  // cfg-note {{later used here}}
   t2 = TakeSv(std::string()); // expected-warning {{object backing}} \
                               // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}} \
-                              // cfg-note {{variable `t2` is now an alias of `TakeSv(std::string())`}}
+                              // cfg-note {{function call result aliases the storage of the temporary}} \
+                              // cfg-note {{variable 't2' aliases the storage of the temporary}}
   use(t2);                    // cfg-note {{later used here}}
 
   return TakeSv(std::string()); // expected-warning {{returning address}} \
@@ -899,11 +921,13 @@ std::string_view test1_2() {
 
 std::string_view test1_3() {
   std::string_view t3 = TakeStrRef(std::string()); // expected-warning {{temporary}} \
-                                                   // cfg-note {{variable `t3` is now an alias of `TakeStrRef(std::string())`}} \
+                                                   // cfg-note {{function call result aliases the storage of the temporary}} \
+                                                   // cfg-note {{variable 't3' aliases the storage of the temporary}} \
                                                    // cfg-warning {{object whose reference is captured 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-note {{variable `t3` is now an alias of `TakeStrRef(std::string())`}} \
+                                  // cfg-note {{function call result aliases the storage of the temporary}} \
+                                  // cfg-note {{variable 't3' aliases the storage of the temporary}} \
                                   // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
   use(t3);                        // cfg-note {{later used here}}
   return TakeStrRef(std::string()); // expected-warning {{returning address}} \
@@ -926,12 +950,14 @@ 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-note {{variable `t1` is now an alias of `Foo<std::string>().get().operator basic_string_view()`}} \
+                                                  // cfg-note {{function call result aliases the storage of the temporary}} \
+                                                  // cfg-note {{variable 't1' aliases the storage of the temporary}} \
                                                   // cfg-warning {{object whose reference is captured 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 {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}} \
-                                 // cfg-note {{variable `t1` is now an alias of `Foo<std::string>().get().operator basic_string_view()`}}
+                                 // cfg-note {{function call result aliases the storage of the temporary}} \
+                                 // cfg-note {{variable 't1' aliases the storage of the temporary}}
   use(t1);                       // cfg-note {{later used here}}
   return r1.get(); // expected-warning {{address of stack}} \
                    // cfg-warning {{address of stack memory is returned later}} cfg-note {{returned here}}
@@ -1052,11 +1078,16 @@ void operator_star_arrow_reference() {
 
   auto temporary = []() { return std::vector<std::string>{{"1"}}; };
   const char* x = temporary().begin()->data();    // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}} \
-                                                  // cfg-note {{variable `x` is now an alias of `temporary().begin()->data()`}}
+                                                  // cfg-note {{expression aliases the storage of the temporary}} \
+                                                  // cfg-note {{function call result aliases the storage of the temporary}} \
+                                                  // cfg-note {{variable 'x' aliases the storage of the temporary}}
   const char* y = (*temporary().begin()).data();  // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}} \
-                                                  // cfg-note {{variable `y` is now an alias of `(* temporary().begin()).data()`}}
+                                                  // cfg-note {{expression aliases the storage of the temporary}} \
+                                                  // cfg-note {{function call result aliases the storage of the temporary}} \
+                                                  // cfg-note {{variable 'y' aliases the storage of the temporary}}
   const std::string& z = (*temporary().begin());  // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}} \
-                                                  // cfg-note {{variable `z` is now an alias of `operator*(temporary().begin())`}}
+                                                  // cfg-note {{expression aliases the storage of the temporary}} \
+                                                  // cfg-note {{variable 'z' aliases the storage of the temporary}}
 
   use(p, q, r, x, y, z); // cfg-note 3 {{later used here}}
 }
@@ -1069,11 +1100,18 @@ void operator_star_arrow_of_iterators_false_positive_no_cfg_analysis() {
 
   auto temporary = []() { return std::vector<std::pair<int, std::string>>{{1, "1"}}; };
   const char* x = temporary().begin()->second.data();   // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}} \
-                                                        // cfg-note {{variable `x` is now an alias of `temporary().begin()->second.data()`}}
+                                                        // cfg-note {{expression aliases the storage of the temporary}} \
+                                                        // cfg-note {{member access aliases the storage of the temporary}} \
+                                                        // cfg-note {{function call result aliases the storage of the temporary}} \
+                                                        // cfg-note {{variable 'x' aliases the storage of the temporary}}
   const char* y = (*temporary().begin()).second.data(); // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}} \
-                                                        // cfg-note {{variable `y` is now an alias of `(* temporary().begin()).second.data()`}}
+                                                        // cfg-note {{expression aliases the storage of the temporary}} \
+                                                        // cfg-note {{member access aliases the storage of the temporary}} \
+                                                        // cfg-note {{function call result aliases the storage of the temporary}} \
+                                                        // cfg-note {{variable 'y' aliases the storage of the temporary}}
   const std::string& z = (*temporary().begin()).second; // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}} \
-                                                        // cfg-note {{variable `z` is now an alias of `operator*(temporary().begin())`}}
+                                                        // cfg-note {{expression aliases the storage of the temporary}} \
+                                                        // cfg-note {{variable 'z' aliases the storage of the temporary}}
 
   use(p, q, r, x, y, z); // cfg-note 3 {{later used here}}
 }
@@ -1123,20 +1161,23 @@ 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-note {{variable `k2` is now an alias of `S().s.operator basic_string_view()`}} \
+                               // cfg-note {{variable 'k2' aliases the storage of the temporary}} \
                                // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
 
   std::string_view k3 = Q().get()->sv; // OK
   std::string_view k4  = Q().get()->s; // expected-warning {{object backing the pointer will}} \
                                        // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}} \
-                                       // cfg-note {{variable `k4` is now an alias of `Q().get()->s.operator basic_string_view()`}}
+                                       // cfg-note {{function call result aliases the storage of the temporary}} \
+                                       // cfg-note {{variable 'k4' aliases the storage of the temporary}}
 
 
   std::string_view lb1 = foo(S().s); // expected-warning {{object backing the pointer will}} \
-                                     // cfg-note {{variable `lb1` is now an alias of `foo(S().s)`}} \
+                                     // cfg-note {{function call result aliases the storage of the temporary}} \
+                                     // cfg-note {{variable 'lb1' aliases the storage of the temporary}} \
                                      // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
   std::string_view lb2 = foo(Q().get()->s); // expected-warning {{object backing the pointer will}} \
-                                            // cfg-note {{variable `lb2` is now an alias of `foo(Q().get()->s)`}} \
+                                            // cfg-note {{function call result aliases the storage of the temporary}} \
+                                            // cfg-note {{variable 'lb2' aliases the storage of the temporary}} \
                                             // cfg-warning {{object whose reference is captured does not live long enough}} cfg-note {{destroyed here}}
 
   use(k1, k2, k3, k4, lb1, lb2);  // cfg-note 4 {{later used here}}
diff --git a/clang/test/Sema/warn-lifetime-safety-cfg-bailout.cpp b/clang/test/Sema/warn-lifetime-safety-cfg-bailout.cpp
index 51cd8a6e5b349..2b047878b21cb 100644
--- a/clang/test/Sema/warn-lifetime-safety-cfg-bailout.cpp
+++ b/clang/test/Sema/warn-lifetime-safety-cfg-bailout.cpp
@@ -27,7 +27,8 @@ void single_block_cfg() {
   MyObj* p;
   {
     MyObj s;
-    p = &s;     // bailout-warning {{object whose reference is captured does not live long enough}} bailout-note {{variable `p` is now an alias of `s`}}
+    p = &s;     // bailout-warning {{object whose reference is captured does not live long enough}} \
+                // bailout-note {{variable 'p' aliases the storage of variable 's'}}
   }             // bailout-note {{destroyed here}}
   (void)*p;     // bailout-note {{later used here}}
 }
@@ -39,7 +40,8 @@ void multiple_block_cfg() {
   {
     if (a > 5) {
       MyObj s;
-      p = &s;    // nobailout-warning {{object whose reference is captured does not live long enough}} nobailout-note {{variable `p` is now an alias of `s`}}
+      p = &s;    // nobailout-warning {{object whose reference is captured does not live long enough}} \
+                 // nobailout-note {{variable 'p' aliases the storage of variable 's'}}
     } else {     // nobailout-note {{destroyed here}}
       p = &safe;
     }     
diff --git a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
index dcf3b7719ce1c..125310fdead8c 100644
--- a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
+++ b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
@@ -221,21 +221,24 @@ View return_view_field(const ViewProvider& v) {    // expected-warning {{paramet
 void test_get_on_temporary_pointer() {
   const ReturnsSelf* s_ref = &ReturnsSelf().get(); // expected-warning {{object whose reference is captured does not live long enough}}.
                                                    // expected-note at -1 {{destroyed here}}.
-                                                   // expected-note at -2 {{variable `s_ref` is now an alias of `ReturnsSelf().get()`}}
+                                                   // expected-note at -2 {{function call result aliases the storage of the temporary}}
+                                                   // expected-note at -3 {{variable 's_ref' aliases the storage of the temporary}}
   (void)s_ref;                                     // expected-note {{later used here}}
 }
 
 void test_get_on_temporary_ref() {
   const ReturnsSelf& s_ref = ReturnsSelf().get();  // expected-warning {{object whose reference is captured does not live long enough}}.
                                                    // expected-note at -1 {{destroyed here}}.
-                                                   // expected-note at -2 {{variable `s_ref` is now an alias of `ReturnsSelf().get()`}}
+                                                   // expected-note at -2 {{function call result aliases the storage of the temporary}}
+                                                   // expected-note at -3 {{variable 's_ref' aliases the storage of the temporary}}
   (void)s_ref;                                     // expected-note {{later used here}}
 }
 
 void test_getView_on_temporary() {
   View sv = ViewProvider{1}.getView();      // expected-warning {{object whose reference is captured does not live long enough}}.
                                             // expected-note at -1 {{destroyed here}}.
-                                            // expected-note at -2 {{variable `sv` is now an alias of `ViewProvider{1}.getView()`}}
+                                            // expected-note at -2 {{function call result aliases the storage of the temporary}}
+                                            // expected-note at -3 {{variable 'sv' aliases the storage of the temporary}}
   (void)sv;                                 // expected-note {{later used here}}
 }
 
diff --git a/clang/test/Sema/warn-lifetime-safety.cpp b/clang/test/Sema/warn-lifetime-safety.cpp
index 8b62f0779a92d..3df319836c7f7 100644
--- a/clang/test/Sema/warn-lifetime-safety.cpp
+++ b/clang/test/Sema/warn-lifetime-safety.cpp
@@ -54,7 +54,7 @@ void simple_case() {
   {
     MyObj s;
     p = &s;     // expected-warning {{object whose reference is captured does not live long enough}} \
-                // expected-note {{variable `p` is now an alias of `s`}}
+                // expected-note {{variable 'p' aliases the storage of variable 's'}}
   }             // expected-note {{destroyed here}}
   (void)*p;     // expected-note {{later used here}}
 }
@@ -64,7 +64,7 @@ void simple_case_gsl() {
   {
     MyObj s;
     v = s;      // expected-warning {{object whose reference is captured does not live long enough}} \
-                // expected-note {{variable `v` is now an alias of `s`}}
+                // expected-note {{variable 'v' aliases the storage of variable 's'}}
   }             // expected-note {{destroyed here}}
   v.use();      // expected-note {{later used here}}
 }
@@ -93,8 +93,8 @@ void pointer_chain() {
   {
     MyObj s;
     p = &s;     // expected-warning {{does not live long enough}} \
-                // expected-note {{variable `p` is now an alias of `s`}}
-    q = p;      // expected-note {{variable `q` is now an alias of `p`}}
+                // expected-note {{variable 'p' aliases the storage of variable 's'}}
+    q = p;      // expected-note {{variable 'q' aliases the storage of variable 's'}}
   }             // expected-note {{destroyed here}}
   (void)*q;     // expected-note {{later used here}}
 }
@@ -104,8 +104,8 @@ void propagation_gsl() {
   {
     MyObj s;
     v1 = s;     // expected-warning {{object whose reference is captured does not live long enough}} \
-                // expected-note {{variable `v1` is now an alias of `s`}}
-    v2 = v1;    // expected-note {{`v2` is now an alias of `v1`}}
+                // expected-note {{variable 'v1' aliases the storage of variable 's'}}
+    v2 = v1;    // expected-note {{variable 'v2' aliases the storage of variable 's'}}
   }             // expected-note {{destroyed here}}
   v2.use();     // expected-note {{later used here}}
 }
@@ -115,7 +115,7 @@ void multiple_uses_one_warning() {
   {
     MyObj s;
     p = &s;     // expected-warning {{does not live long enough}} \
-                // expected-note {{variable `p` is now an alias of `s`}}
+                // expected-note {{variable 'p' aliases the storage of variable 's'}}
   }             // expected-note {{destroyed here}}
   (void)*p;     // expected-note {{later used here}}
   // No second warning for the same loan.
@@ -129,11 +129,11 @@ void multiple_pointers() {
   {
     MyObj s;
     p = &s;     // expected-warning {{does not live long enough}} \
-                // expected-note {{variable `p` is now an alias of `s`}}
+                // expected-note {{variable 'p' aliases the storage of variable 's'}}
     q = &s;     // expected-warning {{does not live long enough}} \
-                // expected-note {{variable `q` is now an alias of `s`}}
+                // expected-note {{variable 'q' aliases the storage of variable 's'}}
     r = &s;     // expected-warning {{does not live long enough}} \
-                // expected-note {{variable `r` is now an alias of `s`}}
+                // expected-note {{variable 'r' aliases the storage of variable 's'}}
   }             // expected-note 3 {{destroyed here}}
   (void)*p;     // expected-note {{later used here}}
   (void)*q;     // expected-note {{later used here}}
@@ -145,12 +145,12 @@ void single_pointer_multiple_loans(bool cond) {
   if (cond){
     MyObj s;
     p = &s;     // expected-warning {{does not live long enough}} \
-                // expected-note {{`p` is now an alias of `s`}}
+                // expected-note {{variable 'p' aliases the storage of variable 's'}}
   }             // expected-note {{destroyed here}}
   else {
     MyObj t;
     p = &t;     // expected-warning {{does not live long enough}} \
-                // expected-note {{variable `p` is now an alias of `t`}}
+                // expected-note {{variable 'p' aliases the storage of variable 't'}}
   }             // expected-note {{destroyed here}}
   (void)*p;     // expected-note 2  {{later used here}}
 }
@@ -160,12 +160,12 @@ void single_pointer_multiple_loans_gsl(bool cond) {
   if (cond){
     MyObj s;
     v = s;      // expected-warning {{object whose reference is captured does not live long enough}} \
-                // expected-note {{variable `v` is now an alias of `s`}}
+                // expected-note {{variable 'v' aliases the storage of variable 's'}}
   }             // expected-note {{destroyed here}}
   else {
     MyObj t;
     v = t;      // expected-warning {{object whose reference is captured does not live long enough}} \
-                // expected-note {{variable `v` is now an alias of `t`}}
+                // expected-note {{variable 'v' aliases the storage of variable 't'}}
   }             // expected-note {{destroyed here}}
   v.use();      // expected-note 2 {{later used here}}
 }
@@ -176,7 +176,7 @@ void if_branch(bool cond) {
   if (cond) {
     MyObj temp;
     p = &temp;  // expected-warning {{object whose reference is captured does not live long enough}} \
-                // expected-note {{variable `p` is now an alias of `temp`}}
+                // expected-note {{variable 'p' aliases the storage of variable 'temp'}}
   }             // expected-note {{destroyed here}}
   (void)*p;     // expected-note {{later used here}}
 }
@@ -187,7 +187,7 @@ void if_branch_potential(bool cond) {
   if (cond) {
     MyObj temp;
     p = &temp;  // expected-warning {{object whose reference is captured does not live long enough}} \
-                // expected-note {{variable `p` is now an alias of `temp`}}
+                // expected-note {{variable 'p' aliases the storage of variable 'temp'}}
   }             // expected-note {{destroyed here}}
   if (!cond)
     (void)*p;   // expected-note {{later used here}}
@@ -201,7 +201,7 @@ void if_branch_gsl(bool cond) {
   if (cond) {
     MyObj temp;
     v = temp;   // expected-warning {{object whose reference is captured does not live long enough}} \
-                // expected-note {{variable `v` is now an alias of `temp`}}
+                // expected-note {{variable 'v' aliases the storage of variable 'temp'}}
   }             // expected-note {{destroyed here}}
   v.use();      // expected-note {{later used here}}
 }
@@ -215,10 +215,10 @@ void potential_together(bool cond) {
     MyObj s;
     if (cond)
       p_definite = &s;  // expected-warning {{does not live long enough}} \
-                        // expected-note {{variable `p_definite` is now an alias of `s`}}
+                        // expected-note {{variable 'p_definite' aliases the storage of variable 's'}}
     if (cond)
       p_maybe = &s;     // expected-warning {{does not live long enough}} \
-                        // expected-note {{variable `p_maybe` is now an alias of `s`}}
+                        // expected-note {{variable 'p_maybe' aliases the storage of variable 's'}}
   }                     // expected-note 2 {{destroyed here}}
   (void)*p_definite;    // expected-note {{later used here}}
   if (!cond)
@@ -232,8 +232,8 @@ void overrides_potential(bool cond) {
   {
     MyObj s;
     q = &s;       // expected-warning {{does not live long enough}} \
-                  // expected-note {{variable `q` is now an alias of `s`}}
-    p = q;        // expected-note {{variable `p` is now an alias of `q`}}
+                  // expected-note {{variable 'q' aliases the storage of variable 's'}}
+    p = q;        // expected-note {{variable 'p' aliases the storage of variable 's'}}
   }               // expected-note {{destroyed here}}
 
   if (cond) {
@@ -253,7 +253,7 @@ void due_to_conditional_killing(bool cond) {
   {
     MyObj s;
     q = &s;       // expected-warning {{does not live long enough}} \
-                  // expected-note {{variable `q` is now an alias of `s`}}
+                  // expected-note {{variable 'q' aliases the storage of variable 's'}}
   }               // expected-note {{destroyed here}}
   if (cond) {
     // 'q' is conditionally "rescued". 'p' is not.
@@ -267,7 +267,7 @@ void for_loop_use_after_loop_body(MyObj safe) {
   for (int i = 0; i < 1; ++i) {
     MyObj s;
     p = &s;     // expected-warning {{does not live long enough}} \
-                // expected-note {{variable `p` is now an alias of `s`}}
+                // expected-note {{variable 'p' aliases the storage of variable 's'}}
   }             // expected-note {{destroyed here}}
   (void)*p;     // expected-note {{later used here}}
 }
@@ -288,7 +288,7 @@ void for_loop_gsl() {
   for (int i = 0; i < 1; ++i) {
     MyObj s;
     v = s;      // expected-warning {{object whose reference is captured does not live long enough}} \
-                // expected-note {{variable `v` is now an alias of `s`}}
+                // expected-note {{variable 'v' aliases the storage of variable 's'}}
   }             // expected-note {{destroyed here}}
   v.use();      // expected-note {{later used here}}
 }
@@ -300,7 +300,7 @@ void for_loop_use_before_loop_body(MyObj safe) {
     (void)*p;   // expected-note {{later used here}}
     MyObj s;
     p = &s;     // expected-warning {{does not live long enough}} \
-                // expected-note {{variable `p` is now an alias of `s`}}
+                // expected-note {{variable 'p' aliases the storage of variable 's'}}
   }             // expected-note {{destroyed here}}
   (void)*p;
 }
@@ -312,7 +312,7 @@ void loop_with_break(bool cond) {
     if (cond) {
       MyObj temp;
       p = &temp; // expected-warning {{does not live long enough}} \
-                 // expected-note {{variable `p` is now an alias of `temp`}}
+                 // expected-note {{variable 'p' aliases the storage of variable 'temp'}}
       break;     // expected-note {{destroyed here}}
     }           
   } 
@@ -326,7 +326,7 @@ void loop_with_break_gsl(bool cond) {
     if (cond) {
       MyObj temp;
       v = temp;   // expected-warning {{object whose reference is captured does not live long enough}} \
-                  // expected-note {{variable `v` is now an alias of `temp`}}
+                  // expected-note {{variable 'v' aliases the storage of variable 'temp'}}
       break;      // expected-note {{destroyed here}}
     }
   }
@@ -341,7 +341,7 @@ void multiple_expiry_of_same_loan(bool cond) {
     MyObj unsafe;
     if (cond) {
       p = &unsafe; // expected-warning {{does not live long enough}} \
-                   // expected-note {{variable `p` is now an alias of `unsafe`}}
+                   // expected-note {{variable 'p' aliases the storage of variable 'unsafe'}}
       break;       // expected-note {{destroyed here}}
     }
   }
@@ -352,7 +352,7 @@ void multiple_expiry_of_same_loan(bool cond) {
     MyObj unsafe;
     if (cond) {
       p = &unsafe;    // expected-warning {{does not live long enough}} \
-                      // expected-note {{variable `p` is now an alias of `unsafe`}}
+                      // expected-note {{variable 'p' aliases the storage of variable 'unsafe'}}
       if (cond)
         break;        // expected-note {{destroyed here}}
     }
@@ -364,7 +364,7 @@ void multiple_expiry_of_same_loan(bool cond) {
     if (cond) {
       MyObj unsafe2;
       p = &unsafe2;   // expected-warning {{does not live long enough}} \
-                      // expected-note {{variable `p` is now an alias of `unsafe2`}}
+                      // expected-note {{variable 'p' aliases the storage of variable 'unsafe2'}}
       break;          // expected-note {{destroyed here}}
     }
   }
@@ -375,7 +375,7 @@ void multiple_expiry_of_same_loan(bool cond) {
     MyObj unsafe;
     if (cond)
       p = &unsafe;    // expected-warning {{does not live long enough}} \
-                      // expected-note {{variable `p` is now an alias of `unsafe`}}
+                      // expected-note {{variable 'p' aliases the storage of variable 'unsafe'}}
     if (cond)
       break;          // expected-note {{destroyed here}}
   }
@@ -389,7 +389,7 @@ void switch_potential(int mode) {
   case 1: {
     MyObj temp;
     p = &temp;  // expected-warning {{object whose reference is captured does not live long enough}} \
-                // expected-note {{variable `p` is now an alias of `temp`}}
+                // expected-note {{variable 'p' aliases the storage of variable 'temp'}}
     break;      // expected-note {{destroyed here}}
   }
   case 2: {
@@ -409,19 +409,19 @@ void switch_uaf(int mode) {
   case 1: {
     MyObj temp1;
     p = &temp1; // expected-warning {{does not live long enough}} \
-                // expected-note {{variable `p` is now an alias of `temp1`}}
+                // expected-note {{variable 'p' aliases the storage of variable 'temp1'}}
     break;      // expected-note {{destroyed here}}
   }
   case 2: {
     MyObj temp2;
     p = &temp2; // expected-warning {{does not live long enough}} \
-                // expected-note {{variable `p` is now an alias of `temp2`}}
+                // expected-note {{variable 'p' aliases the storage of variable 'temp2'}}
     break;      // expected-note {{destroyed here}}
   }
   default: {
     MyObj temp2;
     p = &temp2; // expected-warning {{does not live long enough}} \
-                // expected-note {{variable `p` is now an alias of `temp2`}}
+                // expected-note {{variable 'p' aliases the storage of variable 'temp2'}}
     break;      // expected-note {{destroyed here}}
   }
   }
@@ -434,19 +434,19 @@ void switch_gsl(int mode) {
   case 1: {
     MyObj temp1;
     v = temp1;  // expected-warning {{object whose reference is captured does not live long enough}} \
-                // expected-note {{variable `v` is now an alias of `temp1`}}
+                // expected-note {{variable 'v' aliases the storage of variable 'temp1'}}
     break;      // expected-note {{destroyed here}}
   }
   case 2: {
     MyObj temp2;
     v = temp2;  // expected-warning {{object whose reference is captured does not live long enough}} \
-                // expected-note {{variable `v` is now an alias of `temp2`}}
+                // expected-note {{variable 'v' aliases the storage of variable 'temp2'}}
     break;      // expected-note {{destroyed here}}
   }
   default: {
     MyObj temp3;
     v = temp3;  // expected-warning {{object whose reference is captured does not live long enough}} \
-                // expected-note {{variable `v` is now an alias of `temp3`}}
+                // expected-note {{variable 'v' aliases the storage of variable 'temp3'}}
     break;      // expected-note {{destroyed here}}
   }
   }
@@ -460,7 +460,7 @@ void loan_from_previous_iteration(MyObj safe, bool condition) {
   while (condition) {
     MyObj x;
     p = &x;     // expected-warning {{does not live long enough}} \
-                // expected-note {{variable `p` is now an alias of `x`}}
+                // expected-note {{variable 'p' aliases the storage of variable 'x'}}
 
     if (condition)
       q = p;
@@ -474,7 +474,7 @@ void trivial_int_uaf() {
   {
       int b = 1;
       a = &b;  // expected-warning {{object whose reference is captured does not live long enough}} \
-               // expected-note {{variable `a` is now an alias of `b`}}
+               // expected-note {{variable 'a' aliases the storage of variable 'b'}}
   }            // expected-note {{destroyed here}}
   (void)*a;    // expected-note {{later used here}}
 }
@@ -484,7 +484,7 @@ void trivial_class_uaf() {
   {
       TriviallyDestructedClass s;
       ptr = &s; // expected-warning {{object whose reference is captured does not live long enough}} \
-                // expected-note {{variable `ptr` is now an alias of `s`}}
+                // expected-note {{variable 'ptr' aliases the storage of variable 's'}}
   }             // expected-note {{destroyed here}}
   (void)ptr;    // expected-note {{later used here}}
 }
@@ -677,7 +677,7 @@ void test_view_pointer() {
   {
     View v;
     vp = &v;     // expected-warning {{object whose reference is captured does not live long enough}} \
-                 // expected-note {{variable `vp` is now an alias of `v`}}
+                 // expected-note {{variable 'vp' aliases the storage of variable 'v'}}
   }              // expected-note {{destroyed here}}
   vp->use();     // expected-note {{later used here}}
 }
@@ -687,7 +687,7 @@ void test_view_double_pointer() {
   {
     View* vp = nullptr;
     vpp = &vp;   // expected-warning {{object whose reference is captured does not live long enough}} \
-                 // expected-note {{variable `vpp` is now an alias of `vp`}}
+                 // expected-note {{variable 'vpp' aliases the storage of variable 'vp'}}
   }              // expected-note {{destroyed here}}
   (**vpp).use(); // expected-note {{later used here}}
 }
@@ -715,8 +715,9 @@ void test_lifetimebound_multi_level() {
     int* p = nullptr;
     int** pp = &p;
     int*** ppp = &pp; // expected-warning {{object whose reference is captured does not live long enough}} \
-                      // expected-note {{variable `ppp` is now an alias of `pp`}}
-    result = return_inner_ptr_addr(ppp); // expected-note {{variable `result` is now an alias of `return_inner_ptr_addr(ppp)`}}
+                      // expected-note {{variable 'ppp' aliases the storage of variable 'pp'}}
+    result = return_inner_ptr_addr(ppp); // expected-note {{function call result aliases the storage of variable 'pp'}} \
+                                         // expected-note {{variable 'result' aliases the storage of variable 'pp'}}
   }                   // expected-note {{destroyed here}}
   (void)**result;     // expected-note {{used here}}
 }
@@ -750,7 +751,7 @@ MyObj* uaf_before_uar() {
   {
     MyObj local_obj;
     p = &local_obj;  // expected-warning {{object whose reference is captured does not live long enough}} \
-                     // expected-note {{variable `p` is now an alias of `local_obj`}}
+                     // expected-note {{variable 'p' aliases the storage of variable 'local_obj'}}
   }                  // expected-note {{destroyed here}}
   return p;          // expected-note {{later used here}}
 }
@@ -829,7 +830,8 @@ void lifetimebound_simple_function() {
   {
     MyObj obj;
     v = Identity(obj); // expected-warning {{object whose reference is captured does not live long enough}} \
-                       // expected-note {{variable `v` is now an alias of `Identity(obj)`}}
+                       // expected-note {{function call result aliases the storage of variable 'obj'}} \
+                       // expected-note {{variable 'v' aliases the storage of variable 'obj'}}
   }                    // expected-note {{destroyed here}}
   v.use();             // expected-note {{later used here}}
 }
@@ -838,8 +840,10 @@ void lifetimebound_multiple_args_definite() {
   View v;
   {
     MyObj obj1, obj2;
-    v = Choose(true,  // expected-note {{variable `v` is now an alias of `Choose(true, obj1, obj2)`}} \
-                      // expected-note {{variable `v` is now an alias of `Choose(true, obj1, obj2)`}}
+    v = Choose(true,  // expected-note {{function call result aliases the storage of variable 'obj1'}} \
+                      // expected-note {{variable 'v' aliases the storage of variable 'obj1'}} \
+                      // expected-note {{function call result aliases the storage of variable 'obj2'}} \
+                      // expected-note {{variable 'v' aliases the storage of variable 'obj2'}}
                obj1,  // expected-warning {{object whose reference is captured does not live long enough}}
                obj2); // expected-warning {{object whose reference is captured does not live long enough}}
   }                              // expected-note 2 {{destroyed here}}
@@ -853,8 +857,10 @@ void lifetimebound_multiple_args_potential(bool cond) {
     MyObj obj1;
     if (cond) {
       MyObj obj2;
-      v = Choose(true,             // expected-note {{variable `v` is now an alias of `Choose(true, obj1, obj2)`}} \
-                                   // expected-note {{variable `v` is now an alias of `Choose(true, obj1, obj2)`}}
+      v = Choose(true,             // expected-note {{function call result aliases the storage of variable 'obj1'}} \
+                                   // expected-note {{variable 'v' aliases the storage of variable 'obj1'}} \
+                                   // expected-note {{function call result aliases the storage of variable 'obj2'}} \
+                                   // expected-note {{variable 'v' aliases the storage of variable 'obj2'}}
                  obj1,             // expected-warning {{object whose reference is captured does not live long enough}}
                  obj2);            // expected-warning {{object whose reference is captured does not live long enough}}
     }                              // expected-note {{destroyed here}}
@@ -868,7 +874,8 @@ void lifetimebound_mixed_args() {
   {
     MyObj obj1, obj2;
     v = SelectFirst(obj1,        // expected-warning {{object whose reference is captured does not live long enough}} \
-                                 // expected-note {{variable `v` is now an alias of `SelectFirst(obj1, obj2)`}}
+                                 // expected-note {{function call result aliases the storage of variable 'obj1'}} \
+                                 // expected-note {{variable 'v' aliases the storage of variable 'obj1'}}
                     obj2);
   }                              // expected-note {{destroyed here}}
   v.use();                       // expected-note {{later used here}}
@@ -885,7 +892,8 @@ void lifetimebound_member_function() {
   {
     MyObj obj;
     v  = obj.getView(); // expected-warning {{object whose reference is captured does not live long enough}} \
-                        // expected-note {{variable `v` is now an alias of `obj.getView()`}}
+                        // expected-note {{function call result aliases the storage of variable 'obj'}} \
+                        // expected-note {{variable 'v' aliases the storage of variable 'obj'}}
   }                     // expected-note {{destroyed here}}
   v.use();              // expected-note {{later used here}}
 }
@@ -901,7 +909,7 @@ void lifetimebound_conversion_operator() {
   {
     LifetimeBoundConversionView obj;
     v = obj;  // expected-warning {{object whose reference is captured does not live long enough}} \
-              // expected-note {{variable `v` is now an alias of `obj.operator View()`}}
+              // expected-note {{variable 'v' aliases the storage of variable 'obj'}}
   }           // expected-note {{destroyed here}}
   v.use();    // expected-note {{later used here}}
 }
@@ -911,7 +919,8 @@ void lifetimebound_chained_calls() {
   {
     MyObj obj;
     v = Identity(Identity(Identity(obj))); // expected-warning {{object whose reference is captured does not live long enough}} \
-                                           // expected-note {{variable `v` is now an alias of `Identity(Identity(Identity(obj)))`}}
+                                           // expected-note {{function call result aliases the storage of variable 'obj'}} \
+                                           // expected-note {{variable 'v' aliases the storage of variable 'obj'}}
   }                                        // expected-note {{destroyed here}}
   v.use();                                 // expected-note {{later used here}}
 }
@@ -921,7 +930,8 @@ void lifetimebound_with_pointers() {
   {
     MyObj obj;
     ptr = GetPointer(obj); // expected-warning {{object whose reference is captured does not live long enough}} \
-                           // expected-note {{variable `ptr` is now an alias of `GetPointer(obj)`}}
+                           // expected-note {{function call result aliases the storage of variable 'obj'}} \
+                           // expected-note {{variable 'ptr' aliases the storage of variable 'obj'}}
   }                        // expected-note {{destroyed here}}
   (void)*ptr;              // expected-note {{later used here}}
 }
@@ -939,7 +949,8 @@ void lifetimebound_partial_safety(bool cond) {
   
   if (cond) {
     MyObj temp_obj;
-    v = Choose(true,       // expected-note {{variable `v` is now an alias of `Choose(true, safe_obj, temp_obj)`}}
+    v = Choose(true,      // expected-note {{function call result aliases the storage of variable 'temp_obj'}} \
+                          // expected-note {{variable 'v' aliases the storage of variable 'temp_obj'}}
                safe_obj,
                temp_obj); // expected-warning {{object whose reference is captured does not live long enough}}
   }                       // expected-note {{destroyed here}}
@@ -953,9 +964,10 @@ void lifetimebound_return_reference() {
   {
     MyObj obj;
     View temp_v = obj;     // expected-warning {{object whose reference is captured does not live long enough}} \
-                           // expected-note {{variable `temp_v` is now an alias of `obj`}}
-    const MyObj& ref = GetObject(temp_v); // expected-note {{variable `ref` is now an alias of `GetObject(temp_v)`}}
-    ptr = &ref;           // expected-note {{variable `ptr` is now an alias of `ref`}}
+                           // expected-note {{variable 'temp_v' aliases the storage of variable 'obj'}}
+    const MyObj& ref = GetObject(temp_v); // expected-note {{function call result aliases the storage of variable 'obj'}} \
+                                          // expected-note {{variable 'ref' aliases the storage of variable 'obj'}}
+    ptr = &ref;           // expected-note {{variable 'ptr' aliases the storage of variable 'obj'}}
   }                       // expected-note {{destroyed here}}
   (void)*ptr;             // expected-note {{later used here}}
 }
@@ -969,7 +981,8 @@ void lifetimebound_ctor() {
   LifetimeBoundCtor v;
   {
     MyObj obj;
-    v = obj; // expected-warning {{object whose reference is captured does not live long enough}}
+    v = obj; // expected-warning {{object whose reference is captured does not live long enough}} \
+             // expected-note {{variable 'v' aliases the storage of variable 'obj'}}
   }          // expected-note {{destroyed here}}
   (void)v;   // expected-note {{later used here}}
 }
@@ -1046,7 +1059,7 @@ void conditional_operator_one_unsafe_branch(bool cond) {
   {
     MyObj temp;
     p = cond ? &temp  // expected-warning {{object whose reference is captured does not live long enough}} \
-                      // expected-note {{variable `p` is now an alias of `temp`}}
+                      // expected-note {{variable 'p' aliases the storage of variable 'temp'}}
              : &safe;
   }  // expected-note {{destroyed here}}
 
@@ -1063,9 +1076,9 @@ void conditional_operator_two_unsafe_branches(bool cond) {
   {
     MyObj a, b;
     p = cond ? &a   // expected-warning {{object whose reference is captured does not live long enough}} \
-                    // expected-note {{variable `p` is now an alias of `a`}}
-             : &b;  // expected-warning {{object whose reference is captured does not live long enough}} \
-                    // expected-note {{variable `p` is now an alias of `b`}}
+                    // expected-note {{variable 'p' aliases the storage of variable 'a'}} \
+                    // expected-note {{variable 'p' aliases the storage of variable 'b'}}
+             : &b;  // expected-warning {{object whose reference is captured does not live long enough}}
   }  // expected-note 2 {{destroyed here}}
   (void)*p;  // expected-note 2 {{later used here}}
 }
@@ -1075,13 +1088,13 @@ void conditional_operator_nested(bool cond) {
   {
     MyObj a, b, c, d;
     p = cond ? cond ? &a    // expected-warning {{object whose reference is captured does not live long enough}}. \
-                            // expected-note {{variable `p` is now an alias of `a`}}
-                    : &b    // expected-warning {{object whose reference is captured does not live long enough}}. \
-                            // expected-note {{variable `p` is now an alias of `b`}}
-             : cond ? &c    // expected-warning {{object whose reference is captured does not live long enough}}. \
-                            // expected-note {{variable `p` is now an alias of `c`}}
-                    : &d;   // expected-warning {{object whose reference is captured does not live long enough}}. \
-                            // expected-note {{variable `p` is now an alias of `d`}}
+                            // expected-note {{variable 'p' aliases the storage of variable 'a'}} \
+                            // expected-note {{variable 'p' aliases the storage of variable 'b'}} \
+                            // expected-note {{variable 'p' aliases the storage of variable 'c'}} \
+                            // expected-note {{variable 'p' aliases the storage of variable 'd'}}
+                    : &b    // expected-warning {{object whose reference is captured does not live long enough}}.
+             : cond ? &c    // expected-warning {{object whose reference is captured does not live long enough}}.
+                    : &d;   // expected-warning {{object whose reference is captured does not live long enough}}.
   }  // expected-note 4 {{destroyed here}}
   (void)*p;  // expected-note 4 {{later used here}}
 }
@@ -1091,8 +1104,10 @@ void conditional_operator_lifetimebound(bool cond) {
   {
     MyObj a, b;
     p = Identity(cond ? &a    // expected-warning {{object whose reference is captured does not live long enough}} \
-                              // expected-note {{variable `p` is now an alias of `Identity(cond ? &a : &b)`}} \
-                              // expected-note {{variable `p` is now an alias of `Identity(cond ? &a : &b)`}}
+                              // expected-note {{function call result aliases the storage of variable 'b'}} \
+                              // expected-note {{variable 'p' aliases the storage of variable 'b'}} \
+                              // expected-note {{function call result aliases the storage of variable 'a'}} \
+                              // expected-note {{variable 'p' aliases the storage of variable 'a'}}
                       : &b);  // expected-warning {{object whose reference is captured does not live long enough}}
   }  // expected-note 2 {{destroyed here}}
   (void)*p;  // expected-note 2 {{later used here}}
@@ -1103,8 +1118,10 @@ void conditional_operator_lifetimebound_nested(bool cond) {
   {
     MyObj a, b;
     p = Identity(cond ? Identity(&a)    // expected-warning {{object whose reference is captured does not live long enough}} \
-                                        // expected-note {{variable `p` is now an alias of `Identity(cond ? Identity(&a) : Identity(&b))`}} \
-                                        // expected-note {{variable `p` is now an alias of `Identity(cond ? Identity(&a) : Identity(&b))`}}
+                                        // expected-note {{function call result aliases the storage of variable 'b'}} \
+                                        // expected-note {{variable 'p' aliases the storage of variable 'b'}} \
+                                        // expected-note {{function call result aliases the storage of variable 'a'}} \
+                                        // expected-note {{variable 'p' aliases the storage of variable 'a'}}
                       : Identity(&b));  // expected-warning {{object whose reference is captured does not live long enough}}
   }  // expected-note 2 {{destroyed here}}
   (void)*p;  // expected-note 2 {{later used here}}
@@ -1115,10 +1132,14 @@ void conditional_operator_lifetimebound_nested_deep(bool cond) {
   {
     MyObj a, b, c, d;
     p = Identity(cond ? Identity(cond ? &a     // expected-warning {{object whose reference is captured does not live long enough}} \
-                                               // expected-note {{variable `p` is now an alias of `Identity(cond ? Identity(cond ? &a : &b) : Identity(cond ? &c : &d))`}} \
-                                               // expected-note {{variable `p` is now an alias of `Identity(cond ? Identity(cond ? &a : &b) : Identity(cond ? &c : &d))`}} \
-                                               // expected-note {{variable `p` is now an alias of `Identity(cond ? Identity(cond ? &a : &b) : Identity(cond ? &c : &d))`}} \
-                                               // expected-note {{variable `p` is now an alias of `Identity(cond ? Identity(cond ? &a : &b) : Identity(cond ? &c : &d))`}}
+                                               // expected-note {{function call result aliases the storage of variable 'a'}} \
+                                               // expected-note {{variable 'p' aliases the storage of variable 'a'}} \
+                                               // expected-note {{function call result aliases the storage of variable 'b'}} \
+                                               // expected-note {{variable 'p' aliases the storage of variable 'b'}} \
+                                               // expected-note {{function call result aliases the storage of variable 'c'}} \
+                                               // expected-note {{variable 'p' aliases the storage of variable 'c'}} \
+                                               // expected-note {{function call result aliases the storage of variable 'd'}} \
+                                               // expected-note {{variable 'p' aliases the storage of variable 'd'}}
                                       : &b)    // expected-warning {{object whose reference is captured does not live long enough}}
                       : Identity(cond ? &c     // expected-warning {{object whose reference is captured does not live long enough}}
                                       : &d));  // expected-warning {{object whose reference is captured does not live long enough}}
@@ -1131,30 +1152,39 @@ void parentheses(bool cond) {
   {
     MyObj a;
     p = &((((a))));  // expected-warning {{object whose reference is captured does not live long enough}} \
-                     // expected-note {{variable `p` is now an alias of `a`}}
+                     // expected-note {{variable 'p' aliases the storage of variable 'a'}}
   }                  // expected-note {{destroyed here}}
   (void)*p;          // expected-note {{later used here}}
 
   {
     MyObj a;
     p = ((GetPointer((a))));  // expected-warning {{object whose reference is captured does not live long enough}} \
-                              // expected-note {{variable `p` is now an alias of `GetPointer((a))`}}
+                              // expected-note {{function call result aliases the storage of variable 'a'}} \
+                              // expected-note {{variable 'p' aliases the storage of variable 'a'}}
   }                           // expected-note {{destroyed here}}
   (void)*p;                   // expected-note {{later used here}}
 
   {
     MyObj a, b, c, d;
-    p = &(cond ? (cond ? a     // expected-warning {{object whose reference is captured does not live long enough}}. expected-note {{variable `p` is now an alias of `a`}}
-                       : b)    // expected-warning {{object whose reference is captured does not live long enough}}. expected-note {{variable `p` is now an alias of `b`}}
-               : (cond ? c     // expected-warning {{object whose reference is captured does not live long enough}}. expected-note {{variable `p` is now an alias of `c`}}
-                       : d));  // expected-warning {{object whose reference is captured does not live long enough}}. expected-note {{variable `p` is now an alias of `d`}}
+    p = &(cond ? (cond ? a     // expected-warning {{object whose reference is captured does not live long enough}}. \
+                               // expected-note {{variable 'p' aliases the storage of variable 'a'}} \
+                               // expected-note {{variable 'p' aliases the storage of variable 'b'}} \
+                               // expected-note {{variable 'p' aliases the storage of variable 'c'}} \
+                               // expected-note {{variable 'p' aliases the storage of variable 'd'}}
+                       : b)    // expected-warning {{object whose reference is captured does not live long enough}}.
+               : (cond ? c     // expected-warning {{object whose reference is captured does not live long enough}}.
+                       : d));  // expected-warning {{object whose reference is captured does not live long enough}}.
   }  // expected-note 4 {{destroyed here}}
   (void)*p;  // expected-note 4 {{later used here}}
 
   {
     MyObj a, b, c, d;
-    p = ((cond ? (((cond ? &a : &b)))   // expected-warning 2 {{object whose reference is captured does not live long enough}}. expected-note {{variable `p` is now an alias of `b`}} expected-note {{variable `p` is now an alias of `a`}}
-              : &(((cond ? c : d)))));  // expected-warning 2 {{object whose reference is captured does not live long enough}}. expected-note {{variable `p` is now an alias of `d`}} expected-note {{variable `p` is now an alias of `c`}}
+    p = ((cond ? (((cond ? &a : &b)))   // expected-warning 2 {{object whose reference is captured does not live long enough}}. \
+                                        // expected-note {{variable 'p' aliases the storage of variable 'a'}} \
+                                        // expected-note {{variable 'p' aliases the storage of variable 'b'}} \
+                                        // expected-note {{variable 'p' aliases the storage of variable 'c'}} \
+                                        // expected-note {{variable 'p' aliases the storage of variable 'd'}}
+              : &(((cond ? c : d)))));  // expected-warning 2 {{object whose reference is captured does not live long enough}}.
   }  // expected-note 4 {{destroyed here}}
   (void)*p;  // expected-note 4 {{later used here}}
 
@@ -1163,20 +1193,26 @@ void parentheses(bool cond) {
 void use_temporary_after_destruction() {
   View a;
   a = non_trivially_destructed_temporary(); // expected-warning {{object whose reference is captured does not live long enough}} \
-                  expected-note {{destroyed here}} expected-note {{variable `a` is now an alias of `non_trivially_destructed_temporary()`}}
+                                            // expected-note {{destroyed here}} \
+                                            // expected-note {{function call result aliases the storage of the temporary}} \
+                                            // expected-note {{variable 'a' aliases the storage of the temporary}}
   use(a); // expected-note {{later used here}}
 }
 
 void passing_temporary_to_lifetime_bound_function() {
   View a = construct_view(non_trivially_destructed_temporary()); // expected-warning {{object whose reference is captured does not live long enough}} \
-                expected-note {{destroyed here}} expected-note {{variable `a` is now an alias of `construct_view(non_trivially_destructed_temporary())`}}
+                                                                 // expected-note {{destroyed here}} \
+                                                                 // expected-note {{function call result aliases the storage of the temporary}} \
+                                                                 // expected-note {{variable 'a' aliases the storage of the temporary}}
   use(a); // expected-note {{later used here}}
 }
 
 void use_trivial_temporary_after_destruction() {
   View a;
   a = trivially_destructed_temporary(); // expected-warning {{object whose reference is captured does not live long enough}} \
-                expected-note {{destroyed here}} expected-note {{variable `a` is now an alias of `trivially_destructed_temporary()`}}
+                                        // expected-note {{destroyed here}} \
+                                        // expected-note {{function call result aliases the storage of the temporary}} \
+                                        // expected-note {{variable 'a' aliases the storage of the temporary}}
   use(a); // expected-note {{later used here}}
 }
 
@@ -1217,8 +1253,10 @@ void foobar() {
   View view;
   {
     StatusOr<MyObj> string_or = getStringOr();
-    view = string_or. // expected-warning {{object whose reference is captured does not live long enough}}
-            value();  // expected-note {{variable `view` is now an alias of `string_or.value()`}}
+    view = string_or. // expected-warning {{object whose reference is captured does not live long enough}} \\
+                      // expected-note {{function call result aliases the storage of variable 'string_or'}} \\
+                      // expected-note {{variable 'view' aliases the storage of variable 'string_or'}}
+            value();
   }                     // expected-note {{destroyed here}}
   (void)view;           // expected-note {{later used here}}
 }
@@ -1238,8 +1276,8 @@ void range_based_for_use_after_scope() {
   {
     MyObjStorage s;
     for (const MyObj &o : s) { // expected-warning {{object whose reference is captured does not live long enough}} \
-                               // expected-note {{variable `o` is now an alias of `__begin2`}}
-      v = o;                  // expected-note {{variable `v` is now an alias of `o`}}
+                               // expected-note {{variable 'o' aliases the storage of variable 's'}}
+      v = o;                   // expected-note {{variable 'v' aliases the storage of variable 's'}}
     }
   } // expected-note {{destroyed here}}
   v.use(); // expected-note {{later used here}}
@@ -1260,7 +1298,7 @@ void range_based_for_not_reference() {
     MyObjStorage s;
     for (MyObj o : s) { // expected-note {{destroyed here}}
       v = o; // expected-warning {{object whose reference is captured does not live long enough}} \
-             // expected-note {{variable `v` is now an alias of `o`}}
+             // expected-note {{variable 'v' aliases the storage of variable 'o'}}
     }
   }
   v.use();  // expected-note {{later used here}}
@@ -1294,7 +1332,8 @@ void test_user_defined_deref_uaf() {
     MyObj obj;
     SmartPtr<MyObj> smart_ptr(&obj);
     p = &(*smart_ptr);  // expected-warning {{object whose reference is captured does not live long enough}} \
-                        // expected-note {{variable `p` is now an alias of `operator*(smart_ptr)`}}
+                        // expected-note {{expression aliases the storage of variable 'smart_ptr'}} \
+                        // expected-note {{variable 'p' aliases the storage of variable 'smart_ptr'}}
   }                     // expected-note {{destroyed here}}
   (void)*p;             // expected-note {{later used here}}
 }
@@ -1312,7 +1351,8 @@ void test_user_defined_deref_with_view() {
     MyObj obj;
     SmartPtr<MyObj> smart_ptr(&obj);
     v = *smart_ptr;  // expected-warning {{object whose reference is captured does not live long enough}} \
-                     // expected-note {{variable `v` is now an alias of `operator*(smart_ptr)`}}
+                     // expected-note {{expression aliases the storage of variable 'smart_ptr'}} \
+                     // expected-note {{variable 'v' aliases the storage of variable 'smart_ptr'}}
   }                  // expected-note {{destroyed here}}
   v.use();           // expected-note {{later used here}}
 }
@@ -1323,7 +1363,8 @@ void test_user_defined_deref_arrow() {
     MyObj obj;
     SmartPtr<MyObj> smart_ptr(&obj);
     p = smart_ptr.operator->();  // expected-warning {{object whose reference is captured does not live long enough}} \
-                                 // expected-note {{variable `p` is now an alias of `smart_ptr.operator->()`}}
+                                 // expected-note {{function call result aliases the storage of variable 'smart_ptr'}} \
+                                 // expected-note {{variable 'p' aliases the storage of variable 'smart_ptr'}}
   }                              // expected-note {{destroyed here}}
   (void)*p;                      // expected-note {{later used here}}
 }
@@ -1334,7 +1375,8 @@ void test_user_defined_deref_chained() {
     MyObj obj;
     SmartPtr<SmartPtr<MyObj>> double_ptr;
     p = &(**double_ptr);  // expected-warning {{object whose reference is captured does not live long enough}} \
-                          // expected-note {{variable `p` is now an alias of `operator*(* double_ptr)`}}
+                          // expected-note {{expression aliases the storage of variable 'double_ptr'}} \
+                          // expected-note {{variable 'p' aliases the storage of variable 'double_ptr'}}
   }                       // expected-note {{destroyed here}}
   (void)*p;               // expected-note {{later used here}}
 }
@@ -1486,7 +1528,7 @@ void strict_warn_on_move() {
   {
     MyObj a;
     v = a;            // expected-warning-re {{object whose reference {{.*}} may have been moved}} \
-                      // expected-note {{variable `v` is now an alias of `a`}}
+                      // expected-note {{variable 'v' aliases the storage of variable 'a'}}
     b = std::move(a); // expected-note {{potentially moved here}}
   }                   // expected-note {{destroyed here}}
   (void)v;            // expected-note {{later used here}}
@@ -1500,7 +1542,7 @@ void flow_sensitive(bool c) {
       MyObj b = std::move(a);
       return;
     }
-    v = a;  // expected-warning {{object whose reference}} expected-note {{variable `v` is now an alias of `a`}}
+    v = a;  // expected-warning {{object whose reference}} expected-note {{variable 'v' aliases the storage of variable 'a'}}
   }         // expected-note {{destroyed here}}
   (void)v;  // expected-note {{later used here}}
 }
@@ -1511,8 +1553,8 @@ void detect_conditional(bool cond) {
   {
     MyObj a, b;
     v = cond ? a : b; // expected-warning-re 2 {{object whose reference {{.*}} may have been moved}} \
-                      // expected-note {{variable `v` is now an alias of `b`}} \
-                      // expected-note {{variable `v` is now an alias of `a`}}
+                      // expected-note {{variable 'v' aliases the storage of variable 'b'}} \
+                      // expected-note {{variable 'v' aliases the storage of variable 'a'}}
     take(std::move(cond ? a : b)); // expected-note 2 {{potentially moved here}}
   }         // expected-note 2 {{destroyed here}}
   (void)v;  // expected-note 2 {{later used here}}
@@ -1523,14 +1565,16 @@ void wrong_use_of_move_is_permissive() {
   {
     MyObj a;
     v = std::move(a); // expected-warning {{object whose reference is captured does not live long enough}} \
-                      // expected-note {{variable `v` is now an alias of `std::move(a)`}}
+                      // expected-note {{function call result aliases the storage of variable 'a'}} \
+                      // expected-note {{variable 'v' aliases the storage of 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 {{object whose reference is captured does not live long enough}} \
-                                // expected-note {{variable `p` is now an alias of `std::move(a).getData()`}}
+                                // expected-note 2 {{function call result aliases the storage of variable 'a'}} \
+                                // expected-note {{variable 'p' aliases the storage of variable 'a'}}
   }         // expected-note {{destroyed here}}
   (void)p;  // expected-note {{later used here}}
 }
@@ -1542,7 +1586,8 @@ void test_release_no_uaf() {
   {
     std::unique_ptr<int> p;
     r = p.get();        // expected-warning-re {{object whose reference {{.*}} may have been moved}} \
-                        // expected-note {{variable `r` is now an alias of `p.get()`}}
+                        // expected-note {{function call result aliases the storage of variable 'p'}} \
+                        // expected-note {{variable 'r' aliases the storage of variable 'p'}}
     take(p.release());  // expected-note {{potentially moved here}}
   }                     // expected-note {{destroyed here}}
   (void)*r;             // expected-note {{later used here}}
@@ -1565,9 +1610,12 @@ void bar() {
     {
         S s;
         x = s.x();        // expected-warning {{object whose reference is captured does not live long enough}} \
-                          // expected-note {{variable `x` is now an alias of `s.x()`}}
+                          // expected-note {{function call result aliases the storage of variable 's'}} \
+                          // expected-note {{variable 'x' aliases the storage of variable 's'}}
         View y = S().x(); // expected-warning {{object whose reference is captured does not live long enough}} \
-                             expected-note {{destroyed here}} expected-note {{variable `y` is now an alias of `S().x()`}}
+                          // expected-note {{destroyed here}} \
+                          // expected-note {{function call result aliases the storage of the temporary}} \
+                          // expected-note {{variable 'y' aliases the storage of the temporary}}
         (void)y; // expected-note {{used here}}
     } // expected-note {{destroyed here}}
     (void)x; // expected-note {{used here}}
@@ -1657,20 +1705,23 @@ const S& identity(const S& in [[clang::lifetimebound]]);
 void test_temporary() {
   const std::string& x = S().x(); // expected-warning {{object whose reference is captured does not live long enough}} \
                                   // expected-note {{destroyed here}} \
-                                  // expected-note {{variable `x` is now an alias of `S().x()`}}
+                                  // expected-note {{function call result aliases the storage of the temporary}} \
+                                  // expected-note {{variable 'x' aliases the storage of the temporary}}
   (void)x; // expected-note {{later used here}}
 
   const std::string& y = identity(S().x()); // expected-warning {{object whose reference is captured does not live long enough}} \
                                             // expected-note {{destroyed here}} \
-                                            // expected-note {{variable `y` is now an alias of `identity(S().x())`}}
+                                            // expected-note {{function call result aliases the storage of the temporary}} \
+                                            // expected-note {{variable 'y' aliases the storage of the temporary}}
   (void)y; // expected-note {{later used here}}
 
   std::string_view z;
   {
     S s;
     const std::string& zz = s.x(); // expected-warning {{object whose reference is captured does not live long enough}} \
-                                   // expected-note {{variable `zz` is now an alias of `s.x()`}}
-    z = zz;                        // expected-note {{variable `z` is now an alias of `zz.operator basic_string_view()`}}
+                                   // expected-note {{function call result aliases the storage of variable 's'}} \
+                                   // expected-note {{variable 'zz' aliases the storage of variable 's'}}
+    z = zz;                        // expected-note {{variable 'z' aliases the storage of variable 's'}}
   } // expected-note {{destroyed here}}
   (void)z; // expected-note {{later used here}}
 }
@@ -1680,14 +1731,16 @@ void test_lifetime_extension_ok() {
   (void)x;
   const S& y = identity(S()); // expected-warning {{object whose reference is captured does not live long enough}} \
                               // expected-note {{destroyed here}} \
-                              // expected-note {{variable `y` is now an alias of `identity(S())`}}
+                              // expected-note {{function call result aliases the storage of the temporary}} \
+                              // expected-note {{variable 'y' aliases the storage of the temporary}}
   (void)y; // expected-note {{later used here}}
 }
 
 const std::string& test_return() {
   const std::string& x = S().x(); // expected-warning {{object whose reference is captured does not live long enough}} \
                                   // expected-note {{destroyed here}} \
-                                  // expected-note {{variable `x` is now an alias of `S().x()`}}
+                                  // expected-note {{function call result aliases the storage of the temporary}} \
+                                  // expected-note {{variable 'x' aliases the storage of the temporary}}
   return x; // expected-note {{later used here}}
 }
 } // namespace reference_type_decl_ref_expr
@@ -1704,8 +1757,8 @@ void uaf() {
   {
     S str;
     S* p = &str;  // expected-warning {{object whose reference is captured does not live long enough}} \
-                  // expected-note {{variable `p` is now an alias of `str`}}
-    view = p->s;  // expected-note {{variable `view` is now an alias of `p->s.operator basic_string_view()`}}
+                  // expected-note {{variable 'p' aliases the storage of variable 'str'}}
+    view = p->s;  // expected-note {{variable 'view' aliases the storage of variable 'str'}}
   } // expected-note {{destroyed here}}
   (void)view;  // expected-note {{later used here}}
 }
@@ -1731,8 +1784,8 @@ void uaf_union() {
   {
     U u = U{"hello"};
     U* up = &u;  // expected-warning {{object whose reference is captured does not live long enough}} \
-                 // expected-note {{variable `up` is now an alias of `u`}}
-    view = up->s; // expected-note {{variable `view` is now an alias of `up->s.operator basic_string_view()`}}
+                 // expected-note {{variable 'up' aliases the storage of variable 'u'}}
+    view = up->s; // expected-note {{variable 'view' aliases the storage of variable 'u'}}
   } // expected-note {{destroyed here}}
   (void)view;  // expected-note {{later used here}}
 }
@@ -1748,8 +1801,9 @@ void uaf_anonymous_union() {
   int* ip;
   {
     AnonymousUnion au;
-    AnonymousUnion* up = &au;  // expected-warning {{object whose reference is captured does not live long enough}} expected-note {{variable `up` is now an alias of `au`}}
-    ip = &up->x; // expected-note {{variable `ip` is now an alias of `up`}}
+    AnonymousUnion* up = &au;  // expected-warning {{object whose reference is captured does not live long enough}} \
+                               // expected-note {{variable 'up' aliases the storage of variable 'au'}}
+    ip = &up->x; // expected-note {{variable 'ip' aliases the storage of variable 'au'}}
   } // expected-note {{destroyed here}}
   (void)ip;  // expected-note {{later used here}}
 }
@@ -1809,13 +1863,16 @@ void test() {
   MemberFuncsTpl<MyObj> mtf;
   const MyObj* pTMA = mtf.memberA(MyObj()); // expected-warning {{object whose reference is captured does not live long enough}} \
                                             // expected-note {{destroyed here}} \
-                                            // expected-note {{variable `pTMA` is now an alias of `mtf.memberA(MyObj())`}}
+                                            // expected-note {{function call result aliases the storage of the temporary}} \
+                                            // expected-note {{variable 'pTMA' aliases the storage of the temporary}}
   const MyObj* pTMB = mtf.memberB(MyObj()); // tu-warning {{object whose reference is captured does not live long enough}} \
                                             // tu-note {{destroyed here}} \
-                                            // tu-note {{variable `pTMB` is now an alias of `mtf.memberB(MyObj())`}}
+                                            // tu-note {{function call result aliases the storage of the temporary}} \
+                                            // tu-note {{variable 'pTMB' aliases the storage of the temporary}}
   const MyObj* pTMC = mtf.memberC(MyObj()); // expected-warning {{object whose reference is captured does not live long enough}} \
                                             // expected-note {{destroyed here}} \
-                                            // expected-note {{variable `pTMC` is now an alias of `mtf.memberC(MyObj())`}}
+                                            // expected-note {{function call result aliases the storage of the temporary}} \
+                                            // expected-note {{variable 'pTMC' aliases the storage of the temporary}}
   (void)pTMA; // expected-note {{later used here}}
   (void)pTMB; // tu-note {{later used here}}
   (void)pTMC; // expected-note {{later used here}}
@@ -1851,7 +1908,9 @@ void test_optional_arrow() {
   {
     std::optional<std::string> opt;
     p = opt->data();  // expected-warning {{object whose reference is captured does not live long enough}} \
-                      // expected-note {{variable `p` is now an alias of `opt->data()`}}
+                      // expected-note {{expression aliases the storage of variable 'opt'}} \
+                      // expected-note {{function call result aliases the storage of variable 'opt'}} \
+                      // expected-note {{variable 'p' aliases the storage of variable 'opt'}}
   }                   // expected-note {{destroyed here}}
   (void)*p;           // expected-note {{later used here}}
 }
@@ -1861,7 +1920,9 @@ void test_optional_arrow_lifetimebound() {
   {
     std::optional<MyObj> opt;
     v = opt->getView();  // expected-warning {{object whose reference is captured does not live long enough}} \
-                         // expected-note {{variable `v` is now an alias of `opt->getView()`}}
+                         // expected-note {{expression aliases the storage of variable 'opt'}} \
+                         // expected-note {{function call result aliases the storage of variable 'opt'}} \
+                         // expected-note {{variable 'v' aliases the storage of variable 'opt'}}
   }                      // expected-note {{destroyed here}}
   v.use();               // expected-note {{later used here}}
 }
@@ -1871,7 +1932,9 @@ void test_unique_ptr_arrow() {
   {
     std::unique_ptr<std::string> up;
     p = up->data();  // expected-warning {{object whose reference is captured does not live long enough}} \
-                     // expected-note {{variable `p` is now an alias of `up->data()`}}
+                     // expected-note {{expression aliases the storage of variable 'up'}} \
+                     // expected-note {{function call result aliases the storage of variable 'up'}} \
+                     // expected-note {{variable 'p' aliases the storage of variable 'up'}}
   }                  // expected-note {{destroyed here}}
   (void)*p;          // expected-note {{later used here}}
 }
@@ -2063,8 +2126,8 @@ void multi_level_pointer_in_loop() {
     MyObj** pp;
     if (i > 5) {
       p = &obj; // expected-warning {{object whose reference is captured does not live long enough}} \
-                // expected-note {{variable `p` is now an alias of `obj`}}
-      pp = &p;  // expected-note {{variable `pp` is now an alias of `p`}}
+                // expected-note {{variable 'p' aliases the storage of variable 'obj'}}
+      pp = &p;  // expected-note {{variable 'pp' aliases the storage of variable 'obj'}}
     }
     (void)**pp; // expected-note {{later used here}}
   }             // expected-note {{destroyed here}}
@@ -2076,7 +2139,7 @@ void outer_pointer_outlives_inner_pointee() {
   for (int i = 0; i < 10; ++i) {
     MyObj obj;
     view = &obj;     // expected-warning {{object whose reference is captured does not live long enough}} \
-                     // expected-note {{variable `view` is now an alias of `obj`}}
+                     // expected-note {{variable 'view' aliases the storage of variable 'obj'}}
   }                  // expected-note {{destroyed here}}
   (void)*view;       // expected-note {{later used here}}
 }
@@ -2090,7 +2153,7 @@ void element_use_after_scope() {
   {
     int a[10]{};
     p = &a[2]; // expected-warning {{object whose reference is captured does not live long enough}} \
-               // expected-note {{variable `p` is now an alias of `a`}}
+               // expected-note {{variable 'p' aliases the storage of variable 'a'}}
   }            // expected-note {{destroyed here}}
   (void)*p;    // expected-note {{later used here}}
 }
@@ -2123,7 +2186,7 @@ void multidimensional_use_after_scope() {
   {
     int a[3][4]{};
     p = &a[1][2]; // expected-warning {{object whose reference is captured does not live long enough}} \
-                  // expected-note {{variable `p` is now an alias of `a`}}
+                  // expected-note {{variable 'p' aliases the storage of variable 'a'}}
   }               // expected-note {{destroyed here}}
   (void)*p;       // expected-note {{later used here}}
 }
@@ -2137,7 +2200,7 @@ void member_array_element_use_after_scope() {
   {
     S s;
     p = &s.arr[0]; // expected-warning {{object whose reference is captured does not live long enough}} \
-                   // expected-note {{variable `p` is now an alias of `s`}}
+                   // expected-note {{variable 'p' aliases the storage of variable 's'}}
   }                // expected-note {{destroyed here}}
   (void)*p;        // expected-note {{later used here}}
 }
@@ -2147,7 +2210,7 @@ void array_of_pointers_use_after_scope() {
   {
     int* a[10]{};
     p = a;  // expected-warning {{object whose reference is captured does not live long enough}} \
-            // expected-note {{variable `p` is now an alias of `a`}}
+            // expected-note {{variable 'p' aliases the storage of variable 'a'}}
   }         // expected-note {{destroyed here}}
   (void)*p; // expected-note {{later used here}}
 }
@@ -2157,7 +2220,7 @@ void reversed_subscript_use_after_scope() {
   {
     int a[10]{};
     p = &(0[a]); // expected-warning {{object whose reference is captured does not live long enough}} \
-                 // expected-note {{variable `p` is now an alias of `a`}}
+                 // expected-note {{variable 'p' aliases the storage of variable 'a'}}
   }              // expected-note {{destroyed here}}
   (void)*p;      // expected-note {{later used here}}
 }
@@ -2230,8 +2293,8 @@ struct S {
 
 void indexing_with_static_operator() {
   S()(1, 2);
-  S& x = S()("1", //expected-note {{variable `x` is now an alias of `operator()(S(), "1", 2, 3)`}} \
-                  //expected-note {{variable `x` is now an alias of `operator()(S(), "1", 2, 3)`}}
+  S& x = S()("1", //expected-note 2 {{expression aliases the storage of the temporary}} \
+                  //expected-note 2 {{variable 'x' aliases the storage of the temporary}}
              2,   // expected-warning {{object whose reference is captured does not live long enough}} expected-note {{destroyed here}}
              3);  // expected-warning {{object whose reference is captured does not live long enough}} expected-note {{destroyed here}}
 
@@ -2256,12 +2319,15 @@ S getS(const std::string &s [[clang::lifetimebound]]);
 
 void from_free_function() {
   S s = getS(std::string("temp")); // expected-warning {{object whose reference is captured does not live long enough}} \
+                                   // expected-note {{function call result aliases the storage of the temporary}} \
+                                   // expected-note {{variable 's' aliases the storage of the temporary}} \
                                    // expected-note {{destroyed here}}
   use(s);                          // expected-note {{later used here}}
 }
 
 void from_constructor() {
   S s(std::string("temp")); // expected-warning {{object whose reference is captured does not live long enough}} \
+                            // expected-note {{variable 's' aliases the storage of the temporary}} \
                             // expected-note {{destroyed here}}
   use(s);                   // expected-note {{later used here}}
 }
@@ -2275,12 +2341,16 @@ struct Factory {
 void from_method() {
   Factory f;
   S s = f.make(std::string("temp")); // expected-warning {{object whose reference is captured does not live long enough}} \
+                                     // expected-note {{function call result aliases the storage of the temporary}} \
+                                     // expected-note {{variable 's' aliases the storage of the temporary}} \
                                      // expected-note {{destroyed here}}
   use(s);                            // expected-note {{later used here}}
 }
 
 void from_static_method() {
   S s = Factory::create(std::string("temp")); // expected-warning {{object whose reference is captured does not live long enough}} \
+                                              // expected-note {{function call result aliases the storage of the temporary}} \
+                                              // expected-note {{variable 's' aliases the storage of the temporary}} \
                                               // expected-note {{destroyed here}}
   use(s);                                     // expected-note {{later used here}}
 }
@@ -2289,7 +2359,9 @@ void from_lifetimebound_this_method() {
   S value;
   {
     Factory f;
-    value = f.makeThis(); // expected-warning {{object whose reference is captured does not live long enough}}
+    value = f.makeThis(); // expected-warning {{object whose reference is captured does not live long enough}} \
+                          // expected-note {{function call result aliases the storage of variable 'f'}} \
+                          // expected-note {{variable 'value' aliases the storage of variable 'f'}}
   }                       // expected-note {{destroyed here}}
   use(value);             // expected-note {{later used here}}
 }
@@ -2298,7 +2370,9 @@ void across_scope() {
   S s{};
   {
     std::string str{"abc"};
-    s = getS(str); // expected-warning {{object whose reference is captured does not live long enough}}
+    s = getS(str); // expected-warning {{object whose reference is captured does not live long enough}} \
+                   // expected-note {{function call result aliases the storage of variable 'str'}} \
+                   // expected-note {{variable 's' aliases the storage of variable 'str'}}
   }                // expected-note {{destroyed here}}
   use(s);          // expected-note {{later used here}}
 }
@@ -2320,8 +2394,10 @@ void assignment_propagation() {
   S a, b;
   {
     std::string str{"abc"};
-    a = getS(str); // expected-warning {{object whose reference is captured does not live long enough}}
-    b = a;
+    a = getS(str); // expected-warning {{object whose reference is captured does not live long enough}} \
+                   // expected-note {{function call result aliases the storage of variable 'str'}} \
+                   // expected-note {{variable 'a' aliases the storage of variable 'str'}}
+    b = a;         // expected-note {{variable 'b' aliases the storage of variable 'str'}}
   }                // expected-note {{destroyed here}}
   use(b);          // expected-note {{later used here}}
 }
@@ -2335,6 +2411,8 @@ void no_annotation() {
 
 void mix_annotated_and_not() {
   S s1 = getS(std::string("temp")); // expected-warning {{object whose reference is captured does not live long enough}} \
+                                    // expected-note {{function call result aliases the storage of the temporary}} \
+                                    // expected-note {{variable 's1' aliases the storage of the temporary}} \
                                     // expected-note {{destroyed here}}
   S s2 = getSNoAnnotation(std::string("temp"));
   use(s1); // expected-note {{later used here}}
@@ -2347,6 +2425,8 @@ S multiple_lifetimebound_params() {
   std::string str{"abc"};
   S s = getS2(str, std::string("temp")); // expected-warning {{address of stack memory is returned later}} \
                                          // expected-warning {{object whose reference is captured does not live long enough}} \
+                                         // expected-note {{function call result aliases the storage of the temporary}} \
+                                         // expected-note {{variable 's' aliases the storage of the temporary}} \
                                          // expected-note {{destroyed here}}
   return s;                              // expected-note {{returned here}} \
                                          // expected-note {{later used here}}
@@ -2366,6 +2446,8 @@ T make(const std::string &s [[clang::lifetimebound]]);
 
 void from_template_instantiation() {
   S s = make<S>(std::string("temp")); // expected-warning {{object whose reference is captured does not live long enough}} \
+                                      // expected-note {{function call result aliases the storage of the temporary}} \
+                                      // expected-note {{variable 's' aliases the storage of the temporary}} \
                                       // expected-note {{destroyed here}}
   use(s);                             // expected-note {{later used here}}
 }
@@ -2429,6 +2511,8 @@ SAlias getSAlias(const std::string &s [[clang::lifetimebound]]);
 
 void from_typedef_return() {
   SAlias s = getSAlias(std::string("temp")); // expected-warning {{object whose reference is captured does not live long enough}} \
+                                             // expected-note {{function call result aliases the storage of the temporary}} \
+                                             // expected-note {{variable 's' aliases the storage of the temporary}} \
                                              // expected-note {{destroyed here}}
   use(s);                                    // expected-note {{later used here}}
 }
@@ -2503,6 +2587,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 {{object whose reference is captured does not live long enough}} \
+                                              // expected-note {{function call result aliases the storage of the temporary}} \
+                                              // expected-note {{variable 'ptr' aliases the storage of the temporar}} \
                                               // expected-note {{destroyed here}}
   (void)ptr;                                  // expected-note {{later used here}}
 }

>From 6a323b710c160b7f2b1dd9b28eb2cc16d685b991 Mon Sep 17 00:00:00 2001
From: suoyuan666 <suoyuan666 at s5n.xyz>
Date: Tue, 31 Mar 2026 17:53:06 +0800
Subject: [PATCH 04/12] fix ci error

Signed-off-by: suoyuan666 <suoyuan666 at s5n.xyz>
---
 clang/lib/Analysis/LifetimeSafety/AssignmentQuery.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/clang/lib/Analysis/LifetimeSafety/AssignmentQuery.cpp b/clang/lib/Analysis/LifetimeSafety/AssignmentQuery.cpp
index c3506f20f57d9..2b26f7aee024b 100644
--- a/clang/lib/Analysis/LifetimeSafety/AssignmentQuery.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/AssignmentQuery.cpp
@@ -13,6 +13,7 @@
 
 #include "clang/Analysis/Analyses/LifetimeSafety/AssignmentQuery.h"
 #include "clang/AST/Decl.h"
+#include "llvm/ADT/SmallPtrSet.h"
 #include "clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h"
 #include "clang/Analysis/Analyses/LifetimeSafety/Origins.h"
 #include "clang/Analysis/AnalysisDeclContext.h"

>From d5e1d6a1859a12890945f7b3c0ace87187dd206e Mon Sep 17 00:00:00 2001
From: suoyuan666 <suoyuan666 at s5n.xyz>
Date: Tue, 31 Mar 2026 17:57:32 +0800
Subject: [PATCH 05/12] fix clang-format error and my comment

Signed-off-by: suoyuan666 <suoyuan666 at s5n.xyz>
---
 clang/lib/Analysis/LifetimeSafety/AssignmentQuery.cpp | 2 +-
 clang/lib/Sema/SemaLifetimeSafety.h                   | 3 +--
 2 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/clang/lib/Analysis/LifetimeSafety/AssignmentQuery.cpp b/clang/lib/Analysis/LifetimeSafety/AssignmentQuery.cpp
index 2b26f7aee024b..eed32cc065506 100644
--- a/clang/lib/Analysis/LifetimeSafety/AssignmentQuery.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/AssignmentQuery.cpp
@@ -13,10 +13,10 @@
 
 #include "clang/Analysis/Analyses/LifetimeSafety/AssignmentQuery.h"
 #include "clang/AST/Decl.h"
-#include "llvm/ADT/SmallPtrSet.h"
 #include "clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h"
 #include "clang/Analysis/Analyses/LifetimeSafety/Origins.h"
 #include "clang/Analysis/AnalysisDeclContext.h"
+#include "llvm/ADT/SmallPtrSet.h"
 #include <cstddef>
 
 namespace {
diff --git a/clang/lib/Sema/SemaLifetimeSafety.h b/clang/lib/Sema/SemaLifetimeSafety.h
index 2c3f3252d7b28..55b8d41268fe0 100644
--- a/clang/lib/Sema/SemaLifetimeSafety.h
+++ b/clang/lib/Sema/SemaLifetimeSafety.h
@@ -58,9 +58,8 @@ inline void reportAssignmentImpl(Sema &S, const Expr *IssueExpr,
 
 inline void reportAssignment(Sema &S, const Expr *IssueExpr,
                              const OriginDestExpr &LHS, const Expr *RHS) {
-  if (!LHS || !RHS) {
+  if (!LHS || !RHS)
     return;
-  }
 
   if (const DeclRefExpr *LDExpr = llvm::dyn_cast<const DeclRefExpr *>(LHS)) {
     reportAssignmentImpl(S, IssueExpr, LDExpr->getDecl(), RHS,

>From 4389f18539d532d00886581dfe3f02e7a0259696 Mon Sep 17 00:00:00 2001
From: suoyuan666 <suoyuan666 at s5n.xyz>
Date: Wed, 1 Apr 2026 13:37:05 +0800
Subject: [PATCH 06/12] [LifetimeSafety]: using AssignmentQuery in
 reportUseAfterReturn

Signed-off-by: suoyuan666 <suoyuan666 at s5n.xyz>
---
 .../Analyses/LifetimeSafety/LifetimeSafety.h  |   8 +-
 .../LifetimeSafety/AssignmentQuery.cpp        |  29 +-
 clang/lib/Analysis/LifetimeSafety/Checker.cpp |  18 +-
 clang/lib/Sema/SemaLifetimeSafety.h           |  12 +-
 .../Sema/warn-lifetime-analysis-nocfg.cpp     |  21 +-
 clang/test/Sema/warn-lifetime-safety.cpp      | 256 ++++++++++++------
 6 files changed, 234 insertions(+), 110 deletions(-)

diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
index 40bc24f87b357..d2dca84d2408a 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
@@ -66,10 +66,10 @@ class LifetimeSafetySemaHelper {
       const std::optional<llvm::SmallVector<AssignmentPair>> AliasList,
       SourceLocation FreeLoc) {}
 
-  virtual void reportUseAfterReturn(const Expr *IssueExpr,
-                                    const Expr *ReturnExpr,
-                                    const Expr *MovedExpr,
-                                    SourceLocation ExpiryLoc) {}
+  virtual void reportUseAfterReturn(
+      const Expr *IssueExpr, const Expr *ReturnExpr, const Expr *MovedExpr,
+      const std::optional<llvm::SmallVector<AssignmentPair>> AliasList,
+      SourceLocation ExpiryLoc) {}
 
   virtual void reportDanglingField(const Expr *IssueExpr,
                                    const FieldDecl *Field,
diff --git a/clang/lib/Analysis/LifetimeSafety/AssignmentQuery.cpp b/clang/lib/Analysis/LifetimeSafety/AssignmentQuery.cpp
index eed32cc065506..33ae7b45ea5fa 100644
--- a/clang/lib/Analysis/LifetimeSafety/AssignmentQuery.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/AssignmentQuery.cpp
@@ -287,28 +287,43 @@ namespace clang::lifetimes::internal {
 std::optional<llvm::SmallVector<AssignmentPair>>
 getAliasList(const AssignmentQueryContext &Context, const Fact *CausingFact,
              const LoanID End, const Expr *IssueExpr) {
-  const auto *UF = llvm::dyn_cast<UseFact>(CausingFact);
+  llvm::SmallVector<OriginID, 4> TargetOIDList;
+  const Expr *WarnningFact = nullptr;
+
+  if (const auto *UF = llvm::dyn_cast<UseFact>(CausingFact)) {
+    WarnningFact = UF->getUseExpr();
+    for (const OriginList *Cur = UF->getUsedOrigins(); Cur;
+         Cur = Cur->peelOuterOrigin())
+      TargetOIDList.push_back(Cur->getOuterOriginID());
+  } else if (const auto *RetEscapeF =
+                 llvm::dyn_cast<ReturnEscapeFact>(CausingFact)) {
+    WarnningFact = RetEscapeF->getReturnExpr();
+    TargetOIDList.push_back(RetEscapeF->getEscapedOriginID());
+  } else {
+    llvm_unreachable("Without a corresponding Fact handler, assignment history "
+                     "traceback will fail.");
+  }
+
   const CFGBlock *StartBlock =
-      Context.ADC.getCFGStmtMap()->getBlock(UF->getUseExpr());
+      Context.ADC.getCFGStmtMap()->getBlock(WarnningFact);
   assert(StartBlock && "Searching CFGBlock failed");
   const CFGBlock *EndBlock = Context.ADC.getCFGStmtMap()->getBlock(IssueExpr);
   assert(EndBlock && "Searching CFGBlock failed");
 
-  for (const OriginList *Cur = UF->getUsedOrigins(); Cur;
-       Cur = Cur->peelOuterOrigin()) {
-    auto TargetOID = Cur->getOuterOriginID();
+  for (auto TargetOID : TargetOIDList) {
     if (StartBlock == EndBlock) {
-      AliasAssignmentSearchResult Result =
+      const AliasAssignmentSearchResult Result =
           getAliasListCore(Context, StartBlock, End, &TargetOID);
       if (!Result.Payload.empty())
         return Result.Payload;
     } else {
-      auto Result =
+      const auto Result =
           getAliasListInMultiBlock(Context, StartBlock, End, &TargetOID);
       if (Result.has_value())
         return Result.value();
     }
   }
+
   return std::nullopt;
 }
 } // namespace clang::lifetimes::internal
diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
index 9e0c2e1ce3e67..fcc3dbd6130b3 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -250,20 +250,20 @@ class LifetimeChecker {
           const struct AssignmentQueryContext Context = {
               LoanPropagation, MovedLoans, LiveOrigins, FactMgr, ADC};
           const auto AliasExprs = getAliasList(Context, UF, LID, IssueExpr);
-          if (!AliasExprs.has_value()) {
-            llvm::dbgs() << "Search variable assignment chain failed\n";
-          }
-
           SemaHelper->reportUseAfterFree(IssueExpr, UF->getUseExpr(), MovedExpr,
                                          AliasExprs, ExpiryLoc);
         }
       } else if (const auto *OEF =
                      CausingFact.dyn_cast<const OriginEscapesFact *>()) {
-        if (const auto *RetEscape = dyn_cast<ReturnEscapeFact>(OEF))
-          // Return stack address.
-          SemaHelper->reportUseAfterReturn(
-              IssueExpr, RetEscape->getReturnExpr(), MovedExpr, ExpiryLoc);
-        else if (const auto *FieldEscape = dyn_cast<FieldEscapeFact>(OEF))
+        if (const auto *RetEscape = dyn_cast<ReturnEscapeFact>(OEF)) {
+          const struct AssignmentQueryContext Context = {
+              LoanPropagation, MovedLoans, LiveOrigins, FactMgr, ADC};
+          const auto AliasExprs =
+              getAliasList(Context, RetEscape, LID, IssueExpr);
+          SemaHelper->reportUseAfterReturn(IssueExpr,
+                                           RetEscape->getReturnExpr(),
+                                           MovedExpr, AliasExprs, ExpiryLoc);
+        } else if (const auto *FieldEscape = dyn_cast<FieldEscapeFact>(OEF))
           // Dangling field.
           SemaHelper->reportDanglingField(
               IssueExpr, FieldEscape->getFieldDecl(), MovedExpr, ExpiryLoc);
diff --git a/clang/lib/Sema/SemaLifetimeSafety.h b/clang/lib/Sema/SemaLifetimeSafety.h
index 55b8d41268fe0..cf75ff27082d4 100644
--- a/clang/lib/Sema/SemaLifetimeSafety.h
+++ b/clang/lib/Sema/SemaLifetimeSafety.h
@@ -95,9 +95,10 @@ class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper {
         << UseExpr->getSourceRange();
   }
 
-  void reportUseAfterReturn(const Expr *IssueExpr, const Expr *ReturnExpr,
-                            const Expr *MovedExpr,
-                            SourceLocation ExpiryLoc) override {
+  void reportUseAfterReturn(
+      const Expr *IssueExpr, const Expr *ReturnExpr, const Expr *MovedExpr,
+      const std::optional<llvm::SmallVector<AssignmentPair>> AliasList,
+      SourceLocation ExpiryLoc) override {
     S.Diag(IssueExpr->getExprLoc(),
            MovedExpr ? diag::warn_lifetime_safety_return_stack_addr_moved
                      : diag::warn_lifetime_safety_return_stack_addr)
@@ -105,6 +106,11 @@ class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper {
     if (MovedExpr)
       S.Diag(MovedExpr->getExprLoc(), diag::note_lifetime_safety_moved_here)
           << MovedExpr->getSourceRange();
+
+    if (AliasList.has_value())
+      for (const auto &AliasStmt : llvm::reverse(AliasList.value()))
+        reportAssignment(S, IssueExpr, AliasStmt.first, AliasStmt.second);
+
     S.Diag(ReturnExpr->getExprLoc(), diag::note_lifetime_safety_returned_here)
         << ReturnExpr->getSourceRange();
   }
diff --git a/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp b/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
index 201a0797efdb4..6042b75f26d4e 100644
--- a/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
+++ b/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
@@ -367,7 +367,9 @@ int &usedToBeFalsePositive(std::vector<int> &v) {
 int &doNotFollowReferencesForLocalOwner() {
 // Warning caught by CFG analysis.
   std::unique_ptr<int> localOwner;
-  int &p = *localOwner // cfg-warning {{address of stack memory is returned later}}
+  int &p = *localOwner // cfg-warning {{address of stack memory is returned later}} \
+                       // cfg-note {{function call result aliases the storage of variable 'localOwner'}} \
+                       // cfg-note {{variable 'p' aliases the storage of variable 'localOwner'}}
             .get();
   return p; // cfg-note {{returned here}}
 }
@@ -1029,14 +1031,18 @@ void test4() {
 
 namespace range_based_for_loop_variables {
 std::string_view test_view_loop_var(std::vector<std::string> strings) {
-  for (std::string_view s : strings) {  // cfg-warning {{address of stack memory is returned later}} 
+  for (std::string_view s : strings) {  // cfg-warning {{address of stack memory is returned later}} \
+                                        // cfg-note {{function call result aliases the storage of variable 'strings'}} \
+                                        // cfg-note {{variable '__begin1' aliases the storage of variable 'strings'}}
     return s; //cfg-note {{returned here}}
   }
   return "";
 }
 
 const char* test_view_loop_var_with_data(std::vector<std::string> strings) {
-  for (std::string_view s : strings) {  // cfg-warning {{address of stack memory is returned later}} 
+  for (std::string_view s : strings) {  // cfg-warning {{address of stack memory is returned later}} \
+                                        // cfg-note {{function call result aliases the storage of variable 'strings'}} \
+                                        // cfg-note {{variable '__begin1' aliases the storage of variable 'strings'}}
     return s.data(); //cfg-note {{returned here}}
   }
   return "";
@@ -1050,14 +1056,19 @@ std::string_view test_no_error_for_views(std::vector<std::string_view> views) {
 }
 
 std::string_view test_string_ref_var(std::vector<std::string> strings) {
-  for (const std::string& s : strings) {  // cfg-warning {{address of stack memory is returned later}} 
+  for (const std::string& s : strings) {  // cfg-warning {{address of stack memory is returned later}} \
+                                          // cfg-note {{function call result aliases the storage of variable 'strings'}} \
+                                          // cfg-note {{variable '__begin1' aliases the storage of variable 'strings'}}
     return s; //cfg-note {{returned here}}
   }
   return "";
 }
 
 std::string_view test_opt_strings(std::optional<std::vector<std::string>> strings_or) {
-  for (const std::string& s : *strings_or) {  // cfg-warning {{address of stack memory is returned later}} 
+  for (const std::string& s : *strings_or) {  // cfg-warning {{address of stack memory is returned later}} \
+                                              // cfg-note {{variable '__range1' aliases the storage of variable 'strings_or'}} \
+                                              // cfg-note {{function call result aliases the storage of variable 'strings_or'}} \
+                                              // cfg-note {{variable '__begin1' aliases the storage of variable 'strings_or'}}
     return s; //cfg-note {{returned here}}
   }
   return "";
diff --git a/clang/test/Sema/warn-lifetime-safety.cpp b/clang/test/Sema/warn-lifetime-safety.cpp
index 3df319836c7f7..04ed6835fac7b 100644
--- a/clang/test/Sema/warn-lifetime-safety.cpp
+++ b/clang/test/Sema/warn-lifetime-safety.cpp
@@ -505,7 +505,8 @@ void small_scope_reference_var_no_error() {
 
 MyObj* simple_return_stack_address() {
   MyObj s;      
-  MyObj* p = &s; // expected-warning {{address of stack memory is returned later}}
+  MyObj* p = &s; // expected-warning {{address of stack memory is returned later}} \
+                 // expected-note {{variable 'p' aliases the storage of variable 's'}}
   return p;      // expected-note {{returned here}}
 }
 
@@ -534,7 +535,8 @@ const MyObj* conditional_assign_unconditional_return(const MyObj& safe, bool c)
   MyObj s; 
   const MyObj* p = &safe;
   if (c) {
-    p = &s;       // expected-warning {{address of stack memory is returned later}}
+    p = &s;       // expected-warning {{address of stack memory is returned later}} \
+                  // expected-note {{variable 'p' aliases the storage of variable 's'}}
   }     
   return p;      // expected-note {{returned here}}
 }
@@ -543,7 +545,8 @@ View conditional_assign_both_branches(const MyObj& safe, bool c) {
   MyObj s;
   View p;
   if (c) {
-    p = s;      // expected-warning {{address of stack memory is returned later}}
+    p = s;      // expected-warning {{address of stack memory is returned later}} \
+                // expected-note {{variable 'p' aliases the storage of variable 's'}}
   } 
   else {
     p = safe;
@@ -555,15 +558,17 @@ View conditional_assign_both_branches(const MyObj& safe, bool c) {
 View reassign_safe_to_local(const MyObj& safe) {
   MyObj local;
   View p = safe;
-  p = local;    // expected-warning {{address of stack memory is returned later}}
+  p = local;    // expected-warning {{address of stack memory is returned later}} \
+                // expected-note {{variable 'p' aliases the storage of variable 'local'}}
   return p;     // expected-note {{returned here}}
 }
 
 View pointer_chain_to_local() {
   MyObj local;
-  View p1 = local;     // expected-warning {{address of stack memory is returned later}}
-  View p2 = p1; 
-  return p2;          // expected-note {{returned here}}
+  View p1 = local;     // expected-warning {{address of stack memory is returned later}} \
+                       // expected-note {{variable 'p1' aliases the storage of variable 'local'}}
+  View p2 = p1;        // expected-note {{variable 'p2' aliases the storage of variable 'local'}}
+  return p2;           // expected-note {{returned here}}
 }
 
 View multiple_assign_multiple_return(const MyObj& safe, bool c1, bool c2) {
@@ -571,11 +576,13 @@ View multiple_assign_multiple_return(const MyObj& safe, bool c1, bool c2) {
   MyObj local2;
   View p;
   if (c1) {
-    p = local1;       // expected-warning {{address of stack memory is returned later}}
+    p = local1;       // expected-warning {{address of stack memory is returned later}} \
+                      // expected-note {{variable 'p' aliases the storage of variable 'local1'}}
     return p;         // expected-note {{returned here}}
   }
   else if (c2) {
-    p = local2;       // expected-warning {{address of stack memory is returned later}}
+    p = local2;       // expected-warning {{address of stack memory is returned later}} \
+                      // expected-note {{variable 'p' aliases the storage of variable 'local2'}}
     return p;         // expected-note {{returned here}}
   }
   p = safe;
@@ -587,15 +594,17 @@ View multiple_assign_single_return(const MyObj& safe, bool c1, bool c2) {
   MyObj local2;
   View p;
   if (c1) {
-    p = local1;      // expected-warning {{address of stack memory is returned later}}
+    p = local1;      // expected-warning {{address of stack memory is returned later}} \
+                     // expected-note {{variable 'p' aliases the storage of variable 'local1'}}
   }
   else if (c2) {
-    p = local2;      // expected-warning {{address of stack memory is returned later}}
+    p = local2;      // expected-warning {{address of stack memory is returned later}} \
+                     // expected-note {{variable 'p' aliases the storage of variable 'local2'}}
   }
   else {
     p = safe;
   }
-  return p;         // expected-note 2 {{returned here}}
+  return p;          // expected-note 2 {{returned here}}
 }
 
 View direct_return_of_local() {
@@ -613,14 +622,16 @@ MyObj& reference_return_of_local() {
 int* trivial_int_uar() {
   int *a;
   int b = 1;
-  a = &b;          // expected-warning {{address of stack memory is returned later}}
+  a = &b;          // expected-warning {{address of stack memory is returned later}} \
+                   // expected-note {{variable 'a' aliases the storage of variable 'b'}}
   return a;        // expected-note {{returned here}}
 }
 
 TriviallyDestructedClass* trivial_class_uar () {
   TriviallyDestructedClass *ptr;
   TriviallyDestructedClass s;
-  ptr = &s;       // expected-warning {{address of stack memory is returned later}}
+  ptr = &s;       // expected-warning {{address of stack memory is returned later}} \
+                  // expected-note {{variable 'ptr' aliases the storage of variable 's'}}
   return ptr;     // expected-note {{returned here}}
 }
 
@@ -635,7 +646,8 @@ int* return_pointer_to_parameter(int a) {
 }
 
 const int& return_reference_to_parameter(int a) {
-    const int &b = a;   // expected-warning {{address of stack memory is returned later}}
+    const int &b = a;   // expected-warning {{address of stack memory is returned later}} \
+                        // expected-note {{variable 'b' aliases the storage of variable 'a'}}
     return b;           // expected-note {{returned here}}
 }
 int return_reference_to_parameter_no_error(int a) {
@@ -645,24 +657,31 @@ int return_reference_to_parameter_no_error(int a) {
 
 MyObj*& return_ref_to_local_ptr_pointing_to_local() {
   MyObj local;
-  MyObj* p = &local; // expected-warning {{address of stack memory is returned later}}
+  MyObj* p = &local; // expected-warning {{address of stack memory is returned later}} \
+                     // expected-note {{variable 'p' aliases the storage of variable 'local'}}
   return p;          // expected-note {{returned here}} \
                      // expected-warning {{address of stack memory is returned later}} \
                      // expected-note {{returned here}}
 }
 
 const int& reference_via_conditional(int a, int b, bool cond) {
-    const int &c = (cond ? ((a)) : (b));  // expected-warning 2 {{address of stack memory is returned later}}
+    const int &c = (cond ? ((a)) : (b));  // expected-warning 2 {{address of stack memory is returned later}} \
+                                          // expected-note {{variable 'c' aliases the storage of variable 'a'}} \
+                                          // expected-note {{variable 'c' aliases the storage of variable 'b'}}
     return c;                             // expected-note 2 {{returned here}}
 }
 const int* return_pointer_to_parameter_via_reference(int a, int b, bool cond) {
-    const int &c = cond ? a : b;  // expected-warning 2 {{address of stack memory is returned later}}
-    const int* d = &c;
+    const int &c = cond ? a : b;  // expected-warning 2 {{address of stack memory is returned later}} \
+                                  // expected-note {{variable 'c' aliases the storage of variable 'a'}} \
+                                  // expected-note {{variable 'c' aliases the storage of variable 'b'}}
+    const int* d = &c;            // expected-note {{variable 'd' aliases the storage of variable 'a'}} \
+                                  // expected-note {{variable 'd' aliases the storage of variable 'b'}}
     return d;                     // expected-note 2 {{returned here}}
 }
 
 const int& return_pointer_to_parameter_via_reference_1(int a) {
-    const int* d = &a; // expected-warning {{address of stack memory is returned later}}
+    const int* d = &a; // expected-warning {{address of stack memory is returned later}} \
+                       // expected-note {{variable 'd' aliases the storage of variable 'a'}}
     return *d;    // expected-note {{returned here}}
 }
 
@@ -699,7 +718,9 @@ struct PtrHolder {
 
 int* const& test_ref_to_ptr() {
   PtrHolder a;
-  int *const &ref = a.getRef();  // expected-warning {{address of stack memory is returned later}}
+  int *const &ref = a.getRef();  // expected-warning {{address of stack memory is returned later}} \
+                                 // expected-note {{function call result aliases the storage of variable 'a'}} \
+                                 // expected-note {{variable 'ref' aliases the storage of variable 'a'}}
   return ref;  // expected-note {{returned here}}
 }
 int* const test_ref_to_ptr_no_error() {
@@ -736,9 +757,13 @@ void test_assign_through_double_ptr() {
 
 int** test_ternary_double_ptr(bool cond) {
   int a = 1, b = 2;
-  int* pa = &a;  // expected-warning {{address of stack memory is returned later}}
-  int* pb = &b;  // expected-warning {{address of stack memory is returned later}}
-  int** result = cond ? &pa : &pb;  // expected-warning 2 {{address of stack memory is returned later}}
+  int* pa = &a;  // expected-warning {{address of stack memory is returned later}} \
+                 // expected-note {{variable 'pa' aliases the storage of variable 'a'}}
+  int* pb = &b;  // expected-warning {{address of stack memory is returned later}} \
+                 // expected-note {{variable 'pb' aliases the storage of variable 'b'}}
+  int** result = cond ? &pa : &pb;  // expected-warning 2 {{address of stack memory is returned later}} \
+                                    // expected-note {{variable 'result' aliases the storage of variable 'pa'}} \
+                                    // expected-note {{variable 'result' aliases the storage of variable 'pb'}}
   return result; // expected-note 4 {{returned here}}
 }
 //===----------------------------------------------------------------------===//
@@ -760,7 +785,8 @@ View uar_before_uaf(const MyObj& safe, bool c) {
   View p;
   {
     MyObj local_obj; 
-    p = local_obj;  // expected-warning {{ddress of stack memory is returned later}}
+    p = local_obj;  // expected-warning {{ddress of stack memory is returned later}} \
+                    // expected-note {{variable 'p' aliases the storage of variable 'local_obj'}}
     if (c) {
       return p;     // expected-note {{returned here}}
     }
@@ -1285,7 +1311,9 @@ void range_based_for_use_after_scope() {
 
 View range_based_for_use_after_return() {
   MyObjStorage s;
-  for (const MyObj &o : s) { // expected-warning {{address of stack memory is returned later}}
+  for (const MyObj &o : s) { // expected-warning {{address of stack memory is returned later}} \
+                             // expected-note {{function call result aliases the storage of variable 's'}} \
+                             // expected-note {{variable '__begin1' aliases the storage of variable 's'}}
     return o;  // expected-note {{returned here}}
   }
   return *s.begin();  // expected-warning {{address of stack memory is returned later}}
@@ -1425,14 +1453,18 @@ MyObj* call_max_with_obj_error() {
 
 const MyObj* call_max_with_ref_obj_error() {
   MyObj oa, ob;
-  const MyObj& refa = oa;     // expected-warning {{address of stack memory is returned later}}
-  const MyObj& refb = ob;     // expected-warning {{address of stack memory is returned later}}
+  const MyObj& refa = oa;     // expected-warning {{address of stack memory is returned later}} \
+                              // expected-note {{variable 'refa' aliases the storage of variable 'oa'}}
+  const MyObj& refb = ob;     // expected-warning {{address of stack memory is returned later}} \
+                              // expected-note {{variable 'refb' aliases the storage of variable 'ob'}}
   return  &MaxT(refa, refb);  // expected-note 2 {{returned here}}
 }
 const MyObj& call_max_with_ref_obj_return_ref_error() {
   MyObj oa, ob;
-  const MyObj& refa = oa;     // expected-warning {{address of stack memory is returned later}}
-  const MyObj& refb = ob;     // expected-warning {{address of stack memory is returned later}}
+  const MyObj& refa = oa;     // expected-warning {{address of stack memory is returned later}} \
+                              // expected-note {{variable 'refa' aliases the storage of variable 'oa'}}
+  const MyObj& refb = ob;     // expected-warning {{address of stack memory is returned later}} \
+                              // expected-note {{variable 'refb' aliases the storage of variable 'ob'}}
   return  MaxT(refa, refb);   // expected-note 2 {{returned here}}
 }
 
@@ -1464,30 +1496,46 @@ const NonTrivialPointer& call_max_with_non_trivial_view_with_error() {
 namespace MultiPointerTypes {
 int** return_2p() {
   int a = 1;
-  int* b = &a;  // expected-warning {{address of stack memory is returned later}}
-  int** c = &b; // expected-warning {{address of stack memory is returned later}}
+  int* b = &a;  // expected-warning {{address of stack memory is returned later}} \
+                // expected-note {{variable 'b' aliases the storage of variable 'a'}}
+  int** c = &b; // expected-warning {{address of stack memory is returned later}} \
+                // expected-note {{variable 'c' aliases the storage of variable 'a'}} \
+                // expected-note {{variable 'c' aliases the storage of variable 'b'}}
   return c;     // expected-note 2 {{returned here}}
 }
 
 int** return_2p_one_is_safe(int& a) {
   int* b = &a;
-  int** c = &b; // expected-warning {{address of stack memory is returned later}}
+  int** c = &b; // expected-warning {{address of stack memory is returned later}} \
+                // expected-note {{variable 'c' aliases the storage of variable 'b'}}
   return c;     // expected-note {{returned here}}
 }
 
 int*** return_3p() {
   int a = 1;
-  int* b = &a;    // expected-warning {{address of stack memory is returned later}}
-  int** c = &b;   // expected-warning {{address of stack memory is returned later}}
-  int*** d = &c;  // expected-warning {{address of stack memory is returned later}}
+  int* b = &a;    // expected-warning {{address of stack memory is returned later}} \
+                  // expected-note {{variable 'b' aliases the storage of variable 'a'}}
+  int** c = &b;   // expected-warning {{address of stack memory is returned later}} \
+                  // expected-note {{variable 'c' aliases the storage of variable 'a'}} \
+                  // expected-note {{variable 'c' aliases the storage of variable 'b'}}
+  int*** d = &c;  // expected-warning {{address of stack memory is returned later}} \
+                  // expected-note {{variable 'd' aliases the storage of variable 'a'}} \
+                  // expected-note {{variable 'd' aliases the storage of variable 'b'}} \
+                  // expected-note {{variable 'd' aliases the storage of variable 'c'}}
   return d;       // expected-note 3 {{returned here}}
 }
 
 View** return_view_p() {
   MyObj a;
-  View b = a;     // expected-warning {{address of stack memory is returned later}}
-  View* c = &b;   // expected-warning {{address of stack memory is returned later}}
-  View** d = &c;  // expected-warning {{address of stack memory is returned later}}
+  View b = a;     // expected-warning {{address of stack memory is returned later}} \
+                  // expected-note {{variable 'b' aliases the storage of variable 'a'}}
+  View* c = &b;   // expected-warning {{address of stack memory is returned later}} \
+                  // expected-note {{variable 'c' aliases the storage of variable 'a'}} \
+                  // expected-note {{variable 'c' aliases the storage of variable 'b'}}
+  View** d = &c;  // expected-warning {{address of stack memory is returned later}} \
+                  // expected-note {{variable 'd' aliases the storage of variable 'a'}} \
+                  // expected-note {{variable 'd' aliases the storage of variable 'b'}} \
+                  // expected-note {{variable 'd' aliases the storage of variable 'c'}}
   return d;       // expected-note 3 {{returned here}}
 }
 
@@ -1624,24 +1672,30 @@ void bar() {
 
 namespace DereferenceViews {
 const MyObj& testDeref(MyObj obj) {
-  View v = obj; // expected-warning {{address of stack memory is returned later}}
+  View v = obj; // expected-warning {{address of stack memory is returned later}} \
+                // expected-note {{variable 'v' aliases the storage of variable 'obj'}}
   return *v;    // expected-note {{returned here}}
 }
 const MyObj* testDerefAddr(MyObj obj) {
-  View v = obj; // expected-warning {{address of stack memory is returned later}}
+  View v = obj; // expected-warning {{address of stack memory is returned later}} \
+                // expected-note {{variable 'v' aliases the storage of variable 'obj'}}
   return &*v;   // expected-note {{returned here}}
 }
 const MyObj* testData(MyObj obj) {
-  View v = obj;     // expected-warning {{address of stack memory is returned later}}
+  View v = obj;     // expected-warning {{address of stack memory is returned later}} \
+                    // expected-note {{variable 'v' aliases the storage of variable 'obj'}}
   return v.data();  // expected-note {{returned here}}
 }
 const int* testLifetimeboundAccessorOfMyObj(MyObj obj) {
-  View v = obj;           // expected-warning {{address of stack memory is returned later}}
-  const MyObj* ptr = v.data();
+  View v = obj;           // expected-warning {{address of stack memory is returned later}} \
+                          // expected-note {{variable 'v' aliases the storage of variable 'obj'}}
+  const MyObj* ptr = v.data(); // expected-note {{function call result aliases the storage of variable 'obj'}} \
+                               // expected-note {{variable 'ptr' aliases the storage of variable 'obj'}}
   return ptr->getData();  // expected-note {{returned here}}
 }
 const int* testLifetimeboundAccessorOfMyObjThroughDeref(MyObj obj) {
-  View v = obj;         // expected-warning {{address of stack memory is returned later}}
+  View v = obj;         // expected-warning {{address of stack memory is returned later}} \
+                        // expected-note {{variable 'v' aliases the storage of variable 'obj'}}
   return v->getData();  // expected-note {{returned here}}
 }
 } // namespace DereferenceViews
@@ -1665,17 +1719,23 @@ It end() const [[clang::lifetimebound]];
 MyObj Global;
 
 const MyObj& ContainerMyObjReturnRef(Container<MyObj> c) {
-  for (const MyObj& x : c) {  // expected-warning {{address of stack memory is returned later}}
+  for (const MyObj& x : c) {  // expected-warning {{address of stack memory is returned later}} \
+                              // expected-note {{function call result aliases the storage of variable 'c'}} \
+                              // expected-note {{variable '__begin1' aliases the storage of variable 'c'}}
     return x;                 // expected-note {{returned here}}
   }
   return Global;
 }
 
 View ContainerMyObjReturnView(Container<MyObj> c) {
-  for (const MyObj& x : c) {  // expected-warning {{address of stack memory is returned later}}
+  for (const MyObj& x : c) {  // expected-warning {{address of stack memory is returned later}} \
+                              // expected-note {{function call result aliases the storage of variable 'c'}} \
+                              // expected-note {{variable '__begin1' aliases the storage of variable 'c'}}
     return x;                 // expected-note {{returned here}}
   }
-  for (View x : c) {  // expected-warning {{address of stack memory is returned later}}
+  for (View x : c) {  // expected-warning {{address of stack memory is returned later}} \
+                      // expected-note {{function call result aliases the storage of variable 'c'}} \
+                      // expected-note {{variable '__begin1' aliases the storage of variable 'c'}}
     return x;         // expected-note {{returned here}}
   }
   return Global;
@@ -1892,12 +1952,14 @@ View test1(std::string a) {
 }
 
 View test2(std::string a) {
-  View b = View(a); // expected-warning {{address of stack memory is returned later}}
+  View b = View(a); // expected-warning {{address of stack memory is returned later}} \
+                    // expected-note {{variable 'b' aliases the storage of variable 'a'}}
   return b;         // expected-note {{returned here}}
 }
 
 View test3(std::string a) {
-  const View& b = View(a);  // expected-warning {{address of stack memory is returned later}}
+  const View& b = View(a);  // expected-warning {{address of stack memory is returned later}} \
+                            // expected-note {{variable 'b' aliases the storage of variable 'a'}}
   return b;                 // expected-note {{returned here}}
 }
 } // namespace non_trivial_views
@@ -1952,7 +2014,8 @@ void test_optional_view_arrow() {
 namespace lambda_captures {
 auto return_ref_capture() {
   int local = 1;
-  auto lambda = [&local]() { return local; }; // expected-warning {{address of stack memory is returned later}}
+  auto lambda = [&local]() { return local; }; // expected-warning {{address of stack memory is returned later}} \
+                                              // expected-note {{variable 'lambda' aliases the storage of variable 'local'}}
   return lambda; // expected-note {{returned here}}
 }
 
@@ -1970,8 +2033,9 @@ auto capture_int_by_value() {
 
 auto capture_view_by_value() {
   MyObj obj;
-  View v(obj); // expected-warning {{address of stack memory is returned later}}
-  auto lambda = [v]() { return v; };
+  View v(obj); // expected-warning {{address of stack memory is returned later}} \
+               // expected-note {{variable 'v' aliases the storage of variable 'obj'}}
+  auto lambda = [v]() { return v; }; // expected-note {{variable 'lambda' aliases the storage of variable 'obj'}}
   return lambda; // expected-note {{returned here}}
 }
 
@@ -1985,13 +2049,15 @@ void capture_view_by_value_safe() {
 auto capture_pointer_by_ref() {
   MyObj obj;
   MyObj* p = &obj;
-  auto lambda = [&p]() { return p; }; // expected-warning {{address of stack memory is returned later}}
+  auto lambda = [&p]() { return p; }; // expected-warning {{address of stack memory is returned later}} \\
+                                      // expected-note {{variable 'lambda' aliases the storage of variable 'p'}}
   return lambda; // expected-note {{returned here}}
 }
 
 auto capture_multiple() {
   int a, b;
-  auto lambda = [
+  auto lambda = [ // expected-note {{variable 'lambda' aliases the storage of variable 'b'}} \
+                  // expected-note {{variable 'lambda' aliases the storage of variable 'a'}}
     &a,  // expected-warning {{address of stack memory is returned later}}
     &b   // expected-warning {{address of stack memory is returned later}}
   ]() { return a + b; };
@@ -2000,42 +2066,48 @@ auto capture_multiple() {
 
 auto capture_raw_pointer_by_value() {
   int x;
-  int* p = &x; // expected-warning {{address of stack memory is returned later}}
-  auto lambda = [p]() { return p; };
+  int* p = &x; // expected-warning {{address of stack memory is returned later}} \
+               // expected-note {{variable 'p' aliases the storage of variable 'x'}}
+  auto lambda = [p]() { return p; }; // expected-note {{variable 'lambda' aliases the storage of variable 'x'}}
   return lambda; // expected-note {{returned here}}
 }
 
 auto capture_raw_pointer_init_capture() {
   int x;
-  int* p = &x; // expected-warning {{address of stack memory is returned later}}
-  auto lambda = [q = p]() { return q; };
+  int* p = &x; // expected-warning {{address of stack memory is returned later}} \
+               // expected-note {{variable 'p' aliases the storage of variable 'x'}}
+  auto lambda = [q = p]() { return q; }; // expected-note {{variable 'lambda' aliases the storage of variable 'x'}}
   return lambda; // expected-note {{returned here}}
 }
 
 auto capture_view_init_capture() {
   MyObj obj;
-  View v(obj); // expected-warning {{address of stack memory is returned later}}
-  auto lambda = [w = v]() { return w; };
+  View v(obj); // expected-warning {{address of stack memory is returned later}} \
+               // expected-note {{variable 'v' aliases the storage of variable 'obj'}}
+  auto lambda = [w = v]() { return w; }; // expected-note {{variable 'lambda' aliases the storage of variable 'obj'}}
   return lambda; // expected-note {{returned here}}
 }
 
 auto capture_lambda() {
   int x;
-  auto inner = [&x]() { return x; }; // expected-warning {{address of stack memory is returned later}}
-  auto outer = [inner]() { return inner(); };
+  auto inner = [&x]() { return x; }; // expected-warning {{address of stack memory is returned later}} \
+                                     // expected-note {{variable 'inner' aliases the storage of variable 'x'}}
+  auto outer = [inner]() { return inner(); }; // expected-note {{variable 'outer' aliases the storage of variable 'x'}}
   return outer; // expected-note {{returned here}}
 }
 
 auto return_copied_lambda() {
   int local = 1;
-  auto lambda = [&local]() { return local; }; // expected-warning {{address of stack memory is returned later}}
-  auto lambda_copy = lambda;
+  auto lambda = [&local]() { return local; }; // expected-warning {{address of stack memory is returned later}} \
+                                              // expected-note {{variable 'lambda' aliases the storage of variable 'local'}}
+  auto lambda_copy = lambda;                  // expected-note {{variable 'lambda_copy' aliases the storage of variable 'local'}}
   return lambda_copy; // expected-note {{returned here}}
 }
 
 auto implicit_ref_capture() {
   int local = 1;
-  auto lambda = [&]() { return local; }; // expected-warning {{address of stack memory is returned later}}
+  auto lambda = [&]() { return local; }; // expected-warning {{address of stack memory is returned later}} \
+                                         // expected-note {{variable 'lambda' aliases the storage of variable 'local'}}
   return lambda; // expected-note {{returned here}}
 }
 
@@ -2044,14 +2116,17 @@ auto implicit_ref_capture() {
 // can point to the same source location.
 auto implicit_ref_capture_multiple() {
   int local = 1, local2 = 2;
-  auto lambda = [&]() { return local + local2; }; // expected-warning 2 {{address of stack memory is returned later}}
+  auto lambda = [&]() { return local + local2; }; // expected-warning 2 {{address of stack memory is returned later}} \
+                                                  // expected-note {{variable 'lambda' aliases the storage of variable 'local'}} \
+                                                  // expected-note {{variable 'lambda' aliases the storage of variable 'local2'}}
   return lambda; // expected-note 2 {{returned here}}
 }
 
 auto implicit_value_capture() {
   MyObj obj;
-  View v(obj); // expected-warning {{address of stack memory is returned later}}
-  auto lambda = [=]() { return v; };
+  View v(obj); // expected-warning {{address of stack memory is returned later}} \
+               // expected-note {{variable 'v' aliases the storage of variable 'obj'}}
+  auto lambda = [=]() { return v; }; // expected-note {{variable 'lambda' aliases the storage of variable 'obj'}}
   return lambda; // expected-note {{returned here}}
 }
 
@@ -2082,16 +2157,22 @@ auto capture_static_address_by_value() {
 auto capture_static_address_by_ref() {
   static int local = 1;
   int* p = &local;
-  auto lambda = [&p]() { return p; }; // expected-warning {{address of stack memory is returned later}}
+  auto lambda = [&p]() { return p; }; // expected-warning {{address of stack memory is returned later}} \
+                                      // expected-note {{variable 'lambda' aliases the storage of variable 'p'}}
   return lambda; // expected-note {{returned here}}
 }
 
 auto capture_multilevel_pointer() {
   int x;
-  int *p = &x; // expected-warning {{address of stack memory is returned later}}
-  int **q = &p; // expected-warning {{address of stack memory is returned later}}
-  int ***r = &q; // expected-warning {{address of stack memory is returned later}}
-  auto lambda = [=]() { return *p + **q + ***r; };
+  int *p = &x;   // expected-warning {{address of stack memory is returned later}} \
+                 // expected-note {{variable 'p' aliases the storage of variable 'x'}}
+  int **q = &p;  // expected-warning {{address of stack memory is returned later}} \
+                 // expected-note {{variable 'q' aliases the storage of variable 'p'}}
+  int ***r = &q; // expected-warning {{address of stack memory is returned later}} \
+                 // expected-note {{variable 'r' aliases the storage of variable 'q'}}
+  auto lambda = [=]() { return *p + **q + ***r; }; // expected-note {{variable 'lambda' aliases the storage of variable 'x'}} \
+                                                   // expected-note {{variable 'lambda' aliases the storage of variable 'q'}} \
+                                                   // expected-note {{variable 'lambda' aliases the storage of variable 'p'}}
   return lambda; // expected-note 3 {{returned here}}
 }
 } // namespace lambda_captures
@@ -2160,7 +2241,8 @@ void element_use_after_scope() {
 
 int* element_use_after_return() {
   int a[10]{};
-  int* p = &a[0]; // expected-warning {{address of stack memory is returned later}}
+  int* p = &a[0]; // expected-warning {{address of stack memory is returned later}} \
+                  // expected-note {{variable 'p' aliases the storage of variable 'a'}}
   return p;       // expected-note {{returned here}}
 }
 
@@ -2227,7 +2309,8 @@ void reversed_subscript_use_after_scope() {
 
 int* return_decayed_array() {
   int a[10]{};
-  int *p = a; // expected-warning {{address of stack memory is returned later}}
+  int *p = a; // expected-warning {{address of stack memory is returned later}} \
+              // expected-note {{variable 'p' aliases the storage of variable 'a'}}
   return p;   // expected-note {{returned here}}
 }
 
@@ -2385,8 +2468,10 @@ void same_scope() {
 
 S copy_propagation() {
   std::string str{"abc"};
-  S a = getS(str); // expected-warning {{address of stack memory is returned later}}
-  S b = a;
+  S a = getS(str); // expected-warning {{address of stack memory is returned later}} \
+                   // expected-note {{function call result aliases the storage of variable 'str'}} \
+                   // expected-note {{variable 'a' aliases the storage of variable 'str'}}
+  S b = a;         // expected-note {{variable 'b' aliases the storage of variable 'str'}}
   return b; // expected-note {{returned here}}
 }
 
@@ -2427,6 +2512,8 @@ S multiple_lifetimebound_params() {
                                          // expected-warning {{object whose reference is captured does not live long enough}} \
                                          // expected-note {{function call result aliases the storage of the temporary}} \
                                          // expected-note {{variable 's' aliases the storage of the temporary}} \
+                                         // expected-note {{function call result aliases the storage of variable 'str'}} \
+                                         // expected-note {{variable 's' aliases the storage of variable 'str'}} \
                                          // expected-note {{destroyed here}}
   return s;                              // expected-note {{returned here}} \
                                          // expected-note {{later used here}}
@@ -2547,8 +2634,10 @@ DefaultedOuter getDefaultedOuter(const std::string &s [[clang::lifetimebound]]);
 // pattern does not fit the ownership model this analysis supports.
 DefaultedOuter nested_defaulted_outer_with_user_defined_inner() {
   std::string str{"abc"};
-  DefaultedOuter o = getDefaultedOuter(str); // expected-warning {{address of stack memory is returned later}}
-  DefaultedOuter copy = o;
+  DefaultedOuter o = getDefaultedOuter(str); // expected-warning {{address of stack memory is returned later}} \
+                                             // expected-note {{function call result aliases the storage of variable 'str'}} \
+                                             // expected-note {{variable 'o' aliases the storage of variable 'str'}}
+  DefaultedOuter copy = o;                   // expected-note {{variable 'copy' aliases the storage of variable 'str'}}
   return copy; // expected-note {{returned here}}
 }
 
@@ -2596,8 +2685,11 @@ void owner_return_unique_ptr_s() {
 std::string_view return_dangling_view_through_owner() {
   std::string local;
   auto ups = getUniqueS(local);
-  S* s = ups.get(); // expected-warning {{address of stack memory is returned later}}
-  std::string_view sv = s->getData();
+  S* s = ups.get(); // expected-warning {{address of stack memory is returned later}} \
+                    // expected-note {{function call result aliases the storage of variable 'ups'}} \
+                    // expected-note {{variable 's' aliases the storage of variable 'ups'}}
+  std::string_view sv = s->getData(); // expected-note {{function call result aliases the storage of variable 'ups'}} \
+                                      // expected-note {{variable 'sv' aliases the storage of variable 'ups'}}
   return sv; // expected-note {{returned here}}
 }
 

>From 3645ba877fda214d566521e4043907d10362c924 Mon Sep 17 00:00:00 2001
From: suoyuan666 <suoyuan666 at s5n.xyz>
Date: Wed, 1 Apr 2026 21:23:01 +0800
Subject: [PATCH 07/12] [LifetimeSafety] using AssignmentQuery in
 reportDanglingGlobal

Signed-off-by: suoyuan666 <suoyuan666 at s5n.xyz>
---
 .../Analyses/LifetimeSafety/AssignmentQuery.h |  3 +-
 .../Analysis/Analyses/LifetimeSafety/Facts.h  | 10 ++++++
 .../Analyses/LifetimeSafety/LifetimeSafety.h  |  9 ++---
 .../LifetimeSafety/AssignmentQuery.cpp        | 12 +++----
 clang/lib/Analysis/LifetimeSafety/Checker.cpp | 35 ++++++++++++++-----
 clang/lib/Sema/SemaLifetimeSafety.h           | 14 +++++---
 .../warn-lifetime-safety-dangling-global.cpp  | 13 ++++---
 7 files changed, 66 insertions(+), 30 deletions(-)

diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/AssignmentQuery.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/AssignmentQuery.h
index b0f99a8b094ce..097beb1682bab 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/AssignmentQuery.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/AssignmentQuery.h
@@ -72,7 +72,8 @@ struct AssignmentQueryContext {
 /// address originated.
 std::optional<llvm::SmallVector<AssignmentPair>>
 getAliasList(const AssignmentQueryContext &Context, const Fact *CausingFact,
-             const LoanID End, const Expr *IssueExpr);
+             const LoanID End, const CFGBlock *StartBlock,
+             const Expr *IssueExpr);
 } // namespace clang::lifetimes::internal
 
 #endif
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h
index e852f66a3fde2..f0c6152f321e1 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h
@@ -325,6 +325,16 @@ class FactManager {
     return BlockToFacts[B->getBlockID()];
   }
 
+  std::optional<size_t> getBlockID(const Fact *TargetFact) const {
+    for (size_t i = 0; i < BlockToFacts.size(); ++i) {
+      for (const auto &F : BlockToFacts[i]) {
+        if (F == TargetFact)
+          return i;
+      }
+    }
+    return std::nullopt;
+  }
+
   void addBlockFacts(const CFGBlock *B, llvm::ArrayRef<Fact *> NewFacts) {
     if (!NewFacts.empty())
       BlockToFacts[B->getBlockID()].assign(NewFacts.begin(), NewFacts.end());
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
index d2dca84d2408a..32f1607327af7 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
@@ -76,10 +76,11 @@ class LifetimeSafetySemaHelper {
                                    const Expr *MovedExpr,
                                    SourceLocation ExpiryLoc) {}
 
-  virtual void reportDanglingGlobal(const Expr *IssueExpr,
-                                    const VarDecl *DanglingGlobal,
-                                    const Expr *MovedExpr,
-                                    SourceLocation ExpiryLoc) {}
+  virtual void reportDanglingGlobal(
+      const Expr *IssueExpr, const VarDecl *DanglingGlobal,
+      const Expr *MovedExpr,
+      const std::optional<llvm::SmallVector<AssignmentPair>> AliasList,
+      SourceLocation ExpiryLoc) {}
 
   // Reports when a reference/iterator is used after the container operation
   // that invalidated it.
diff --git a/clang/lib/Analysis/LifetimeSafety/AssignmentQuery.cpp b/clang/lib/Analysis/LifetimeSafety/AssignmentQuery.cpp
index 33ae7b45ea5fa..f3e007b375de1 100644
--- a/clang/lib/Analysis/LifetimeSafety/AssignmentQuery.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/AssignmentQuery.cpp
@@ -286,27 +286,25 @@ namespace clang::lifetimes::internal {
 
 std::optional<llvm::SmallVector<AssignmentPair>>
 getAliasList(const AssignmentQueryContext &Context, const Fact *CausingFact,
-             const LoanID End, const Expr *IssueExpr) {
+             const LoanID End, const CFGBlock *StartBlock,
+             const Expr *IssueExpr) {
   llvm::SmallVector<OriginID, 4> TargetOIDList;
-  const Expr *WarnningFact = nullptr;
 
   if (const auto *UF = llvm::dyn_cast<UseFact>(CausingFact)) {
-    WarnningFact = UF->getUseExpr();
     for (const OriginList *Cur = UF->getUsedOrigins(); Cur;
          Cur = Cur->peelOuterOrigin())
       TargetOIDList.push_back(Cur->getOuterOriginID());
   } else if (const auto *RetEscapeF =
                  llvm::dyn_cast<ReturnEscapeFact>(CausingFact)) {
-    WarnningFact = RetEscapeF->getReturnExpr();
     TargetOIDList.push_back(RetEscapeF->getEscapedOriginID());
+  } else if (const auto *GlobalEscapeF =
+                 llvm::dyn_cast<GlobalEscapeFact>(CausingFact)) {
+    TargetOIDList.push_back(GlobalEscapeF->getEscapedOriginID());
   } else {
     llvm_unreachable("Without a corresponding Fact handler, assignment history "
                      "traceback will fail.");
   }
 
-  const CFGBlock *StartBlock =
-      Context.ADC.getCFGStmtMap()->getBlock(WarnningFact);
-  assert(StartBlock && "Searching CFGBlock failed");
   const CFGBlock *EndBlock = Context.ADC.getCFGStmtMap()->getBlock(IssueExpr);
   assert(EndBlock && "Searching CFGBlock failed");
 
diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
index fcc3dbd6130b3..ca6fc8138abc3 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -22,6 +22,7 @@
 #include "clang/Analysis/Analyses/LifetimeSafety/Loans.h"
 #include "clang/Analysis/Analyses/PostOrderCFGView.h"
 #include "clang/Analysis/AnalysisDeclContext.h"
+#include "clang/Analysis/CFG.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Basic/SourceManager.h"
 #include "llvm/ADT/DenseMap.h"
@@ -47,6 +48,7 @@ namespace {
 struct PendingWarning {
   SourceLocation ExpiryLoc; // Where the loan expired.
   llvm::PointerUnion<const UseFact *, const OriginEscapesFact *> CausingFact;
+  const ExpireFact *ExpiryExpr;
   const Expr *MovedExpr;
   const Expr *InvalidatedByExpr;
   bool CausingFactDominatesExpiry;
@@ -174,6 +176,7 @@ class LifetimeChecker {
           continue;
         if (causingFactDominatesExpiry(LiveInfo.Kind))
           CurWarning.CausingFactDominatesExpiry = true;
+        CurWarning.ExpiryExpr = EF;
         CurWarning.CausingFact = LiveInfo.CausingFact;
         CurWarning.ExpiryLoc = EF->getExpiryLoc();
         CurWarning.MovedExpr = MovedExpr;
@@ -213,6 +216,7 @@ class LifetimeChecker {
             FinalWarningsMap[LiveLoanID] = {
                 /*ExpiryLoc=*/{},
                 /*CausingFact=*/LiveInfo.CausingFact,
+                /*ExpiryExpr=*/nullptr,
                 /*MovedExpr=*/nullptr,
                 /*InvalidatedByExpr=*/IOF->getInvalidationExpr(),
                 /*CausingFactDominatesExpiry=*/CurDomination};
@@ -233,6 +237,8 @@ class LifetimeChecker {
           L->getAccessPath().getAsPlaceholderParam();
       const Expr *MovedExpr = Warning.MovedExpr;
       SourceLocation ExpiryLoc = Warning.ExpiryLoc;
+      const struct AssignmentQueryContext Context = {
+          LoanPropagation, MovedLoans, LiveOrigins, FactMgr, ADC};
 
       if (const auto *UF = CausingFact.dyn_cast<const UseFact *>()) {
         if (Warning.InvalidatedByExpr) {
@@ -247,19 +253,20 @@ class LifetimeChecker {
 
         } else {
           // Scope-based expiry (use-after-scope).
-          const struct AssignmentQueryContext Context = {
-              LoanPropagation, MovedLoans, LiveOrigins, FactMgr, ADC};
-          const auto AliasExprs = getAliasList(Context, UF, LID, IssueExpr);
+          const auto *StartBlock =
+              ADC.getCFGStmtMap()->getBlock(UF->getUseExpr());
+          const auto AliasExprs =
+              getAliasList(Context, UF, LID, StartBlock, IssueExpr);
           SemaHelper->reportUseAfterFree(IssueExpr, UF->getUseExpr(), MovedExpr,
                                          AliasExprs, ExpiryLoc);
         }
       } else if (const auto *OEF =
                      CausingFact.dyn_cast<const OriginEscapesFact *>()) {
         if (const auto *RetEscape = dyn_cast<ReturnEscapeFact>(OEF)) {
-          const struct AssignmentQueryContext Context = {
-              LoanPropagation, MovedLoans, LiveOrigins, FactMgr, ADC};
+          const auto *StartBlock =
+              ADC.getCFGStmtMap()->getBlock(RetEscape->getReturnExpr());
           const auto AliasExprs =
-              getAliasList(Context, RetEscape, LID, IssueExpr);
+              getAliasList(Context, RetEscape, LID, StartBlock, IssueExpr);
           SemaHelper->reportUseAfterReturn(IssueExpr,
                                            RetEscape->getReturnExpr(),
                                            MovedExpr, AliasExprs, ExpiryLoc);
@@ -267,11 +274,21 @@ class LifetimeChecker {
           // Dangling field.
           SemaHelper->reportDanglingField(
               IssueExpr, FieldEscape->getFieldDecl(), MovedExpr, ExpiryLoc);
-        else if (const auto *GlobalEscape = dyn_cast<GlobalEscapeFact>(OEF))
+        else if (const auto *GlobalEscape = dyn_cast<GlobalEscapeFact>(OEF)) {
           // Global escape.
+          const auto BlockID = FactMgr.getBlockID(Warning.ExpiryExpr).value();
+          const CFGBlock *StartBlock = nullptr;
+          for (auto *const CFGBlock : *ADC.getCFG()) {
+            if (CFGBlock->getBlockID() == BlockID) {
+              StartBlock = CFGBlock;
+              break;
+            }
+          }
+          const auto AliasExprs =
+              getAliasList(Context, GlobalEscape, LID, StartBlock, IssueExpr);
           SemaHelper->reportDanglingGlobal(IssueExpr, GlobalEscape->getGlobal(),
-                                           MovedExpr, ExpiryLoc);
-        else
+                                           MovedExpr, AliasExprs, ExpiryLoc);
+        } else
           llvm_unreachable("Unhandled OriginEscapesFact type");
       } else
         llvm_unreachable("Unhandled CausingFact type");
diff --git a/clang/lib/Sema/SemaLifetimeSafety.h b/clang/lib/Sema/SemaLifetimeSafety.h
index cf75ff27082d4..89cf0a2f3c0fc 100644
--- a/clang/lib/Sema/SemaLifetimeSafety.h
+++ b/clang/lib/Sema/SemaLifetimeSafety.h
@@ -131,10 +131,11 @@ class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper {
         << DanglingField->getEndLoc();
   }
 
-  void reportDanglingGlobal(const Expr *IssueExpr,
-                            const VarDecl *DanglingGlobal,
-                            const Expr *MovedExpr,
-                            SourceLocation ExpiryLoc) override {
+  void reportDanglingGlobal(
+      const Expr *IssueExpr, const VarDecl *DanglingGlobal,
+      const Expr *MovedExpr,
+      const std::optional<llvm::SmallVector<AssignmentPair>> AliasList,
+      SourceLocation ExpiryLoc) override {
     S.Diag(IssueExpr->getExprLoc(),
            MovedExpr ? diag::warn_lifetime_safety_dangling_global_moved
                      : diag::warn_lifetime_safety_dangling_global)
@@ -142,6 +143,11 @@ class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper {
     if (MovedExpr)
       S.Diag(MovedExpr->getExprLoc(), diag::note_lifetime_safety_moved_here)
           << MovedExpr->getSourceRange();
+
+    if (AliasList.has_value())
+      for (const auto &AliasStmt : llvm::reverse(AliasList.value()))
+        reportAssignment(S, IssueExpr, AliasStmt.first, AliasStmt.second);
+
     if (DanglingGlobal->isStaticLocal() || DanglingGlobal->isStaticDataMember())
       S.Diag(DanglingGlobal->getLocation(),
              diag::note_lifetime_safety_dangling_static_here)
diff --git a/clang/test/Sema/warn-lifetime-safety-dangling-global.cpp b/clang/test/Sema/warn-lifetime-safety-dangling-global.cpp
index ac40c7df5a8f5..98b627c96641b 100644
--- a/clang/test/Sema/warn-lifetime-safety-dangling-global.cpp
+++ b/clang/test/Sema/warn-lifetime-safety-dangling-global.cpp
@@ -22,14 +22,16 @@ void invoke_function_with_side_effects() {
 // We can however catch the inlined one of course!
 void inlined() {
   int local;
-  global = &local; // expected-warning {{address of stack memory escapes to global or static storage}}
-  global_backup = global; 
+  global = &local; // expected-warning {{address of stack memory escapes to global or static storage}} \
+                   // expected-note {{variable 'global' aliases the storage of variable 'local'}}
+  global_backup = global; // expected-note {{variable 'global_backup' aliases the storage of variable 'local'}}
   global = nullptr;
 }
 
 void store_local_in_global() {
   int local;
-  global = &local; // expected-warning {{address of stack memory escapes to global or static storage}}
+  global = &local; // expected-warning {{address of stack memory escapes to global or static storage}} \
+                   // expected-note {{variable 'global' aliases the storage of variable 'local'}}
 }
 
 void store_then_clear() {
@@ -40,5 +42,6 @@ void store_then_clear() {
 
 void dangling_static_field() {
   int local;
-  ObjWithStaticField::static_field = &local; // expected-warning {{address of stack memory escapes to global or static storage}}
-}
\ No newline at end of file
+  ObjWithStaticField::static_field = &local; // expected-warning {{address of stack memory escapes to global or static storage}} \
+                                             // expected-note {{variable 'static_field' aliases the storage of variable 'local'}}
+}

>From 9692b224415f3bba98525665f2d84de7e04c1a28 Mon Sep 17 00:00:00 2001
From: suoyuan666 <suoyuan666 at s5n.xyz>
Date: Thu, 2 Apr 2026 20:24:19 +0800
Subject: [PATCH 08/12] [LifetimeSafety] using AssignmentQuery in
 reportDanglingField

Signed-off-by: suoyuan666 <suoyuan666 at s5n.xyz>
---
 .../Analyses/LifetimeSafety/AssignmentQuery.h |  3 +-
 .../Analyses/LifetimeSafety/LifetimeSafety.h  |  8 ++--
 .../LifetimeSafety/AssignmentQuery.cpp        | 36 ++++++++++++++-
 clang/lib/Analysis/LifetimeSafety/Checker.cpp | 19 ++++++--
 clang/lib/Sema/SemaLifetimeSafety.h           | 18 ++++++--
 .../warn-lifetime-safety-dangling-field.cpp   | 45 +++++++++++++------
 6 files changed, 101 insertions(+), 28 deletions(-)

diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/AssignmentQuery.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/AssignmentQuery.h
index 097beb1682bab..6824081fd458b 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/AssignmentQuery.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/AssignmentQuery.h
@@ -25,7 +25,8 @@
 namespace clang::lifetimes {
 
 using OriginDestExpr =
-    llvm::PointerUnion<const DeclRefExpr *, const ValueDecl *>;
+    llvm::PointerUnion<const DeclRefExpr *, const ValueDecl *,
+                       const MemberExpr *>;
 
 using AssignmentPair = std::pair<OriginDestExpr, const Expr *>;
 
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
index 32f1607327af7..5e4cc558258c4 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
@@ -71,10 +71,10 @@ class LifetimeSafetySemaHelper {
       const std::optional<llvm::SmallVector<AssignmentPair>> AliasList,
       SourceLocation ExpiryLoc) {}
 
-  virtual void reportDanglingField(const Expr *IssueExpr,
-                                   const FieldDecl *Field,
-                                   const Expr *MovedExpr,
-                                   SourceLocation ExpiryLoc) {}
+  virtual void reportDanglingField(
+      const Expr *IssueExpr, const FieldDecl *Field, const Expr *MovedExpr,
+      const std::optional<llvm::SmallVector<AssignmentPair>> AliasList,
+      SourceLocation ExpiryLoc) {}
 
   virtual void reportDanglingGlobal(
       const Expr *IssueExpr, const VarDecl *DanglingGlobal,
diff --git a/clang/lib/Analysis/LifetimeSafety/AssignmentQuery.cpp b/clang/lib/Analysis/LifetimeSafety/AssignmentQuery.cpp
index f3e007b375de1..85fa25fb49784 100644
--- a/clang/lib/Analysis/LifetimeSafety/AssignmentQuery.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/AssignmentQuery.cpp
@@ -13,6 +13,7 @@
 
 #include "clang/Analysis/Analyses/LifetimeSafety/AssignmentQuery.h"
 #include "clang/AST/Decl.h"
+#include "clang/AST/ParentMap.h"
 #include "clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h"
 #include "clang/Analysis/Analyses/LifetimeSafety/Origins.h"
 #include "clang/Analysis/AnalysisDeclContext.h"
@@ -54,6 +55,25 @@ std::optional<const Expr *> GetPureSrcExpr(const Expr *TargetExpr) {
   return std::nullopt;
 }
 
+/// Specifically handles assignments involving a FieldDecl.
+///
+/// Since we currently only store the FieldDecl without its corresponding
+/// LHS expression, this function attempts to recover or resolve the LHS
+/// context by analyzing the RHS.
+const MemberExpr *getFieldFromAssignmentExpr(const Expr *RHS,
+                                             const ParentMap &CurrParentMap) {
+
+  const Stmt *CurrStmt = CurrParentMap.getParent(RHS);
+  if (!CurrStmt)
+    return nullptr;
+  if (const auto *BinaryOp = llvm::dyn_cast<BinaryOperator>(CurrStmt))
+    return llvm::dyn_cast<MemberExpr>(BinaryOp->getLHS());
+  if (const auto *CXXOp = llvm::dyn_cast<CXXOperatorCallExpr>(CurrStmt);
+      CXXOp && CXXOp->getOperator() == OO_Equal && CXXOp->getNumArgs() == 2)
+    return llvm::dyn_cast<MemberExpr>(CXXOp->getArg(0));
+  return nullptr;
+}
+
 AliasAssignmentSearchResult getAliasListCore(
     const AssignmentQueryContext &Context, const CFGBlock *Block,
     const LoanID EndLoanID, OriginID *TargetOID,
@@ -84,8 +104,17 @@ AliasAssignmentSearchResult getAliasListCore(
           if (!DestDecl.has_value()) {
             if (const ValueDecl *DVecl = TargetOrigin.getDecl();
                 DVecl && !DVecl->getLocation().isInvalid()) {
-              CurrOrigin = *TargetOID;
-              DestDecl = DVecl;
+              if (llvm::isa<FieldDecl>(DVecl)) {
+                const auto *CurrExpr = Context.FactMgr.getOriginMgr()
+                                           .getOrigin(OFF->getSrcOriginID())
+                                           .getExpr();
+                if (CurrExpr)
+                  DestDecl = getFieldFromAssignmentExpr(
+                      CurrExpr, Context.ADC.getParentMap());
+              } else {
+                CurrOrigin = *TargetOID;
+                DestDecl = DVecl;
+              }
             }
           } else {
             auto SExpr = GetPureSrcExpr(TargetOrigin.getExpr());
@@ -297,6 +326,9 @@ getAliasList(const AssignmentQueryContext &Context, const Fact *CausingFact,
   } else if (const auto *RetEscapeF =
                  llvm::dyn_cast<ReturnEscapeFact>(CausingFact)) {
     TargetOIDList.push_back(RetEscapeF->getEscapedOriginID());
+  } else if (const auto *FieldEscapeF =
+                 llvm::dyn_cast<FieldEscapeFact>(CausingFact)) {
+    TargetOIDList.push_back(FieldEscapeF->getEscapedOriginID());
   } else if (const auto *GlobalEscapeF =
                  llvm::dyn_cast<GlobalEscapeFact>(CausingFact)) {
     TargetOIDList.push_back(GlobalEscapeF->getEscapedOriginID());
diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
index ca6fc8138abc3..d6dc29e319a17 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -270,11 +270,22 @@ class LifetimeChecker {
           SemaHelper->reportUseAfterReturn(IssueExpr,
                                            RetEscape->getReturnExpr(),
                                            MovedExpr, AliasExprs, ExpiryLoc);
-        } else if (const auto *FieldEscape = dyn_cast<FieldEscapeFact>(OEF))
+        } else if (const auto *FieldEscape = dyn_cast<FieldEscapeFact>(OEF)) {
           // Dangling field.
-          SemaHelper->reportDanglingField(
-              IssueExpr, FieldEscape->getFieldDecl(), MovedExpr, ExpiryLoc);
-        else if (const auto *GlobalEscape = dyn_cast<GlobalEscapeFact>(OEF)) {
+          const auto BlockID = FactMgr.getBlockID(Warning.ExpiryExpr).value();
+          const CFGBlock *StartBlock = nullptr;
+          for (auto *const CFGBlock : *ADC.getCFG()) {
+            if (CFGBlock->getBlockID() == BlockID) {
+              StartBlock = CFGBlock;
+              break;
+            }
+          }
+          const auto AliasExprs =
+              getAliasList(Context, FieldEscape, LID, StartBlock, IssueExpr);
+          SemaHelper->reportDanglingField(IssueExpr,
+                                          FieldEscape->getFieldDecl(),
+                                          MovedExpr, AliasExprs, ExpiryLoc);
+        } else if (const auto *GlobalEscape = dyn_cast<GlobalEscapeFact>(OEF)) {
           // Global escape.
           const auto BlockID = FactMgr.getBlockID(Warning.ExpiryExpr).value();
           const CFGBlock *StartBlock = nullptr;
diff --git a/clang/lib/Sema/SemaLifetimeSafety.h b/clang/lib/Sema/SemaLifetimeSafety.h
index 89cf0a2f3c0fc..24de0e9d92516 100644
--- a/clang/lib/Sema/SemaLifetimeSafety.h
+++ b/clang/lib/Sema/SemaLifetimeSafety.h
@@ -66,6 +66,10 @@ inline void reportAssignment(Sema &S, const Expr *IssueExpr,
                          LDExpr->getExprLoc());
   } else if (const ValueDecl *LVDecl = llvm::dyn_cast<const ValueDecl *>(LHS)) {
     reportAssignmentImpl(S, IssueExpr, LVDecl, RHS, LVDecl->getLocation());
+  } else if (const MemberExpr *LVDecl =
+                 llvm::dyn_cast<const MemberExpr *>(LHS)) {
+    reportAssignmentImpl(S, IssueExpr, LVDecl->getMemberDecl(), RHS,
+                         LVDecl->getExprLoc());
   }
 }
 
@@ -115,10 +119,11 @@ class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper {
         << ReturnExpr->getSourceRange();
   }
 
-  void reportDanglingField(const Expr *IssueExpr,
-                           const FieldDecl *DanglingField,
-                           const Expr *MovedExpr,
-                           SourceLocation ExpiryLoc) override {
+  void reportDanglingField(
+      const Expr *IssueExpr, const FieldDecl *DanglingField,
+      const Expr *MovedExpr,
+      const std::optional<llvm::SmallVector<AssignmentPair>> AliasList,
+      SourceLocation ExpiryLoc) override {
     S.Diag(IssueExpr->getExprLoc(),
            MovedExpr ? diag::warn_lifetime_safety_dangling_field_moved
                      : diag::warn_lifetime_safety_dangling_field)
@@ -126,6 +131,11 @@ class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper {
     if (MovedExpr)
       S.Diag(MovedExpr->getExprLoc(), diag::note_lifetime_safety_moved_here)
           << MovedExpr->getSourceRange();
+
+    if (AliasList.has_value())
+      for (const auto &AliasStmt : llvm::reverse(AliasList.value()))
+        reportAssignment(S, IssueExpr, AliasStmt.first, AliasStmt.second);
+
     S.Diag(DanglingField->getLocation(),
            diag::note_lifetime_safety_dangling_field_here)
         << DanglingField->getEndLoc();
diff --git a/clang/test/Sema/warn-lifetime-safety-dangling-field.cpp b/clang/test/Sema/warn-lifetime-safety-dangling-field.cpp
index fa45458371012..e8f08775c9749 100644
--- a/clang/test/Sema/warn-lifetime-safety-dangling-field.cpp
+++ b/clang/test/Sema/warn-lifetime-safety-dangling-field.cpp
@@ -15,7 +15,8 @@ struct CtorInit {
 
 struct CtorSet {
   std::string_view view;  // expected-note {{this field dangles}}
-  CtorSet(std::string s) { view = s; } // expected-warning {{address of stack memory escapes to a field}}
+  CtorSet(std::string s) { view = s; } // expected-warning {{address of stack memory escapes to a field}} \
+                                       // expected-note {{variable 'view' aliases the storage of variable 's'}}
 };
 
 struct CtorInitLifetimeBound {
@@ -80,13 +81,19 @@ struct MemberSetters {
   const char* p;          // expected-note 6 {{this field dangles}}
 
   void setWithParam(std::string s) {
-    view = s;     // expected-warning {{address of stack memory escapes to a field}}
-    p = s.data(); // expected-warning {{address of stack memory escapes to a field}}
+    view = s;     // expected-warning {{address of stack memory escapes to a field}} \
+                  // expected-note {{variable 'view' aliases the storage of variable 's'}}
+    p = s.data(); // expected-warning {{address of stack memory escapes to a field}} \
+                  // expected-note {{function call result aliases the storage of variable 's'}} \
+                  // expected-note {{variable 'p' aliases the storage of variable 's'}}
   }
 
   void setWithParamAndReturn(std::string s) {
-    view = s;     // expected-warning {{address of stack memory escapes to a field}}
-    p = s.data(); // expected-warning {{address of stack memory escapes to a field}}
+    view = s;     // expected-warning {{address of stack memory escapes to a field}} \
+                  // expected-note {{variable 'view' aliases the storage of variable 's'}}
+    p = s.data(); // expected-warning {{address of stack memory escapes to a field}} \
+                  // expected-note {{function call result aliases the storage of variable 's'}} \
+                  // expected-note {{variable 'p' aliases the storage of variable 's'}}
     return;
   }
 
@@ -103,14 +110,20 @@ struct MemberSetters {
 
   void setWithLocal() {
     std::string s;
-    view = s;     // expected-warning {{address of stack memory escapes to a field}}
-    p = s.data(); // expected-warning {{address of stack memory escapes to a field}}
+    view = s;     // expected-warning {{address of stack memory escapes to a field}} \
+                  // expected-note {{variable 'view' aliases the storage of variable 's'}}
+    p = s.data(); // expected-warning {{address of stack memory escapes to a field}} \
+                  // expected-note {{function call result aliases the storage of variable 's'}} \
+                  // expected-note {{variable 'p' aliases the storage of variable 's'}}
   }
   
   void setWithLocalButMoved() {
     std::string s;
-    view = s;                 // expected-warning-re {{address of stack memory escapes to a field. {{.*}} may have been moved}}
-    p = s.data();             // expected-warning-re {{address of stack memory escapes to a field. {{.*}} may have been moved}}
+    view = s;                 // expected-warning-re {{address of stack memory escapes to a field. {{.*}} may have been moved}} \
+                              // expected-note {{variable 'view' aliases the storage of variable 's'}}
+    p = s.data();             // expected-warning-re {{address of stack memory escapes to a field. {{.*}} may have been moved}} \
+                              // expected-note {{function call result aliases the storage of variable 's'}} \
+                              // expected-note {{variable 'p' aliases the storage of variable 's'}}
     takeString(std::move(s)); // expected-note 2 {{potentially moved here}}
   }
 
@@ -133,15 +146,21 @@ struct MemberSetters {
     p = kGlobal.data();
 
     std::string local;
-    view = local;     // expected-warning {{address of stack memory escapes to a field}}
-    p = local.data(); // expected-warning {{address of stack memory escapes to a field}}
+    view = local;     // expected-warning {{address of stack memory escapes to a field}} \
+                      // expected-note {{variable 'view' aliases the storage of variable 'local'}}
+    p = local.data(); // expected-warning {{address of stack memory escapes to a field}} \
+                      // expected-note {{function call result aliases the storage of variable 'local'}} \
+                      // expected-note {{variable 'p' aliases the storage of variable 'local'}}
   }
 
   void use_after_scope() {
     {
       std::string local;
-      view = local;     // expected-warning {{address of stack memory escapes to a field}}
-      p = local.data(); // expected-warning {{address of stack memory escapes to a field}}
+      view = local;     // expected-warning {{address of stack memory escapes to a field}} \
+                        // expected-note {{variable 'view' aliases the storage of variable 'local'}}
+      p = local.data(); // expected-warning {{address of stack memory escapes to a field}} \
+                        // expected-note {{function call result aliases the storage of variable 'local'}} \
+                        // expected-note {{variable 'p' aliases the storage of variable 'local'}}
     }
     (void)view;
     (void)p;

>From 369d7b8468699c39f1e38a0016e451a69e3c74fe Mon Sep 17 00:00:00 2001
From: suoyuan666 <suoyuan666 at s5n.xyz>
Date: Fri, 3 Apr 2026 11:23:01 +0800
Subject: [PATCH 09/12] [LifetimeSafety] using AssignmentQuery in
 suggestWithScopeForParmVar

Signed-off-by: suoyuan666 <suoyuan666 at s5n.xyz>
---
 .../Analyses/LifetimeSafety/AssignmentQuery.h |  3 +-
 .../Analyses/LifetimeSafety/LifetimeSafety.h  |  7 ++-
 .../LifetimeSafety/AssignmentQuery.cpp        | 29 ++++++----
 clang/lib/Analysis/LifetimeSafety/Checker.cpp | 57 +++++++++++++------
 clang/lib/Sema/SemaLifetimeSafety.h           | 27 +++++----
 .../Sema/warn-lifetime-safety-suggestions.cpp |  6 +-
 6 files changed, 85 insertions(+), 44 deletions(-)

diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/AssignmentQuery.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/AssignmentQuery.h
index 6824081fd458b..6ebea68a8a427 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/AssignmentQuery.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/AssignmentQuery.h
@@ -27,6 +27,7 @@ namespace clang::lifetimes {
 using OriginDestExpr =
     llvm::PointerUnion<const DeclRefExpr *, const ValueDecl *,
                        const MemberExpr *>;
+using LoanEntity = llvm::PointerUnion<const Expr *, const ParmVarDecl *>;
 
 using AssignmentPair = std::pair<OriginDestExpr, const Expr *>;
 
@@ -35,7 +36,7 @@ struct ExprPrintingResult {
   const Expr *CurrExpr;
 };
 
-ExprPrintingResult FormatIssueExprForSema(const Expr *IssueExpr);
+llvm::SmallString<32> FormatLoanEntityForSema(LoanEntity IssueEntity);
 llvm::SmallVector<ExprPrintingResult> FormatSrcExprForSema(const Expr *SrcExpr);
 
 inline __attribute__((always_inline)) llvm::SmallString<32>
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
index 5e4cc558258c4..7ce366f6fba35 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
@@ -92,9 +92,10 @@ class LifetimeSafetySemaHelper {
                                           const Expr *InvalidationExpr) {}
 
   // Suggests lifetime bound annotations for function paramters.
-  virtual void suggestLifetimeboundToParmVar(SuggestionScope Scope,
-                                             const ParmVarDecl *ParmToAnnotate,
-                                             const Expr *EscapeExpr) {}
+  virtual void suggestLifetimeboundToParmVar(
+      SuggestionScope Scope, const ParmVarDecl *ParmToAnnotate,
+      const std::optional<llvm::SmallVector<AssignmentPair>> AliasList,
+      const Expr *EscapeExpr) {}
 
   // Reports misuse of [[clang::noescape]] when parameter escapes through return
   virtual void reportNoescapeViolation(const ParmVarDecl *ParmWithNoescape,
diff --git a/clang/lib/Analysis/LifetimeSafety/AssignmentQuery.cpp b/clang/lib/Analysis/LifetimeSafety/AssignmentQuery.cpp
index 85fa25fb49784..472f7302b6a12 100644
--- a/clang/lib/Analysis/LifetimeSafety/AssignmentQuery.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/AssignmentQuery.cpp
@@ -232,16 +232,25 @@ getAliasListInMultiBlock(const AssignmentQueryContext &Context,
 
 namespace clang::lifetimes {
 
-ExprPrintingResult FormatIssueExprForSema(const Expr *IssueExpr) {
-  if (!IssueExpr)
-    return {};
-  const auto *PureExpr = IssueExpr->IgnoreParenCasts();
-  if (!PureExpr)
+llvm::SmallString<32> FormatLoanEntityForSema(LoanEntity IssueEntity) {
+  if (!IssueEntity)
     return {};
 
-  if (const auto *IDeclExpr = llvm::dyn_cast<DeclRefExpr>(PureExpr))
-    return {FormatValueDeclForSema(IDeclExpr->getDecl()), IssueExpr};
-  return {{"the temporary"}, IssueExpr};
+  if (const auto *IssueExpr = llvm::dyn_cast<const Expr *>(IssueEntity)) {
+    const auto *PureExpr = IssueExpr->IgnoreParenCasts();
+    if (!PureExpr)
+      return {};
+
+    if (const auto *IDeclExpr = llvm::dyn_cast<DeclRefExpr>(PureExpr))
+      return FormatValueDeclForSema(IDeclExpr->getDecl());
+    return {"the temporary"};
+  }
+  if (const auto *IssueParmDecl =
+          llvm::dyn_cast<const ParmVarDecl *>(IssueEntity)) {
+    return FormatValueDeclForSema(IssueParmDecl);
+  }
+
+  return {"the temporary"};
 }
 
 llvm::SmallVector<ExprPrintingResult>
@@ -337,8 +346,8 @@ getAliasList(const AssignmentQueryContext &Context, const Fact *CausingFact,
                      "traceback will fail.");
   }
 
-  const CFGBlock *EndBlock = Context.ADC.getCFGStmtMap()->getBlock(IssueExpr);
-  assert(EndBlock && "Searching CFGBlock failed");
+  const CFGBlock *EndBlock =
+      IssueExpr ? Context.ADC.getCFGStmtMap()->getBlock(IssueExpr) : nullptr;
 
   for (auto TargetOID : TargetOIDList) {
     if (StartBlock == EndBlock) {
diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
index d6dc29e319a17..e11a9573dbcdd 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -62,7 +62,8 @@ using EscapingTarget =
 class LifetimeChecker {
 private:
   llvm::DenseMap<LoanID, PendingWarning> FinalWarningsMap;
-  llvm::DenseMap<AnnotationTarget, const Expr *> AnnotationWarningsMap;
+  llvm::DenseMap<AnnotationTarget, const ReturnEscapeFact *>
+      AnnotationWarningsMap;
   llvm::DenseMap<const ParmVarDecl *, EscapingTarget> NoescapeWarningsMap;
   const LoanPropagationAnalysis &LoanPropagation;
   const MovedLoansAnalysis &MovedLoans;
@@ -132,14 +133,14 @@ class LifetimeChecker {
       // Suggest lifetimebound for parameter escaping through return.
       if (!PVD->hasAttr<LifetimeBoundAttr>())
         if (auto *ReturnEsc = dyn_cast<ReturnEscapeFact>(OEF))
-          AnnotationWarningsMap.try_emplace(PVD, ReturnEsc->getReturnExpr());
+          AnnotationWarningsMap.try_emplace(PVD, ReturnEsc);
       // TODO: Suggest lifetime_capture_by(this) for parameter escaping to a
       // field!
     };
     auto CheckImplicitThis = [&](const CXXMethodDecl *MD) {
       if (!implicitObjectParamIsLifetimeBound(MD))
         if (auto *ReturnEsc = dyn_cast<ReturnEscapeFact>(OEF))
-          AnnotationWarningsMap.try_emplace(MD, ReturnEsc->getReturnExpr());
+          AnnotationWarningsMap.try_emplace(MD, ReturnEsc);
     };
     for (LoanID LID : EscapedLoans) {
       const Loan *L = FactMgr.getLoanMgr().getLoan(LID);
@@ -327,41 +328,63 @@ class LifetimeChecker {
     return nullptr;
   }
 
-  static void suggestWithScopeForParmVar(LifetimeSafetySemaHelper *SemaHelper,
-                                         const ParmVarDecl *PVD,
-                                         SourceManager &SM,
-                                         const Expr *EscapeExpr) {
+  void suggestWithScopeForParmVar(LifetimeSafetySemaHelper *SemaHelper,
+                                  const ParmVarDecl *PVD, SourceManager &SM,
+                                  const ReturnEscapeFact *EscapeFact) {
+    const struct AssignmentQueryContext Context = {LoanPropagation, MovedLoans,
+                                                   LiveOrigins, FactMgr, ADC};
+    const auto *StartBlock =
+        ADC.getCFGStmtMap()->getBlock(EscapeFact->getReturnExpr());
+    std::optional<LoanID> TargetLoanID;
+
+    for (const LoanID &CurrLoanID : LoanPropagation.getLoans(
+             EscapeFact->getEscapedOriginID(), EscapeFact)) {
+      const Loan *CurrLoan = FactMgr.getLoanMgr().getLoan(CurrLoanID);
+      if (CurrLoan->getAccessPath().getAsPlaceholderParam() == PVD) {
+        TargetLoanID = CurrLoanID;
+        break;
+      }
+    }
+
+    const std::optional<llvm::SmallVector<AssignmentPair>> AliasExprs =
+        TargetLoanID.has_value()
+            ? getAliasList(Context, EscapeFact, TargetLoanID.value(),
+                           StartBlock, nullptr)
+            : std::nullopt;
+
     if (const FunctionDecl *CrossTUDecl = getCrossTUDecl(*PVD, SM))
       SemaHelper->suggestLifetimeboundToParmVar(
           SuggestionScope::CrossTU,
-          CrossTUDecl->getParamDecl(PVD->getFunctionScopeIndex()), EscapeExpr);
+          CrossTUDecl->getParamDecl(PVD->getFunctionScopeIndex()), AliasExprs,
+          EscapeFact->getReturnExpr());
     else
       SemaHelper->suggestLifetimeboundToParmVar(SuggestionScope::IntraTU, PVD,
-                                                EscapeExpr);
+                                                AliasExprs,
+                                                EscapeFact->getReturnExpr());
   }
 
   static void
   suggestWithScopeForImplicitThis(LifetimeSafetySemaHelper *SemaHelper,
                                   const CXXMethodDecl *MD, SourceManager &SM,
-                                  const Expr *EscapeExpr) {
+                                  const ReturnEscapeFact *EscapeFact) {
     if (const FunctionDecl *CrossTUDecl = getCrossTUDecl(*MD, SM))
       SemaHelper->suggestLifetimeboundToImplicitThis(
           SuggestionScope::CrossTU, cast<CXXMethodDecl>(CrossTUDecl),
-          EscapeExpr);
+          EscapeFact->getReturnExpr());
     else
-      SemaHelper->suggestLifetimeboundToImplicitThis(SuggestionScope::IntraTU,
-                                                     MD, EscapeExpr);
+      SemaHelper->suggestLifetimeboundToImplicitThis(
+          SuggestionScope::IntraTU, MD, EscapeFact->getReturnExpr());
   }
 
   void suggestAnnotations() {
     if (!SemaHelper)
       return;
     SourceManager &SM = AST.getSourceManager();
-    for (auto [Target, EscapeExpr] : AnnotationWarningsMap) {
+    for (auto [Target, EscapeFact] : AnnotationWarningsMap) {
       if (const auto *PVD = Target.dyn_cast<const ParmVarDecl *>())
-        suggestWithScopeForParmVar(SemaHelper, PVD, SM, EscapeExpr);
+        suggestWithScopeForParmVar(SemaHelper, PVD, SM, EscapeFact);
       else if (const auto *MD = Target.dyn_cast<const CXXMethodDecl *>())
-        suggestWithScopeForImplicitThis(SemaHelper, MD, SM, EscapeExpr);
+        suggestWithScopeForImplicitThis(SemaHelper, MD, SM, EscapeFact);
     }
   }
 
@@ -379,7 +402,7 @@ class LifetimeChecker {
   }
 
   void inferAnnotations() {
-    for (auto [Target, EscapeExpr] : AnnotationWarningsMap) {
+    for (auto [Target, EscapeFact] : AnnotationWarningsMap) {
       if (const auto *MD = Target.dyn_cast<const CXXMethodDecl *>()) {
         if (!implicitObjectParamIsLifetimeBound(MD))
           SemaHelper->addLifetimeBoundToImplicitThis(cast<CXXMethodDecl>(MD));
diff --git a/clang/lib/Sema/SemaLifetimeSafety.h b/clang/lib/Sema/SemaLifetimeSafety.h
index 24de0e9d92516..67f75a98080b3 100644
--- a/clang/lib/Sema/SemaLifetimeSafety.h
+++ b/clang/lib/Sema/SemaLifetimeSafety.h
@@ -38,11 +38,12 @@ inline bool IsLifetimeSafetyDiagnosticEnabled(Sema &S, const Decl *D) {
                           D->getBeginLoc());
 }
 
-inline void reportAssignmentImpl(Sema &S, const Expr *IssueExpr,
+inline void reportAssignmentImpl(Sema &S, LoanEntity IssueEntity,
                                  const ValueDecl *LHS, const Expr *RHS,
                                  const SourceLocation LHSExploc) {
-  const auto [IssueMsg, _] = FormatIssueExprForSema(IssueExpr);
-  const auto SrcMsgList = FormatSrcExprForSema(RHS);
+  const llvm::SmallString<32> IssueMsg = FormatLoanEntityForSema(IssueEntity);
+  const llvm::SmallVector<ExprPrintingResult> SrcMsgList =
+      FormatSrcExprForSema(RHS);
   if (SrcMsgList.size() == 1 &&
       llvm::isa<DeclRefExpr>(SrcMsgList[0].CurrExpr)) {
     S.Diag(LHSExploc, diag::note_lifetime_safety_note_alias_chain)
@@ -56,19 +57,19 @@ inline void reportAssignmentImpl(Sema &S, const Expr *IssueExpr,
   }
 }
 
-inline void reportAssignment(Sema &S, const Expr *IssueExpr,
+inline void reportAssignment(Sema &S, LoanEntity IssueEntity,
                              const OriginDestExpr &LHS, const Expr *RHS) {
   if (!LHS || !RHS)
     return;
 
   if (const DeclRefExpr *LDExpr = llvm::dyn_cast<const DeclRefExpr *>(LHS)) {
-    reportAssignmentImpl(S, IssueExpr, LDExpr->getDecl(), RHS,
+    reportAssignmentImpl(S, IssueEntity, LDExpr->getDecl(), RHS,
                          LDExpr->getExprLoc());
   } else if (const ValueDecl *LVDecl = llvm::dyn_cast<const ValueDecl *>(LHS)) {
-    reportAssignmentImpl(S, IssueExpr, LVDecl, RHS, LVDecl->getLocation());
+    reportAssignmentImpl(S, IssueEntity, LVDecl, RHS, LVDecl->getLocation());
   } else if (const MemberExpr *LVDecl =
                  llvm::dyn_cast<const MemberExpr *>(LHS)) {
-    reportAssignmentImpl(S, IssueExpr, LVDecl->getMemberDecl(), RHS,
+    reportAssignmentImpl(S, IssueEntity, LVDecl->getMemberDecl(), RHS,
                          LVDecl->getExprLoc());
   }
 }
@@ -190,9 +191,10 @@ class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper {
         << UseExpr->getSourceRange();
   }
 
-  void suggestLifetimeboundToParmVar(SuggestionScope Scope,
-                                     const ParmVarDecl *ParmToAnnotate,
-                                     const Expr *EscapeExpr) override {
+  void suggestLifetimeboundToParmVar(
+      SuggestionScope Scope, const ParmVarDecl *ParmToAnnotate,
+      const std::optional<llvm::SmallVector<AssignmentPair>> AliasList,
+      const Expr *EscapeExpr) override {
     unsigned DiagID =
         (Scope == SuggestionScope::CrossTU)
             ? diag::warn_lifetime_safety_cross_tu_param_suggestion
@@ -209,6 +211,11 @@ class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper {
     S.Diag(ParmToAnnotate->getBeginLoc(), DiagID)
         << ParmToAnnotate->getSourceRange()
         << FixItHint::CreateInsertion(InsertionPoint, FixItText);
+
+    if (AliasList.has_value())
+      for (const auto &AliasStmt : llvm::reverse(AliasList.value()))
+        reportAssignment(S, ParmToAnnotate, AliasStmt.first, AliasStmt.second);
+
     S.Diag(EscapeExpr->getBeginLoc(),
            diag::note_lifetime_safety_suggestion_returned_here)
         << EscapeExpr->getSourceRange();
diff --git a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
index 125310fdead8c..cc5db2e02bf1d 100644
--- a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
+++ b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
@@ -79,9 +79,9 @@ View return_view_directly(View a) {
 View conditional_return_view(View a, View b, bool c) {
   View res;
   if (c)  
-    res = a;                    
+    res = a;   // expected-note {{variable 'res' aliases the storage of variable 'a'}}
   else
-    res = b;          
+    res = b;   // expected-note {{variable 'res' aliases the storage of variable 'b'}}
   return res;  // expected-note 2 {{param returned here}} 
 }
 
@@ -171,7 +171,7 @@ View only_one_paramter_annotated(View a [[clang::lifetimebound]],
 View reassigned_to_another_parameter(
     View a,
     View b) {     // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
-  a = b;
+  a = b;          // expected-note {{variable 'a' aliases the storage of variable 'b'}}
   return a;       // expected-note {{param returned here}} 
 }
 

>From 419ef0f7dad916bfe4469c0d986bc40eae765b8b Mon Sep 17 00:00:00 2001
From: suoyuan666 <suoyuan666 at s5n.xyz>
Date: Fri, 3 Apr 2026 11:39:41 +0800
Subject: [PATCH 10/12] using AssignmentQuery in
 suggestWithScopeForImplicitThis

Signed-off-by: suoyuan666 <suoyuan666 at s5n.xyz>
---
 .../Analyses/LifetimeSafety/AssignmentQuery.h |  3 +-
 .../Analyses/LifetimeSafety/LifetimeSafety.h  |  7 ++--
 .../LifetimeSafety/AssignmentQuery.cpp        |  6 ++--
 clang/lib/Analysis/LifetimeSafety/Checker.cpp | 34 +++++++++++++++----
 clang/lib/Sema/SemaLifetimeSafety.h           | 12 +++++--
 5 files changed, 47 insertions(+), 15 deletions(-)

diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/AssignmentQuery.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/AssignmentQuery.h
index 6ebea68a8a427..a68ffe3cc03d3 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/AssignmentQuery.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/AssignmentQuery.h
@@ -27,7 +27,8 @@ namespace clang::lifetimes {
 using OriginDestExpr =
     llvm::PointerUnion<const DeclRefExpr *, const ValueDecl *,
                        const MemberExpr *>;
-using LoanEntity = llvm::PointerUnion<const Expr *, const ParmVarDecl *>;
+using LoanEntity = llvm::PointerUnion<const Expr *, const ParmVarDecl *,
+                                      const CXXMethodDecl *>;
 
 using AssignmentPair = std::pair<OriginDestExpr, const Expr *>;
 
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
index 7ce366f6fba35..d1644fec7f19e 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
@@ -109,9 +109,10 @@ class LifetimeSafetySemaHelper {
                                        const VarDecl *EscapeGlobal) {}
 
   // Suggests lifetime bound annotations for implicit this.
-  virtual void suggestLifetimeboundToImplicitThis(SuggestionScope Scope,
-                                                  const CXXMethodDecl *MD,
-                                                  const Expr *EscapeExpr) {}
+  virtual void suggestLifetimeboundToImplicitThis(
+      SuggestionScope Scope, const CXXMethodDecl *MD,
+      const std::optional<llvm::SmallVector<AssignmentPair>> AliasList,
+      const Expr *EscapeExpr) {}
 
   // Adds inferred lifetime bound attribute for implicit this to its
   // TypeSourceInfo.
diff --git a/clang/lib/Analysis/LifetimeSafety/AssignmentQuery.cpp b/clang/lib/Analysis/LifetimeSafety/AssignmentQuery.cpp
index 472f7302b6a12..894c13556c373 100644
--- a/clang/lib/Analysis/LifetimeSafety/AssignmentQuery.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/AssignmentQuery.cpp
@@ -246,9 +246,11 @@ llvm::SmallString<32> FormatLoanEntityForSema(LoanEntity IssueEntity) {
     return {"the temporary"};
   }
   if (const auto *IssueParmDecl =
-          llvm::dyn_cast<const ParmVarDecl *>(IssueEntity)) {
+          llvm::dyn_cast<const ParmVarDecl *>(IssueEntity))
     return FormatValueDeclForSema(IssueParmDecl);
-  }
+  if (const auto *IssueCXXMD =
+          llvm::dyn_cast<const CXXMethodDecl *>(IssueEntity))
+    return FormatValueDeclForSema(IssueCXXMD);
 
   return {"the temporary"};
 }
diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
index e11a9573dbcdd..f5018722e9978 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -363,17 +363,39 @@ class LifetimeChecker {
                                                 EscapeFact->getReturnExpr());
   }
 
-  static void
-  suggestWithScopeForImplicitThis(LifetimeSafetySemaHelper *SemaHelper,
-                                  const CXXMethodDecl *MD, SourceManager &SM,
-                                  const ReturnEscapeFact *EscapeFact) {
+  void suggestWithScopeForImplicitThis(LifetimeSafetySemaHelper *SemaHelper,
+                                       const CXXMethodDecl *MD,
+                                       SourceManager &SM,
+                                       const ReturnEscapeFact *EscapeFact) {
+    const struct AssignmentQueryContext Context = {LoanPropagation, MovedLoans,
+                                                   LiveOrigins, FactMgr, ADC};
+    const auto *StartBlock =
+        ADC.getCFGStmtMap()->getBlock(EscapeFact->getReturnExpr());
+    std::optional<LoanID> TargetLoanID;
+
+    for (const LoanID &CurrLoanID : LoanPropagation.getLoans(
+             EscapeFact->getEscapedOriginID(), EscapeFact)) {
+      const Loan *CurrLoan = FactMgr.getLoanMgr().getLoan(CurrLoanID);
+      if (CurrLoan->getAccessPath().getAsPlaceholderThis() == MD) {
+        TargetLoanID = CurrLoanID;
+        break;
+      }
+    }
+
+    const std::optional<llvm::SmallVector<AssignmentPair>> AliasExprs =
+        TargetLoanID.has_value()
+            ? getAliasList(Context, EscapeFact, TargetLoanID.value(),
+                           StartBlock, nullptr)
+            : std::nullopt;
+
     if (const FunctionDecl *CrossTUDecl = getCrossTUDecl(*MD, SM))
       SemaHelper->suggestLifetimeboundToImplicitThis(
           SuggestionScope::CrossTU, cast<CXXMethodDecl>(CrossTUDecl),
-          EscapeFact->getReturnExpr());
+          AliasExprs, EscapeFact->getReturnExpr());
     else
       SemaHelper->suggestLifetimeboundToImplicitThis(
-          SuggestionScope::IntraTU, MD, EscapeFact->getReturnExpr());
+          SuggestionScope::IntraTU, MD, AliasExprs,
+          EscapeFact->getReturnExpr());
   }
 
   void suggestAnnotations() {
diff --git a/clang/lib/Sema/SemaLifetimeSafety.h b/clang/lib/Sema/SemaLifetimeSafety.h
index 67f75a98080b3..3598df63c43d7 100644
--- a/clang/lib/Sema/SemaLifetimeSafety.h
+++ b/clang/lib/Sema/SemaLifetimeSafety.h
@@ -221,9 +221,10 @@ class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper {
         << EscapeExpr->getSourceRange();
   }
 
-  void suggestLifetimeboundToImplicitThis(SuggestionScope Scope,
-                                          const CXXMethodDecl *MD,
-                                          const Expr *EscapeExpr) override {
+  void suggestLifetimeboundToImplicitThis(
+      SuggestionScope Scope, const CXXMethodDecl *MD,
+      const std::optional<llvm::SmallVector<AssignmentPair>> AliasList,
+      const Expr *EscapeExpr) override {
     unsigned DiagID = (Scope == SuggestionScope::CrossTU)
                           ? diag::warn_lifetime_safety_cross_tu_this_suggestion
                           : diag::warn_lifetime_safety_intra_tu_this_suggestion;
@@ -249,6 +250,11 @@ class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper {
         << MD->getNameInfo().getSourceRange()
         << FixItHint::CreateInsertion(InsertionPoint,
                                       " [[clang::lifetimebound]]");
+
+    if (AliasList.has_value())
+      for (const auto &AliasStmt : llvm::reverse(AliasList.value()))
+        reportAssignment(S, MD, AliasStmt.first, AliasStmt.second);
+
     S.Diag(EscapeExpr->getBeginLoc(),
            diag::note_lifetime_safety_suggestion_returned_here)
         << EscapeExpr->getSourceRange();

>From 8b41460ceea42d9244f361d7a44efffa20b30406 Mon Sep 17 00:00:00 2001
From: suoyuan666 <suoyuan666 at s5n.xyz>
Date: Fri, 3 Apr 2026 14:09:09 +0800
Subject: [PATCH 11/12] fix test error

Signed-off-by: suoyuan666 <suoyuan666 at s5n.xyz>
---
 clang/test/Sema/warn-lifetime-safety.cpp | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/clang/test/Sema/warn-lifetime-safety.cpp b/clang/test/Sema/warn-lifetime-safety.cpp
index 04ed6835fac7b..9fa7bf9ddddfc 100644
--- a/clang/test/Sema/warn-lifetime-safety.cpp
+++ b/clang/test/Sema/warn-lifetime-safety.cpp
@@ -2329,9 +2329,12 @@ void pointer_arithmetic_use_after_scope() {
   int* p3;
   {
     int a[10]{};
-    p = a + 5;  // expected-warning {{object whose reference is captured does not live long enough}}
-    p2 = a - 5; // expected-warning {{object whose reference is captured does not live long enough}}
-    p3 = 5 + a; // expected-warning {{object whose reference is captured does not live long enough}}
+    p = a + 5;  // expected-warning {{object whose reference is captured does not live long enough}} \
+                // expected-note {{variable 'p' aliases the storage of variable 'a'}}
+    p2 = a - 5; // expected-warning {{object whose reference is captured does not live long enough}} \
+                // expected-note {{variable 'p2' aliases the storage of variable 'a'}}
+    p3 = 5 + a; // expected-warning {{object whose reference is captured does not live long enough}} \
+                // expected-note {{variable 'p3' aliases the storage of variable 'a'}}
   }             // expected-note 3 {{destroyed here}}
   (void)*p;     // expected-note {{later used here}}
   (void)*p2;    // expected-note {{later used here}}

>From 597b57b04e878328fb013404ce55734d0d0370b9 Mon Sep 17 00:00:00 2001
From: suoyuan666 <suoyuan666 at s5n.xyz>
Date: Fri, 3 Apr 2026 14:15:33 +0800
Subject: [PATCH 12/12] fix RHS format error

Signed-off-by: suoyuan666 <suoyuan666 at s5n.xyz>
---
 .../Analyses/LifetimeSafety/AssignmentQuery.h |  11 -
 .../LifetimeSafety/AssignmentQuery.cpp        |  18 +-
 clang/lib/Sema/SemaLifetimeSafety.h           |  15 +-
 .../Sema/warn-lifetime-analysis-nocfg.cpp     |  22 +-
 .../Sema/warn-lifetime-safety-cfg-bailout.cpp |   4 +-
 .../warn-lifetime-safety-dangling-field.cpp   |  38 +-
 .../warn-lifetime-safety-dangling-global.cpp  |   8 +-
 .../Sema/warn-lifetime-safety-suggestions.cpp |   6 +-
 clang/test/Sema/warn-lifetime-safety.cpp      | 550 +++++++++---------
 9 files changed, 342 insertions(+), 330 deletions(-)

diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/AssignmentQuery.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/AssignmentQuery.h
index a68ffe3cc03d3..3af1908662140 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/AssignmentQuery.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/AssignmentQuery.h
@@ -39,17 +39,6 @@ struct ExprPrintingResult {
 
 llvm::SmallString<32> FormatLoanEntityForSema(LoanEntity IssueEntity);
 llvm::SmallVector<ExprPrintingResult> FormatSrcExprForSema(const Expr *SrcExpr);
-
-inline __attribute__((always_inline)) llvm::SmallString<32>
-FormatValueDeclForSema(const ValueDecl *TargetValue) {
-  llvm::SmallString<32> Result;
-  if (TargetValue) {
-    Result += "variable '";
-    Result += TargetValue->getName();
-    Result += "'";
-  }
-  return Result;
-}
 } // namespace clang::lifetimes
 
 namespace clang::lifetimes::internal {
diff --git a/clang/lib/Analysis/LifetimeSafety/AssignmentQuery.cpp b/clang/lib/Analysis/LifetimeSafety/AssignmentQuery.cpp
index 894c13556c373..f685072fb58bf 100644
--- a/clang/lib/Analysis/LifetimeSafety/AssignmentQuery.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/AssignmentQuery.cpp
@@ -228,6 +228,18 @@ getAliasListInMultiBlock(const AssignmentQueryContext &Context,
 
   return std::nullopt;
 }
+
+
+llvm::SmallString<32>
+FormatRHSValueDeclForSema(const ValueDecl *TargetValue) {
+  llvm::SmallString<32> Result;
+  if (TargetValue) {
+    Result += "'";
+    Result += TargetValue->getName();
+    Result += "'";
+  }
+  return Result;
+}
 } // namespace
 
 namespace clang::lifetimes {
@@ -242,15 +254,15 @@ llvm::SmallString<32> FormatLoanEntityForSema(LoanEntity IssueEntity) {
       return {};
 
     if (const auto *IDeclExpr = llvm::dyn_cast<DeclRefExpr>(PureExpr))
-      return FormatValueDeclForSema(IDeclExpr->getDecl());
+      return FormatRHSValueDeclForSema(IDeclExpr->getDecl());
     return {"the temporary"};
   }
   if (const auto *IssueParmDecl =
           llvm::dyn_cast<const ParmVarDecl *>(IssueEntity))
-    return FormatValueDeclForSema(IssueParmDecl);
+    return FormatRHSValueDeclForSema(IssueParmDecl);
   if (const auto *IssueCXXMD =
           llvm::dyn_cast<const CXXMethodDecl *>(IssueEntity))
-    return FormatValueDeclForSema(IssueCXXMD);
+    return FormatRHSValueDeclForSema(IssueCXXMD);
 
   return {"the temporary"};
 }
diff --git a/clang/lib/Sema/SemaLifetimeSafety.h b/clang/lib/Sema/SemaLifetimeSafety.h
index 3598df63c43d7..beac2009feff8 100644
--- a/clang/lib/Sema/SemaLifetimeSafety.h
+++ b/clang/lib/Sema/SemaLifetimeSafety.h
@@ -38,6 +38,17 @@ inline bool IsLifetimeSafetyDiagnosticEnabled(Sema &S, const Decl *D) {
                           D->getBeginLoc());
 }
 
+inline __attribute__((always_inline)) llvm::SmallString<32>
+FormatLHSValueDeclForSema(const ValueDecl *TargetValue) {
+  llvm::SmallString<32> Result;
+  if (TargetValue) {
+    Result += "variable '";
+    Result += TargetValue->getName();
+    Result += "'";
+  }
+  return Result;
+}
+
 inline void reportAssignmentImpl(Sema &S, LoanEntity IssueEntity,
                                  const ValueDecl *LHS, const Expr *RHS,
                                  const SourceLocation LHSExploc) {
@@ -47,13 +58,13 @@ inline void reportAssignmentImpl(Sema &S, LoanEntity IssueEntity,
   if (SrcMsgList.size() == 1 &&
       llvm::isa<DeclRefExpr>(SrcMsgList[0].CurrExpr)) {
     S.Diag(LHSExploc, diag::note_lifetime_safety_note_alias_chain)
-        << FormatValueDeclForSema(LHS) << IssueMsg;
+        << FormatLHSValueDeclForSema(LHS) << IssueMsg;
   } else {
     for (const auto &SrcMsg : llvm::reverse(SrcMsgList))
       S.Diag(RHS->getBeginLoc(), diag::note_lifetime_safety_note_alias_chain)
           << SrcMsg.CurrExpr->getSourceRange() << SrcMsg.Value << IssueMsg;
     S.Diag(LHSExploc, diag::note_lifetime_safety_note_alias_chain)
-        << FormatValueDeclForSema(LHS) << IssueMsg;
+        << FormatLHSValueDeclForSema(LHS) << IssueMsg;
   }
 }
 
diff --git a/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp b/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
index 6042b75f26d4e..ce188f91de7b0 100644
--- a/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
+++ b/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
@@ -368,8 +368,8 @@ int &doNotFollowReferencesForLocalOwner() {
 // Warning caught by CFG analysis.
   std::unique_ptr<int> localOwner;
   int &p = *localOwner // cfg-warning {{address of stack memory is returned later}} \
-                       // cfg-note {{function call result aliases the storage of variable 'localOwner'}} \
-                       // cfg-note {{variable 'p' aliases the storage of variable 'localOwner'}}
+                       // cfg-note {{function call result aliases the storage of 'localOwner'}} \
+                       // cfg-note {{variable 'p' aliases the storage of 'localOwner'}}
             .get();
   return p; // cfg-note {{returned here}}
 }
@@ -1032,8 +1032,8 @@ void test4() {
 namespace range_based_for_loop_variables {
 std::string_view test_view_loop_var(std::vector<std::string> strings) {
   for (std::string_view s : strings) {  // cfg-warning {{address of stack memory is returned later}} \
-                                        // cfg-note {{function call result aliases the storage of variable 'strings'}} \
-                                        // cfg-note {{variable '__begin1' aliases the storage of variable 'strings'}}
+                                        // cfg-note {{function call result aliases the storage of 'strings'}} \
+                                        // cfg-note {{variable '__begin1' aliases the storage of 'strings'}}
     return s; //cfg-note {{returned here}}
   }
   return "";
@@ -1041,8 +1041,8 @@ std::string_view test_view_loop_var(std::vector<std::string> strings) {
 
 const char* test_view_loop_var_with_data(std::vector<std::string> strings) {
   for (std::string_view s : strings) {  // cfg-warning {{address of stack memory is returned later}} \
-                                        // cfg-note {{function call result aliases the storage of variable 'strings'}} \
-                                        // cfg-note {{variable '__begin1' aliases the storage of variable 'strings'}}
+                                        // cfg-note {{function call result aliases the storage of 'strings'}} \
+                                        // cfg-note {{variable '__begin1' aliases the storage of 'strings'}}
     return s.data(); //cfg-note {{returned here}}
   }
   return "";
@@ -1057,8 +1057,8 @@ std::string_view test_no_error_for_views(std::vector<std::string_view> views) {
 
 std::string_view test_string_ref_var(std::vector<std::string> strings) {
   for (const std::string& s : strings) {  // cfg-warning {{address of stack memory is returned later}} \
-                                          // cfg-note {{function call result aliases the storage of variable 'strings'}} \
-                                          // cfg-note {{variable '__begin1' aliases the storage of variable 'strings'}}
+                                          // cfg-note {{function call result aliases the storage of 'strings'}} \
+                                          // cfg-note {{variable '__begin1' aliases the storage of 'strings'}}
     return s; //cfg-note {{returned here}}
   }
   return "";
@@ -1066,9 +1066,9 @@ std::string_view test_string_ref_var(std::vector<std::string> strings) {
 
 std::string_view test_opt_strings(std::optional<std::vector<std::string>> strings_or) {
   for (const std::string& s : *strings_or) {  // cfg-warning {{address of stack memory is returned later}} \
-                                              // cfg-note {{variable '__range1' aliases the storage of variable 'strings_or'}} \
-                                              // cfg-note {{function call result aliases the storage of variable 'strings_or'}} \
-                                              // cfg-note {{variable '__begin1' aliases the storage of variable 'strings_or'}}
+                                              // cfg-note {{variable '__range1' aliases the storage of 'strings_or'}} \
+                                              // cfg-note {{function call result aliases the storage of 'strings_or'}} \
+                                              // cfg-note {{variable '__begin1' aliases the storage of 'strings_or'}}
     return s; //cfg-note {{returned here}}
   }
   return "";
diff --git a/clang/test/Sema/warn-lifetime-safety-cfg-bailout.cpp b/clang/test/Sema/warn-lifetime-safety-cfg-bailout.cpp
index 2b047878b21cb..bf6a1712bc297 100644
--- a/clang/test/Sema/warn-lifetime-safety-cfg-bailout.cpp
+++ b/clang/test/Sema/warn-lifetime-safety-cfg-bailout.cpp
@@ -28,7 +28,7 @@ void single_block_cfg() {
   {
     MyObj s;
     p = &s;     // bailout-warning {{object whose reference is captured does not live long enough}} \
-                // bailout-note {{variable 'p' aliases the storage of variable 's'}}
+                // bailout-note {{variable 'p' aliases the storage of 's'}}
   }             // bailout-note {{destroyed here}}
   (void)*p;     // bailout-note {{later used here}}
 }
@@ -41,7 +41,7 @@ void multiple_block_cfg() {
     if (a > 5) {
       MyObj s;
       p = &s;    // nobailout-warning {{object whose reference is captured does not live long enough}} \
-                 // nobailout-note {{variable 'p' aliases the storage of variable 's'}}
+                 // nobailout-note {{variable 'p' aliases the storage of 's'}}
     } else {     // nobailout-note {{destroyed here}}
       p = &safe;
     }     
diff --git a/clang/test/Sema/warn-lifetime-safety-dangling-field.cpp b/clang/test/Sema/warn-lifetime-safety-dangling-field.cpp
index e8f08775c9749..53969c6c2d798 100644
--- a/clang/test/Sema/warn-lifetime-safety-dangling-field.cpp
+++ b/clang/test/Sema/warn-lifetime-safety-dangling-field.cpp
@@ -16,7 +16,7 @@ struct CtorInit {
 struct CtorSet {
   std::string_view view;  // expected-note {{this field dangles}}
   CtorSet(std::string s) { view = s; } // expected-warning {{address of stack memory escapes to a field}} \
-                                       // expected-note {{variable 'view' aliases the storage of variable 's'}}
+                                       // expected-note {{variable 'view' aliases the storage of 's'}}
 };
 
 struct CtorInitLifetimeBound {
@@ -82,18 +82,18 @@ struct MemberSetters {
 
   void setWithParam(std::string s) {
     view = s;     // expected-warning {{address of stack memory escapes to a field}} \
-                  // expected-note {{variable 'view' aliases the storage of variable 's'}}
+                  // expected-note {{variable 'view' aliases the storage of 's'}}
     p = s.data(); // expected-warning {{address of stack memory escapes to a field}} \
-                  // expected-note {{function call result aliases the storage of variable 's'}} \
-                  // expected-note {{variable 'p' aliases the storage of variable 's'}}
+                  // expected-note {{function call result aliases the storage of 's'}} \
+                  // expected-note {{variable 'p' aliases the storage of 's'}}
   }
 
   void setWithParamAndReturn(std::string s) {
     view = s;     // expected-warning {{address of stack memory escapes to a field}} \
-                  // expected-note {{variable 'view' aliases the storage of variable 's'}}
+                  // expected-note {{variable 'view' aliases the storage of 's'}}
     p = s.data(); // expected-warning {{address of stack memory escapes to a field}} \
-                  // expected-note {{function call result aliases the storage of variable 's'}} \
-                  // expected-note {{variable 'p' aliases the storage of variable 's'}}
+                  // expected-note {{function call result aliases the storage of 's'}} \
+                  // expected-note {{variable 'p' aliases the storage of 's'}}
     return;
   }
 
@@ -111,19 +111,19 @@ struct MemberSetters {
   void setWithLocal() {
     std::string s;
     view = s;     // expected-warning {{address of stack memory escapes to a field}} \
-                  // expected-note {{variable 'view' aliases the storage of variable 's'}}
+                  // expected-note {{variable 'view' aliases the storage of 's'}}
     p = s.data(); // expected-warning {{address of stack memory escapes to a field}} \
-                  // expected-note {{function call result aliases the storage of variable 's'}} \
-                  // expected-note {{variable 'p' aliases the storage of variable 's'}}
+                  // expected-note {{function call result aliases the storage of 's'}} \
+                  // expected-note {{variable 'p' aliases the storage of 's'}}
   }
   
   void setWithLocalButMoved() {
     std::string s;
     view = s;                 // expected-warning-re {{address of stack memory escapes to a field. {{.*}} may have been moved}} \
-                              // expected-note {{variable 'view' aliases the storage of variable 's'}}
+                              // expected-note {{variable 'view' aliases the storage of 's'}}
     p = s.data();             // expected-warning-re {{address of stack memory escapes to a field. {{.*}} may have been moved}} \
-                              // expected-note {{function call result aliases the storage of variable 's'}} \
-                              // expected-note {{variable 'p' aliases the storage of variable 's'}}
+                              // expected-note {{function call result aliases the storage of 's'}} \
+                              // expected-note {{variable 'p' aliases the storage of 's'}}
     takeString(std::move(s)); // expected-note 2 {{potentially moved here}}
   }
 
@@ -147,20 +147,20 @@ struct MemberSetters {
 
     std::string local;
     view = local;     // expected-warning {{address of stack memory escapes to a field}} \
-                      // expected-note {{variable 'view' aliases the storage of variable 'local'}}
+                      // expected-note {{variable 'view' aliases the storage of 'local'}}
     p = local.data(); // expected-warning {{address of stack memory escapes to a field}} \
-                      // expected-note {{function call result aliases the storage of variable 'local'}} \
-                      // expected-note {{variable 'p' aliases the storage of variable 'local'}}
+                      // expected-note {{function call result aliases the storage of 'local'}} \
+                      // expected-note {{variable 'p' aliases the storage of 'local'}}
   }
 
   void use_after_scope() {
     {
       std::string local;
       view = local;     // expected-warning {{address of stack memory escapes to a field}} \
-                        // expected-note {{variable 'view' aliases the storage of variable 'local'}}
+                        // expected-note {{variable 'view' aliases the storage of 'local'}}
       p = local.data(); // expected-warning {{address of stack memory escapes to a field}} \
-                        // expected-note {{function call result aliases the storage of variable 'local'}} \
-                        // expected-note {{variable 'p' aliases the storage of variable 'local'}}
+                        // expected-note {{function call result aliases the storage of 'local'}} \
+                        // expected-note {{variable 'p' aliases the storage of 'local'}}
     }
     (void)view;
     (void)p;
diff --git a/clang/test/Sema/warn-lifetime-safety-dangling-global.cpp b/clang/test/Sema/warn-lifetime-safety-dangling-global.cpp
index 98b627c96641b..600930389e75c 100644
--- a/clang/test/Sema/warn-lifetime-safety-dangling-global.cpp
+++ b/clang/test/Sema/warn-lifetime-safety-dangling-global.cpp
@@ -23,15 +23,15 @@ void invoke_function_with_side_effects() {
 void inlined() {
   int local;
   global = &local; // expected-warning {{address of stack memory escapes to global or static storage}} \
-                   // expected-note {{variable 'global' aliases the storage of variable 'local'}}
-  global_backup = global; // expected-note {{variable 'global_backup' aliases the storage of variable 'local'}}
+                   // expected-note {{variable 'global' aliases the storage of 'local'}}
+  global_backup = global; // expected-note {{variable 'global_backup' aliases the storage of 'local'}}
   global = nullptr;
 }
 
 void store_local_in_global() {
   int local;
   global = &local; // expected-warning {{address of stack memory escapes to global or static storage}} \
-                   // expected-note {{variable 'global' aliases the storage of variable 'local'}}
+                   // expected-note {{variable 'global' aliases the storage of 'local'}}
 }
 
 void store_then_clear() {
@@ -43,5 +43,5 @@ void store_then_clear() {
 void dangling_static_field() {
   int local;
   ObjWithStaticField::static_field = &local; // expected-warning {{address of stack memory escapes to global or static storage}} \
-                                             // expected-note {{variable 'static_field' aliases the storage of variable 'local'}}
+                                             // expected-note {{variable 'static_field' aliases the storage of 'local'}}
 }
diff --git a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
index cc5db2e02bf1d..a0c43057e8704 100644
--- a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
+++ b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
@@ -79,9 +79,9 @@ View return_view_directly(View a) {
 View conditional_return_view(View a, View b, bool c) {
   View res;
   if (c)  
-    res = a;   // expected-note {{variable 'res' aliases the storage of variable 'a'}}
+    res = a;   // expected-note {{variable 'res' aliases the storage of 'a'}}
   else
-    res = b;   // expected-note {{variable 'res' aliases the storage of variable 'b'}}
+    res = b;   // expected-note {{variable 'res' aliases the storage of 'b'}}
   return res;  // expected-note 2 {{param returned here}} 
 }
 
@@ -171,7 +171,7 @@ View only_one_paramter_annotated(View a [[clang::lifetimebound]],
 View reassigned_to_another_parameter(
     View a,
     View b) {     // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}.
-  a = b;          // expected-note {{variable 'a' aliases the storage of variable 'b'}}
+  a = b;          // expected-note {{variable 'a' aliases the storage of 'b'}}
   return a;       // expected-note {{param returned here}} 
 }
 
diff --git a/clang/test/Sema/warn-lifetime-safety.cpp b/clang/test/Sema/warn-lifetime-safety.cpp
index 9fa7bf9ddddfc..a1c6f488a8a7b 100644
--- a/clang/test/Sema/warn-lifetime-safety.cpp
+++ b/clang/test/Sema/warn-lifetime-safety.cpp
@@ -54,7 +54,7 @@ void simple_case() {
   {
     MyObj s;
     p = &s;     // expected-warning {{object whose reference is captured does not live long enough}} \
-                // expected-note {{variable 'p' aliases the storage of variable 's'}}
+                // expected-note {{variable 'p' aliases the storage of 's'}}
   }             // expected-note {{destroyed here}}
   (void)*p;     // expected-note {{later used here}}
 }
@@ -64,7 +64,7 @@ void simple_case_gsl() {
   {
     MyObj s;
     v = s;      // expected-warning {{object whose reference is captured does not live long enough}} \
-                // expected-note {{variable 'v' aliases the storage of variable 's'}}
+                // expected-note {{variable 'v' aliases the storage of 's'}}
   }             // expected-note {{destroyed here}}
   v.use();      // expected-note {{later used here}}
 }
@@ -93,8 +93,8 @@ void pointer_chain() {
   {
     MyObj s;
     p = &s;     // expected-warning {{does not live long enough}} \
-                // expected-note {{variable 'p' aliases the storage of variable 's'}}
-    q = p;      // expected-note {{variable 'q' aliases the storage of variable 's'}}
+                // expected-note {{variable 'p' aliases the storage of 's'}}
+    q = p;      // expected-note {{variable 'q' aliases the storage of 's'}}
   }             // expected-note {{destroyed here}}
   (void)*q;     // expected-note {{later used here}}
 }
@@ -104,8 +104,8 @@ void propagation_gsl() {
   {
     MyObj s;
     v1 = s;     // expected-warning {{object whose reference is captured does not live long enough}} \
-                // expected-note {{variable 'v1' aliases the storage of variable 's'}}
-    v2 = v1;    // expected-note {{variable 'v2' aliases the storage of variable 's'}}
+                // expected-note {{variable 'v1' aliases the storage of 's'}}
+    v2 = v1;    // expected-note {{variable 'v2' aliases the storage of 's'}}
   }             // expected-note {{destroyed here}}
   v2.use();     // expected-note {{later used here}}
 }
@@ -115,7 +115,7 @@ void multiple_uses_one_warning() {
   {
     MyObj s;
     p = &s;     // expected-warning {{does not live long enough}} \
-                // expected-note {{variable 'p' aliases the storage of variable 's'}}
+                // expected-note {{variable 'p' aliases the storage of 's'}}
   }             // expected-note {{destroyed here}}
   (void)*p;     // expected-note {{later used here}}
   // No second warning for the same loan.
@@ -129,11 +129,11 @@ void multiple_pointers() {
   {
     MyObj s;
     p = &s;     // expected-warning {{does not live long enough}} \
-                // expected-note {{variable 'p' aliases the storage of variable 's'}}
+                // expected-note {{variable 'p' aliases the storage of 's'}}
     q = &s;     // expected-warning {{does not live long enough}} \
-                // expected-note {{variable 'q' aliases the storage of variable 's'}}
+                // expected-note {{variable 'q' aliases the storage of 's'}}
     r = &s;     // expected-warning {{does not live long enough}} \
-                // expected-note {{variable 'r' aliases the storage of variable 's'}}
+                // expected-note {{variable 'r' aliases the storage of 's'}}
   }             // expected-note 3 {{destroyed here}}
   (void)*p;     // expected-note {{later used here}}
   (void)*q;     // expected-note {{later used here}}
@@ -145,12 +145,12 @@ void single_pointer_multiple_loans(bool cond) {
   if (cond){
     MyObj s;
     p = &s;     // expected-warning {{does not live long enough}} \
-                // expected-note {{variable 'p' aliases the storage of variable 's'}}
+                // expected-note {{variable 'p' aliases the storage of 's'}}
   }             // expected-note {{destroyed here}}
   else {
     MyObj t;
     p = &t;     // expected-warning {{does not live long enough}} \
-                // expected-note {{variable 'p' aliases the storage of variable 't'}}
+                // expected-note {{variable 'p' aliases the storage of 't'}}
   }             // expected-note {{destroyed here}}
   (void)*p;     // expected-note 2  {{later used here}}
 }
@@ -160,12 +160,12 @@ void single_pointer_multiple_loans_gsl(bool cond) {
   if (cond){
     MyObj s;
     v = s;      // expected-warning {{object whose reference is captured does not live long enough}} \
-                // expected-note {{variable 'v' aliases the storage of variable 's'}}
+                // expected-note {{variable 'v' aliases the storage of 's'}}
   }             // expected-note {{destroyed here}}
   else {
     MyObj t;
     v = t;      // expected-warning {{object whose reference is captured does not live long enough}} \
-                // expected-note {{variable 'v' aliases the storage of variable 't'}}
+                // expected-note {{variable 'v' aliases the storage of 't'}}
   }             // expected-note {{destroyed here}}
   v.use();      // expected-note 2 {{later used here}}
 }
@@ -176,7 +176,7 @@ void if_branch(bool cond) {
   if (cond) {
     MyObj temp;
     p = &temp;  // expected-warning {{object whose reference is captured does not live long enough}} \
-                // expected-note {{variable 'p' aliases the storage of variable 'temp'}}
+                // expected-note {{variable 'p' aliases the storage of 'temp'}}
   }             // expected-note {{destroyed here}}
   (void)*p;     // expected-note {{later used here}}
 }
@@ -187,7 +187,7 @@ void if_branch_potential(bool cond) {
   if (cond) {
     MyObj temp;
     p = &temp;  // expected-warning {{object whose reference is captured does not live long enough}} \
-                // expected-note {{variable 'p' aliases the storage of variable 'temp'}}
+                // expected-note {{variable 'p' aliases the storage of 'temp'}}
   }             // expected-note {{destroyed here}}
   if (!cond)
     (void)*p;   // expected-note {{later used here}}
@@ -201,7 +201,7 @@ void if_branch_gsl(bool cond) {
   if (cond) {
     MyObj temp;
     v = temp;   // expected-warning {{object whose reference is captured does not live long enough}} \
-                // expected-note {{variable 'v' aliases the storage of variable 'temp'}}
+                // expected-note {{variable 'v' aliases the storage of 'temp'}}
   }             // expected-note {{destroyed here}}
   v.use();      // expected-note {{later used here}}
 }
@@ -215,10 +215,10 @@ void potential_together(bool cond) {
     MyObj s;
     if (cond)
       p_definite = &s;  // expected-warning {{does not live long enough}} \
-                        // expected-note {{variable 'p_definite' aliases the storage of variable 's'}}
+                        // expected-note {{variable 'p_definite' aliases the storage of 's'}}
     if (cond)
       p_maybe = &s;     // expected-warning {{does not live long enough}} \
-                        // expected-note {{variable 'p_maybe' aliases the storage of variable 's'}}
+                        // expected-note {{variable 'p_maybe' aliases the storage of 's'}}
   }                     // expected-note 2 {{destroyed here}}
   (void)*p_definite;    // expected-note {{later used here}}
   if (!cond)
@@ -232,8 +232,8 @@ void overrides_potential(bool cond) {
   {
     MyObj s;
     q = &s;       // expected-warning {{does not live long enough}} \
-                  // expected-note {{variable 'q' aliases the storage of variable 's'}}
-    p = q;        // expected-note {{variable 'p' aliases the storage of variable 's'}}
+                  // expected-note {{variable 'q' aliases the storage of 's'}}
+    p = q;        // expected-note {{variable 'p' aliases the storage of 's'}}
   }               // expected-note {{destroyed here}}
 
   if (cond) {
@@ -253,7 +253,7 @@ void due_to_conditional_killing(bool cond) {
   {
     MyObj s;
     q = &s;       // expected-warning {{does not live long enough}} \
-                  // expected-note {{variable 'q' aliases the storage of variable 's'}}
+                  // expected-note {{variable 'q' aliases the storage of 's'}}
   }               // expected-note {{destroyed here}}
   if (cond) {
     // 'q' is conditionally "rescued". 'p' is not.
@@ -267,7 +267,7 @@ void for_loop_use_after_loop_body(MyObj safe) {
   for (int i = 0; i < 1; ++i) {
     MyObj s;
     p = &s;     // expected-warning {{does not live long enough}} \
-                // expected-note {{variable 'p' aliases the storage of variable 's'}}
+                // expected-note {{variable 'p' aliases the storage of 's'}}
   }             // expected-note {{destroyed here}}
   (void)*p;     // expected-note {{later used here}}
 }
@@ -288,7 +288,7 @@ void for_loop_gsl() {
   for (int i = 0; i < 1; ++i) {
     MyObj s;
     v = s;      // expected-warning {{object whose reference is captured does not live long enough}} \
-                // expected-note {{variable 'v' aliases the storage of variable 's'}}
+                // expected-note {{variable 'v' aliases the storage of 's'}}
   }             // expected-note {{destroyed here}}
   v.use();      // expected-note {{later used here}}
 }
@@ -300,7 +300,7 @@ void for_loop_use_before_loop_body(MyObj safe) {
     (void)*p;   // expected-note {{later used here}}
     MyObj s;
     p = &s;     // expected-warning {{does not live long enough}} \
-                // expected-note {{variable 'p' aliases the storage of variable 's'}}
+                // expected-note {{variable 'p' aliases the storage of 's'}}
   }             // expected-note {{destroyed here}}
   (void)*p;
 }
@@ -312,7 +312,7 @@ void loop_with_break(bool cond) {
     if (cond) {
       MyObj temp;
       p = &temp; // expected-warning {{does not live long enough}} \
-                 // expected-note {{variable 'p' aliases the storage of variable 'temp'}}
+                 // expected-note {{variable 'p' aliases the storage of 'temp'}}
       break;     // expected-note {{destroyed here}}
     }           
   } 
@@ -326,7 +326,7 @@ void loop_with_break_gsl(bool cond) {
     if (cond) {
       MyObj temp;
       v = temp;   // expected-warning {{object whose reference is captured does not live long enough}} \
-                  // expected-note {{variable 'v' aliases the storage of variable 'temp'}}
+                  // expected-note {{variable 'v' aliases the storage of 'temp'}}
       break;      // expected-note {{destroyed here}}
     }
   }
@@ -341,7 +341,7 @@ void multiple_expiry_of_same_loan(bool cond) {
     MyObj unsafe;
     if (cond) {
       p = &unsafe; // expected-warning {{does not live long enough}} \
-                   // expected-note {{variable 'p' aliases the storage of variable 'unsafe'}}
+                   // expected-note {{variable 'p' aliases the storage of 'unsafe'}}
       break;       // expected-note {{destroyed here}}
     }
   }
@@ -352,7 +352,7 @@ void multiple_expiry_of_same_loan(bool cond) {
     MyObj unsafe;
     if (cond) {
       p = &unsafe;    // expected-warning {{does not live long enough}} \
-                      // expected-note {{variable 'p' aliases the storage of variable 'unsafe'}}
+                      // expected-note {{variable 'p' aliases the storage of 'unsafe'}}
       if (cond)
         break;        // expected-note {{destroyed here}}
     }
@@ -364,7 +364,7 @@ void multiple_expiry_of_same_loan(bool cond) {
     if (cond) {
       MyObj unsafe2;
       p = &unsafe2;   // expected-warning {{does not live long enough}} \
-                      // expected-note {{variable 'p' aliases the storage of variable 'unsafe2'}}
+                      // expected-note {{variable 'p' aliases the storage of 'unsafe2'}}
       break;          // expected-note {{destroyed here}}
     }
   }
@@ -375,7 +375,7 @@ void multiple_expiry_of_same_loan(bool cond) {
     MyObj unsafe;
     if (cond)
       p = &unsafe;    // expected-warning {{does not live long enough}} \
-                      // expected-note {{variable 'p' aliases the storage of variable 'unsafe'}}
+                      // expected-note {{variable 'p' aliases the storage of 'unsafe'}}
     if (cond)
       break;          // expected-note {{destroyed here}}
   }
@@ -389,7 +389,7 @@ void switch_potential(int mode) {
   case 1: {
     MyObj temp;
     p = &temp;  // expected-warning {{object whose reference is captured does not live long enough}} \
-                // expected-note {{variable 'p' aliases the storage of variable 'temp'}}
+                // expected-note {{variable 'p' aliases the storage of 'temp'}}
     break;      // expected-note {{destroyed here}}
   }
   case 2: {
@@ -409,19 +409,19 @@ void switch_uaf(int mode) {
   case 1: {
     MyObj temp1;
     p = &temp1; // expected-warning {{does not live long enough}} \
-                // expected-note {{variable 'p' aliases the storage of variable 'temp1'}}
+                // expected-note {{variable 'p' aliases the storage of 'temp1'}}
     break;      // expected-note {{destroyed here}}
   }
   case 2: {
     MyObj temp2;
     p = &temp2; // expected-warning {{does not live long enough}} \
-                // expected-note {{variable 'p' aliases the storage of variable 'temp2'}}
+                // expected-note {{variable 'p' aliases the storage of 'temp2'}}
     break;      // expected-note {{destroyed here}}
   }
   default: {
     MyObj temp2;
     p = &temp2; // expected-warning {{does not live long enough}} \
-                // expected-note {{variable 'p' aliases the storage of variable 'temp2'}}
+                // expected-note {{variable 'p' aliases the storage of 'temp2'}}
     break;      // expected-note {{destroyed here}}
   }
   }
@@ -434,19 +434,19 @@ void switch_gsl(int mode) {
   case 1: {
     MyObj temp1;
     v = temp1;  // expected-warning {{object whose reference is captured does not live long enough}} \
-                // expected-note {{variable 'v' aliases the storage of variable 'temp1'}}
+                // expected-note {{variable 'v' aliases the storage of 'temp1'}}
     break;      // expected-note {{destroyed here}}
   }
   case 2: {
     MyObj temp2;
     v = temp2;  // expected-warning {{object whose reference is captured does not live long enough}} \
-                // expected-note {{variable 'v' aliases the storage of variable 'temp2'}}
+                // expected-note {{variable 'v' aliases the storage of 'temp2'}}
     break;      // expected-note {{destroyed here}}
   }
   default: {
     MyObj temp3;
     v = temp3;  // expected-warning {{object whose reference is captured does not live long enough}} \
-                // expected-note {{variable 'v' aliases the storage of variable 'temp3'}}
+                // expected-note {{variable 'v' aliases the storage of 'temp3'}}
     break;      // expected-note {{destroyed here}}
   }
   }
@@ -460,7 +460,7 @@ void loan_from_previous_iteration(MyObj safe, bool condition) {
   while (condition) {
     MyObj x;
     p = &x;     // expected-warning {{does not live long enough}} \
-                // expected-note {{variable 'p' aliases the storage of variable 'x'}}
+                // expected-note {{variable 'p' aliases the storage of 'x'}}
 
     if (condition)
       q = p;
@@ -474,7 +474,7 @@ void trivial_int_uaf() {
   {
       int b = 1;
       a = &b;  // expected-warning {{object whose reference is captured does not live long enough}} \
-               // expected-note {{variable 'a' aliases the storage of variable 'b'}}
+               // expected-note {{variable 'a' aliases the storage of 'b'}}
   }            // expected-note {{destroyed here}}
   (void)*a;    // expected-note {{later used here}}
 }
@@ -484,7 +484,7 @@ void trivial_class_uaf() {
   {
       TriviallyDestructedClass s;
       ptr = &s; // expected-warning {{object whose reference is captured does not live long enough}} \
-                // expected-note {{variable 'ptr' aliases the storage of variable 's'}}
+                // expected-note {{variable 'ptr' aliases the storage of 's'}}
   }             // expected-note {{destroyed here}}
   (void)ptr;    // expected-note {{later used here}}
 }
@@ -506,7 +506,7 @@ void small_scope_reference_var_no_error() {
 MyObj* simple_return_stack_address() {
   MyObj s;      
   MyObj* p = &s; // expected-warning {{address of stack memory is returned later}} \
-                 // expected-note {{variable 'p' aliases the storage of variable 's'}}
+                 // expected-note {{variable 'p' aliases the storage of 's'}}
   return p;      // expected-note {{returned here}}
 }
 
@@ -536,7 +536,7 @@ const MyObj* conditional_assign_unconditional_return(const MyObj& safe, bool c)
   const MyObj* p = &safe;
   if (c) {
     p = &s;       // expected-warning {{address of stack memory is returned later}} \
-                  // expected-note {{variable 'p' aliases the storage of variable 's'}}
+                  // expected-note {{variable 'p' aliases the storage of 's'}}
   }     
   return p;      // expected-note {{returned here}}
 }
@@ -546,7 +546,7 @@ View conditional_assign_both_branches(const MyObj& safe, bool c) {
   View p;
   if (c) {
     p = s;      // expected-warning {{address of stack memory is returned later}} \
-                // expected-note {{variable 'p' aliases the storage of variable 's'}}
+                // expected-note {{variable 'p' aliases the storage of 's'}}
   } 
   else {
     p = safe;
@@ -559,15 +559,15 @@ View reassign_safe_to_local(const MyObj& safe) {
   MyObj local;
   View p = safe;
   p = local;    // expected-warning {{address of stack memory is returned later}} \
-                // expected-note {{variable 'p' aliases the storage of variable 'local'}}
+                // expected-note {{variable 'p' aliases the storage of 'local'}}
   return p;     // expected-note {{returned here}}
 }
 
 View pointer_chain_to_local() {
   MyObj local;
   View p1 = local;     // expected-warning {{address of stack memory is returned later}} \
-                       // expected-note {{variable 'p1' aliases the storage of variable 'local'}}
-  View p2 = p1;        // expected-note {{variable 'p2' aliases the storage of variable 'local'}}
+                       // expected-note {{variable 'p1' aliases the storage of 'local'}}
+  View p2 = p1;        // expected-note {{variable 'p2' aliases the storage of 'local'}}
   return p2;           // expected-note {{returned here}}
 }
 
@@ -577,12 +577,12 @@ View multiple_assign_multiple_return(const MyObj& safe, bool c1, bool c2) {
   View p;
   if (c1) {
     p = local1;       // expected-warning {{address of stack memory is returned later}} \
-                      // expected-note {{variable 'p' aliases the storage of variable 'local1'}}
+                      // expected-note {{variable 'p' aliases the storage of 'local1'}}
     return p;         // expected-note {{returned here}}
   }
   else if (c2) {
     p = local2;       // expected-warning {{address of stack memory is returned later}} \
-                      // expected-note {{variable 'p' aliases the storage of variable 'local2'}}
+                      // expected-note {{variable 'p' aliases the storage of 'local2'}}
     return p;         // expected-note {{returned here}}
   }
   p = safe;
@@ -595,11 +595,11 @@ View multiple_assign_single_return(const MyObj& safe, bool c1, bool c2) {
   View p;
   if (c1) {
     p = local1;      // expected-warning {{address of stack memory is returned later}} \
-                     // expected-note {{variable 'p' aliases the storage of variable 'local1'}}
+                     // expected-note {{variable 'p' aliases the storage of 'local1'}}
   }
   else if (c2) {
     p = local2;      // expected-warning {{address of stack memory is returned later}} \
-                     // expected-note {{variable 'p' aliases the storage of variable 'local2'}}
+                     // expected-note {{variable 'p' aliases the storage of 'local2'}}
   }
   else {
     p = safe;
@@ -623,7 +623,7 @@ int* trivial_int_uar() {
   int *a;
   int b = 1;
   a = &b;          // expected-warning {{address of stack memory is returned later}} \
-                   // expected-note {{variable 'a' aliases the storage of variable 'b'}}
+                   // expected-note {{variable 'a' aliases the storage of 'b'}}
   return a;        // expected-note {{returned here}}
 }
 
@@ -631,7 +631,7 @@ TriviallyDestructedClass* trivial_class_uar () {
   TriviallyDestructedClass *ptr;
   TriviallyDestructedClass s;
   ptr = &s;       // expected-warning {{address of stack memory is returned later}} \
-                  // expected-note {{variable 'ptr' aliases the storage of variable 's'}}
+                  // expected-note {{variable 'ptr' aliases the storage of 's'}}
   return ptr;     // expected-note {{returned here}}
 }
 
@@ -647,7 +647,7 @@ int* return_pointer_to_parameter(int a) {
 
 const int& return_reference_to_parameter(int a) {
     const int &b = a;   // expected-warning {{address of stack memory is returned later}} \
-                        // expected-note {{variable 'b' aliases the storage of variable 'a'}}
+                        // expected-note {{variable 'b' aliases the storage of 'a'}}
     return b;           // expected-note {{returned here}}
 }
 int return_reference_to_parameter_no_error(int a) {
@@ -658,7 +658,7 @@ int return_reference_to_parameter_no_error(int a) {
 MyObj*& return_ref_to_local_ptr_pointing_to_local() {
   MyObj local;
   MyObj* p = &local; // expected-warning {{address of stack memory is returned later}} \
-                     // expected-note {{variable 'p' aliases the storage of variable 'local'}}
+                     // expected-note {{variable 'p' aliases the storage of 'local'}}
   return p;          // expected-note {{returned here}} \
                      // expected-warning {{address of stack memory is returned later}} \
                      // expected-note {{returned here}}
@@ -666,22 +666,22 @@ MyObj*& return_ref_to_local_ptr_pointing_to_local() {
 
 const int& reference_via_conditional(int a, int b, bool cond) {
     const int &c = (cond ? ((a)) : (b));  // expected-warning 2 {{address of stack memory is returned later}} \
-                                          // expected-note {{variable 'c' aliases the storage of variable 'a'}} \
-                                          // expected-note {{variable 'c' aliases the storage of variable 'b'}}
+                                          // expected-note {{variable 'c' aliases the storage of 'a'}} \
+                                          // expected-note {{variable 'c' aliases the storage of 'b'}}
     return c;                             // expected-note 2 {{returned here}}
 }
 const int* return_pointer_to_parameter_via_reference(int a, int b, bool cond) {
     const int &c = cond ? a : b;  // expected-warning 2 {{address of stack memory is returned later}} \
-                                  // expected-note {{variable 'c' aliases the storage of variable 'a'}} \
-                                  // expected-note {{variable 'c' aliases the storage of variable 'b'}}
-    const int* d = &c;            // expected-note {{variable 'd' aliases the storage of variable 'a'}} \
-                                  // expected-note {{variable 'd' aliases the storage of variable 'b'}}
+                                  // expected-note {{variable 'c' aliases the storage of 'a'}} \
+                                  // expected-note {{variable 'c' aliases the storage of 'b'}}
+    const int* d = &c;            // expected-note {{variable 'd' aliases the storage of 'a'}} \
+                                  // expected-note {{variable 'd' aliases the storage of 'b'}}
     return d;                     // expected-note 2 {{returned here}}
 }
 
 const int& return_pointer_to_parameter_via_reference_1(int a) {
     const int* d = &a; // expected-warning {{address of stack memory is returned later}} \
-                       // expected-note {{variable 'd' aliases the storage of variable 'a'}}
+                       // expected-note {{variable 'd' aliases the storage of 'a'}}
     return *d;    // expected-note {{returned here}}
 }
 
@@ -696,7 +696,7 @@ void test_view_pointer() {
   {
     View v;
     vp = &v;     // expected-warning {{object whose reference is captured does not live long enough}} \
-                 // expected-note {{variable 'vp' aliases the storage of variable 'v'}}
+                 // expected-note {{variable 'vp' aliases the storage of 'v'}}
   }              // expected-note {{destroyed here}}
   vp->use();     // expected-note {{later used here}}
 }
@@ -706,7 +706,7 @@ void test_view_double_pointer() {
   {
     View* vp = nullptr;
     vpp = &vp;   // expected-warning {{object whose reference is captured does not live long enough}} \
-                 // expected-note {{variable 'vpp' aliases the storage of variable 'vp'}}
+                 // expected-note {{variable 'vpp' aliases the storage of 'vp'}}
   }              // expected-note {{destroyed here}}
   (**vpp).use(); // expected-note {{later used here}}
 }
@@ -719,8 +719,8 @@ struct PtrHolder {
 int* const& test_ref_to_ptr() {
   PtrHolder a;
   int *const &ref = a.getRef();  // expected-warning {{address of stack memory is returned later}} \
-                                 // expected-note {{function call result aliases the storage of variable 'a'}} \
-                                 // expected-note {{variable 'ref' aliases the storage of variable 'a'}}
+                                 // expected-note {{function call result aliases the storage of 'a'}} \
+                                 // expected-note {{variable 'ref' aliases the storage of 'a'}}
   return ref;  // expected-note {{returned here}}
 }
 int* const test_ref_to_ptr_no_error() {
@@ -736,9 +736,9 @@ void test_lifetimebound_multi_level() {
     int* p = nullptr;
     int** pp = &p;
     int*** ppp = &pp; // expected-warning {{object whose reference is captured does not live long enough}} \
-                      // expected-note {{variable 'ppp' aliases the storage of variable 'pp'}}
-    result = return_inner_ptr_addr(ppp); // expected-note {{function call result aliases the storage of variable 'pp'}} \
-                                         // expected-note {{variable 'result' aliases the storage of variable 'pp'}}
+                      // expected-note {{variable 'ppp' aliases the storage of 'pp'}}
+    result = return_inner_ptr_addr(ppp); // expected-note {{function call result aliases the storage of 'pp'}} \
+                                         // expected-note {{variable 'result' aliases the storage of 'pp'}}
   }                   // expected-note {{destroyed here}}
   (void)**result;     // expected-note {{used here}}
 }
@@ -758,12 +758,12 @@ void test_assign_through_double_ptr() {
 int** test_ternary_double_ptr(bool cond) {
   int a = 1, b = 2;
   int* pa = &a;  // expected-warning {{address of stack memory is returned later}} \
-                 // expected-note {{variable 'pa' aliases the storage of variable 'a'}}
+                 // expected-note {{variable 'pa' aliases the storage of 'a'}}
   int* pb = &b;  // expected-warning {{address of stack memory is returned later}} \
-                 // expected-note {{variable 'pb' aliases the storage of variable 'b'}}
+                 // expected-note {{variable 'pb' aliases the storage of 'b'}}
   int** result = cond ? &pa : &pb;  // expected-warning 2 {{address of stack memory is returned later}} \
-                                    // expected-note {{variable 'result' aliases the storage of variable 'pa'}} \
-                                    // expected-note {{variable 'result' aliases the storage of variable 'pb'}}
+                                    // expected-note {{variable 'result' aliases the storage of 'pa'}} \
+                                    // expected-note {{variable 'result' aliases the storage of 'pb'}}
   return result; // expected-note 4 {{returned here}}
 }
 //===----------------------------------------------------------------------===//
@@ -776,7 +776,7 @@ MyObj* uaf_before_uar() {
   {
     MyObj local_obj;
     p = &local_obj;  // expected-warning {{object whose reference is captured does not live long enough}} \
-                     // expected-note {{variable 'p' aliases the storage of variable 'local_obj'}}
+                     // expected-note {{variable 'p' aliases the storage of 'local_obj'}}
   }                  // expected-note {{destroyed here}}
   return p;          // expected-note {{later used here}}
 }
@@ -786,7 +786,7 @@ View uar_before_uaf(const MyObj& safe, bool c) {
   {
     MyObj local_obj; 
     p = local_obj;  // expected-warning {{ddress of stack memory is returned later}} \
-                    // expected-note {{variable 'p' aliases the storage of variable 'local_obj'}}
+                    // expected-note {{variable 'p' aliases the storage of 'local_obj'}}
     if (c) {
       return p;     // expected-note {{returned here}}
     }
@@ -856,8 +856,8 @@ void lifetimebound_simple_function() {
   {
     MyObj obj;
     v = Identity(obj); // expected-warning {{object whose reference is captured does not live long enough}} \
-                       // expected-note {{function call result aliases the storage of variable 'obj'}} \
-                       // expected-note {{variable 'v' aliases the storage of variable 'obj'}}
+                       // expected-note {{function call result aliases the storage of 'obj'}} \
+                       // expected-note {{variable 'v' aliases the storage of 'obj'}}
   }                    // expected-note {{destroyed here}}
   v.use();             // expected-note {{later used here}}
 }
@@ -866,10 +866,10 @@ void lifetimebound_multiple_args_definite() {
   View v;
   {
     MyObj obj1, obj2;
-    v = Choose(true,  // expected-note {{function call result aliases the storage of variable 'obj1'}} \
-                      // expected-note {{variable 'v' aliases the storage of variable 'obj1'}} \
-                      // expected-note {{function call result aliases the storage of variable 'obj2'}} \
-                      // expected-note {{variable 'v' aliases the storage of variable 'obj2'}}
+    v = Choose(true,  // expected-note {{function call result aliases the storage of 'obj1'}} \
+                      // expected-note {{variable 'v' aliases the storage of 'obj1'}} \
+                      // expected-note {{function call result aliases the storage of 'obj2'}} \
+                      // expected-note {{variable 'v' aliases the storage of 'obj2'}}
                obj1,  // expected-warning {{object whose reference is captured does not live long enough}}
                obj2); // expected-warning {{object whose reference is captured does not live long enough}}
   }                              // expected-note 2 {{destroyed here}}
@@ -883,10 +883,10 @@ void lifetimebound_multiple_args_potential(bool cond) {
     MyObj obj1;
     if (cond) {
       MyObj obj2;
-      v = Choose(true,             // expected-note {{function call result aliases the storage of variable 'obj1'}} \
-                                   // expected-note {{variable 'v' aliases the storage of variable 'obj1'}} \
-                                   // expected-note {{function call result aliases the storage of variable 'obj2'}} \
-                                   // expected-note {{variable 'v' aliases the storage of variable 'obj2'}}
+      v = Choose(true,             // expected-note {{function call result aliases the storage of 'obj1'}} \
+                                   // expected-note {{variable 'v' aliases the storage of 'obj1'}} \
+                                   // expected-note {{function call result aliases the storage of 'obj2'}} \
+                                   // expected-note {{variable 'v' aliases the storage of 'obj2'}}
                  obj1,             // expected-warning {{object whose reference is captured does not live long enough}}
                  obj2);            // expected-warning {{object whose reference is captured does not live long enough}}
     }                              // expected-note {{destroyed here}}
@@ -900,8 +900,8 @@ void lifetimebound_mixed_args() {
   {
     MyObj obj1, obj2;
     v = SelectFirst(obj1,        // expected-warning {{object whose reference is captured does not live long enough}} \
-                                 // expected-note {{function call result aliases the storage of variable 'obj1'}} \
-                                 // expected-note {{variable 'v' aliases the storage of variable 'obj1'}}
+                                 // expected-note {{function call result aliases the storage of 'obj1'}} \
+                                 // expected-note {{variable 'v' aliases the storage of 'obj1'}}
                     obj2);
   }                              // expected-note {{destroyed here}}
   v.use();                       // expected-note {{later used here}}
@@ -918,8 +918,8 @@ void lifetimebound_member_function() {
   {
     MyObj obj;
     v  = obj.getView(); // expected-warning {{object whose reference is captured does not live long enough}} \
-                        // expected-note {{function call result aliases the storage of variable 'obj'}} \
-                        // expected-note {{variable 'v' aliases the storage of variable 'obj'}}
+                        // expected-note {{function call result aliases the storage of 'obj'}} \
+                        // expected-note {{variable 'v' aliases the storage of 'obj'}}
   }                     // expected-note {{destroyed here}}
   v.use();              // expected-note {{later used here}}
 }
@@ -935,7 +935,7 @@ void lifetimebound_conversion_operator() {
   {
     LifetimeBoundConversionView obj;
     v = obj;  // expected-warning {{object whose reference is captured does not live long enough}} \
-              // expected-note {{variable 'v' aliases the storage of variable 'obj'}}
+              // expected-note {{variable 'v' aliases the storage of 'obj'}}
   }           // expected-note {{destroyed here}}
   v.use();    // expected-note {{later used here}}
 }
@@ -945,8 +945,8 @@ void lifetimebound_chained_calls() {
   {
     MyObj obj;
     v = Identity(Identity(Identity(obj))); // expected-warning {{object whose reference is captured does not live long enough}} \
-                                           // expected-note {{function call result aliases the storage of variable 'obj'}} \
-                                           // expected-note {{variable 'v' aliases the storage of variable 'obj'}}
+                                           // expected-note {{function call result aliases the storage of 'obj'}} \
+                                           // expected-note {{variable 'v' aliases the storage of 'obj'}}
   }                                        // expected-note {{destroyed here}}
   v.use();                                 // expected-note {{later used here}}
 }
@@ -956,8 +956,8 @@ void lifetimebound_with_pointers() {
   {
     MyObj obj;
     ptr = GetPointer(obj); // expected-warning {{object whose reference is captured does not live long enough}} \
-                           // expected-note {{function call result aliases the storage of variable 'obj'}} \
-                           // expected-note {{variable 'ptr' aliases the storage of variable 'obj'}}
+                           // expected-note {{function call result aliases the storage of 'obj'}} \
+                           // expected-note {{variable 'ptr' aliases the storage of 'obj'}}
   }                        // expected-note {{destroyed here}}
   (void)*ptr;              // expected-note {{later used here}}
 }
@@ -975,8 +975,8 @@ void lifetimebound_partial_safety(bool cond) {
   
   if (cond) {
     MyObj temp_obj;
-    v = Choose(true,      // expected-note {{function call result aliases the storage of variable 'temp_obj'}} \
-                          // expected-note {{variable 'v' aliases the storage of variable 'temp_obj'}}
+    v = Choose(true,      // expected-note {{function call result aliases the storage of 'temp_obj'}} \
+                          // expected-note {{variable 'v' aliases the storage of 'temp_obj'}}
                safe_obj,
                temp_obj); // expected-warning {{object whose reference is captured does not live long enough}}
   }                       // expected-note {{destroyed here}}
@@ -990,10 +990,10 @@ void lifetimebound_return_reference() {
   {
     MyObj obj;
     View temp_v = obj;     // expected-warning {{object whose reference is captured does not live long enough}} \
-                           // expected-note {{variable 'temp_v' aliases the storage of variable 'obj'}}
-    const MyObj& ref = GetObject(temp_v); // expected-note {{function call result aliases the storage of variable 'obj'}} \
-                                          // expected-note {{variable 'ref' aliases the storage of variable 'obj'}}
-    ptr = &ref;           // expected-note {{variable 'ptr' aliases the storage of variable 'obj'}}
+                           // expected-note {{variable 'temp_v' aliases the storage of 'obj'}}
+    const MyObj& ref = GetObject(temp_v); // expected-note {{function call result aliases the storage of 'obj'}} \
+                                          // expected-note {{variable 'ref' aliases the storage of 'obj'}}
+    ptr = &ref;           // expected-note {{variable 'ptr' aliases the storage of 'obj'}}
   }                       // expected-note {{destroyed here}}
   (void)*ptr;             // expected-note {{later used here}}
 }
@@ -1008,7 +1008,7 @@ void lifetimebound_ctor() {
   {
     MyObj obj;
     v = obj; // expected-warning {{object whose reference is captured does not live long enough}} \
-             // expected-note {{variable 'v' aliases the storage of variable 'obj'}}
+             // expected-note {{variable 'v' aliases the storage of 'obj'}}
   }          // expected-note {{destroyed here}}
   (void)v;   // expected-note {{later used here}}
 }
@@ -1085,7 +1085,7 @@ void conditional_operator_one_unsafe_branch(bool cond) {
   {
     MyObj temp;
     p = cond ? &temp  // expected-warning {{object whose reference is captured does not live long enough}} \
-                      // expected-note {{variable 'p' aliases the storage of variable 'temp'}}
+                      // expected-note {{variable 'p' aliases the storage of 'temp'}}
              : &safe;
   }  // expected-note {{destroyed here}}
 
@@ -1102,8 +1102,8 @@ void conditional_operator_two_unsafe_branches(bool cond) {
   {
     MyObj a, b;
     p = cond ? &a   // expected-warning {{object whose reference is captured does not live long enough}} \
-                    // expected-note {{variable 'p' aliases the storage of variable 'a'}} \
-                    // expected-note {{variable 'p' aliases the storage of variable 'b'}}
+                    // expected-note {{variable 'p' aliases the storage of 'a'}} \
+                    // expected-note {{variable 'p' aliases the storage of 'b'}}
              : &b;  // expected-warning {{object whose reference is captured does not live long enough}}
   }  // expected-note 2 {{destroyed here}}
   (void)*p;  // expected-note 2 {{later used here}}
@@ -1114,10 +1114,10 @@ void conditional_operator_nested(bool cond) {
   {
     MyObj a, b, c, d;
     p = cond ? cond ? &a    // expected-warning {{object whose reference is captured does not live long enough}}. \
-                            // expected-note {{variable 'p' aliases the storage of variable 'a'}} \
-                            // expected-note {{variable 'p' aliases the storage of variable 'b'}} \
-                            // expected-note {{variable 'p' aliases the storage of variable 'c'}} \
-                            // expected-note {{variable 'p' aliases the storage of variable 'd'}}
+                            // expected-note {{variable 'p' aliases the storage of 'a'}} \
+                            // expected-note {{variable 'p' aliases the storage of 'b'}} \
+                            // expected-note {{variable 'p' aliases the storage of 'c'}} \
+                            // expected-note {{variable 'p' aliases the storage of 'd'}}
                     : &b    // expected-warning {{object whose reference is captured does not live long enough}}.
              : cond ? &c    // expected-warning {{object whose reference is captured does not live long enough}}.
                     : &d;   // expected-warning {{object whose reference is captured does not live long enough}}.
@@ -1130,10 +1130,10 @@ void conditional_operator_lifetimebound(bool cond) {
   {
     MyObj a, b;
     p = Identity(cond ? &a    // expected-warning {{object whose reference is captured does not live long enough}} \
-                              // expected-note {{function call result aliases the storage of variable 'b'}} \
-                              // expected-note {{variable 'p' aliases the storage of variable 'b'}} \
-                              // expected-note {{function call result aliases the storage of variable 'a'}} \
-                              // expected-note {{variable 'p' aliases the storage of variable 'a'}}
+                              // expected-note {{function call result aliases the storage of 'b'}} \
+                              // expected-note {{variable 'p' aliases the storage of 'b'}} \
+                              // expected-note {{function call result aliases the storage of 'a'}} \
+                              // expected-note {{variable 'p' aliases the storage of 'a'}}
                       : &b);  // expected-warning {{object whose reference is captured does not live long enough}}
   }  // expected-note 2 {{destroyed here}}
   (void)*p;  // expected-note 2 {{later used here}}
@@ -1144,10 +1144,10 @@ void conditional_operator_lifetimebound_nested(bool cond) {
   {
     MyObj a, b;
     p = Identity(cond ? Identity(&a)    // expected-warning {{object whose reference is captured does not live long enough}} \
-                                        // expected-note {{function call result aliases the storage of variable 'b'}} \
-                                        // expected-note {{variable 'p' aliases the storage of variable 'b'}} \
-                                        // expected-note {{function call result aliases the storage of variable 'a'}} \
-                                        // expected-note {{variable 'p' aliases the storage of variable 'a'}}
+                                        // expected-note {{function call result aliases the storage of 'b'}} \
+                                        // expected-note {{variable 'p' aliases the storage of 'b'}} \
+                                        // expected-note {{function call result aliases the storage of 'a'}} \
+                                        // expected-note {{variable 'p' aliases the storage of 'a'}}
                       : Identity(&b));  // expected-warning {{object whose reference is captured does not live long enough}}
   }  // expected-note 2 {{destroyed here}}
   (void)*p;  // expected-note 2 {{later used here}}
@@ -1158,14 +1158,14 @@ void conditional_operator_lifetimebound_nested_deep(bool cond) {
   {
     MyObj a, b, c, d;
     p = Identity(cond ? Identity(cond ? &a     // expected-warning {{object whose reference is captured does not live long enough}} \
-                                               // expected-note {{function call result aliases the storage of variable 'a'}} \
-                                               // expected-note {{variable 'p' aliases the storage of variable 'a'}} \
-                                               // expected-note {{function call result aliases the storage of variable 'b'}} \
-                                               // expected-note {{variable 'p' aliases the storage of variable 'b'}} \
-                                               // expected-note {{function call result aliases the storage of variable 'c'}} \
-                                               // expected-note {{variable 'p' aliases the storage of variable 'c'}} \
-                                               // expected-note {{function call result aliases the storage of variable 'd'}} \
-                                               // expected-note {{variable 'p' aliases the storage of variable 'd'}}
+                                               // expected-note {{function call result aliases the storage of 'a'}} \
+                                               // expected-note {{variable 'p' aliases the storage of 'a'}} \
+                                               // expected-note {{function call result aliases the storage of 'b'}} \
+                                               // expected-note {{variable 'p' aliases the storage of 'b'}} \
+                                               // expected-note {{function call result aliases the storage of 'c'}} \
+                                               // expected-note {{variable 'p' aliases the storage of 'c'}} \
+                                               // expected-note {{function call result aliases the storage of 'd'}} \
+                                               // expected-note {{variable 'p' aliases the storage of 'd'}}
                                       : &b)    // expected-warning {{object whose reference is captured does not live long enough}}
                       : Identity(cond ? &c     // expected-warning {{object whose reference is captured does not live long enough}}
                                       : &d));  // expected-warning {{object whose reference is captured does not live long enough}}
@@ -1178,25 +1178,25 @@ void parentheses(bool cond) {
   {
     MyObj a;
     p = &((((a))));  // expected-warning {{object whose reference is captured does not live long enough}} \
-                     // expected-note {{variable 'p' aliases the storage of variable 'a'}}
+                     // expected-note {{variable 'p' aliases the storage of 'a'}}
   }                  // expected-note {{destroyed here}}
   (void)*p;          // expected-note {{later used here}}
 
   {
     MyObj a;
     p = ((GetPointer((a))));  // expected-warning {{object whose reference is captured does not live long enough}} \
-                              // expected-note {{function call result aliases the storage of variable 'a'}} \
-                              // expected-note {{variable 'p' aliases the storage of variable 'a'}}
+                              // expected-note {{function call result aliases the storage of 'a'}} \
+                              // expected-note {{variable 'p' aliases the storage of 'a'}}
   }                           // expected-note {{destroyed here}}
   (void)*p;                   // expected-note {{later used here}}
 
   {
     MyObj a, b, c, d;
     p = &(cond ? (cond ? a     // expected-warning {{object whose reference is captured does not live long enough}}. \
-                               // expected-note {{variable 'p' aliases the storage of variable 'a'}} \
-                               // expected-note {{variable 'p' aliases the storage of variable 'b'}} \
-                               // expected-note {{variable 'p' aliases the storage of variable 'c'}} \
-                               // expected-note {{variable 'p' aliases the storage of variable 'd'}}
+                               // expected-note {{variable 'p' aliases the storage of 'a'}} \
+                               // expected-note {{variable 'p' aliases the storage of 'b'}} \
+                               // expected-note {{variable 'p' aliases the storage of 'c'}} \
+                               // expected-note {{variable 'p' aliases the storage of 'd'}}
                        : b)    // expected-warning {{object whose reference is captured does not live long enough}}.
                : (cond ? c     // expected-warning {{object whose reference is captured does not live long enough}}.
                        : d));  // expected-warning {{object whose reference is captured does not live long enough}}.
@@ -1206,10 +1206,10 @@ void parentheses(bool cond) {
   {
     MyObj a, b, c, d;
     p = ((cond ? (((cond ? &a : &b)))   // expected-warning 2 {{object whose reference is captured does not live long enough}}. \
-                                        // expected-note {{variable 'p' aliases the storage of variable 'a'}} \
-                                        // expected-note {{variable 'p' aliases the storage of variable 'b'}} \
-                                        // expected-note {{variable 'p' aliases the storage of variable 'c'}} \
-                                        // expected-note {{variable 'p' aliases the storage of variable 'd'}}
+                                        // expected-note {{variable 'p' aliases the storage of 'a'}} \
+                                        // expected-note {{variable 'p' aliases the storage of 'b'}} \
+                                        // expected-note {{variable 'p' aliases the storage of 'c'}} \
+                                        // expected-note {{variable 'p' aliases the storage of 'd'}}
               : &(((cond ? c : d)))));  // expected-warning 2 {{object whose reference is captured does not live long enough}}.
   }  // expected-note 4 {{destroyed here}}
   (void)*p;  // expected-note 4 {{later used here}}
@@ -1280,8 +1280,8 @@ void foobar() {
   {
     StatusOr<MyObj> string_or = getStringOr();
     view = string_or. // expected-warning {{object whose reference is captured does not live long enough}} \\
-                      // expected-note {{function call result aliases the storage of variable 'string_or'}} \\
-                      // expected-note {{variable 'view' aliases the storage of variable 'string_or'}}
+                      // expected-note {{function call result aliases the storage of 'string_or'}} \\
+                      // expected-note {{variable 'view' aliases the storage of 'string_or'}}
             value();
   }                     // expected-note {{destroyed here}}
   (void)view;           // expected-note {{later used here}}
@@ -1302,8 +1302,8 @@ void range_based_for_use_after_scope() {
   {
     MyObjStorage s;
     for (const MyObj &o : s) { // expected-warning {{object whose reference is captured does not live long enough}} \
-                               // expected-note {{variable 'o' aliases the storage of variable 's'}}
-      v = o;                   // expected-note {{variable 'v' aliases the storage of variable 's'}}
+                               // expected-note {{variable 'o' aliases the storage of 's'}}
+      v = o;                   // expected-note {{variable 'v' aliases the storage of 's'}}
     }
   } // expected-note {{destroyed here}}
   v.use(); // expected-note {{later used here}}
@@ -1312,8 +1312,8 @@ void range_based_for_use_after_scope() {
 View range_based_for_use_after_return() {
   MyObjStorage s;
   for (const MyObj &o : s) { // expected-warning {{address of stack memory is returned later}} \
-                             // expected-note {{function call result aliases the storage of variable 's'}} \
-                             // expected-note {{variable '__begin1' aliases the storage of variable 's'}}
+                             // expected-note {{function call result aliases the storage of 's'}} \
+                             // expected-note {{variable '__begin1' aliases the storage of 's'}}
     return o;  // expected-note {{returned here}}
   }
   return *s.begin();  // expected-warning {{address of stack memory is returned later}}
@@ -1326,7 +1326,7 @@ void range_based_for_not_reference() {
     MyObjStorage s;
     for (MyObj o : s) { // expected-note {{destroyed here}}
       v = o; // expected-warning {{object whose reference is captured does not live long enough}} \
-             // expected-note {{variable 'v' aliases the storage of variable 'o'}}
+             // expected-note {{variable 'v' aliases the storage of 'o'}}
     }
   }
   v.use();  // expected-note {{later used here}}
@@ -1360,8 +1360,8 @@ void test_user_defined_deref_uaf() {
     MyObj obj;
     SmartPtr<MyObj> smart_ptr(&obj);
     p = &(*smart_ptr);  // expected-warning {{object whose reference is captured does not live long enough}} \
-                        // expected-note {{expression aliases the storage of variable 'smart_ptr'}} \
-                        // expected-note {{variable 'p' aliases the storage of variable 'smart_ptr'}}
+                        // expected-note {{expression aliases the storage of 'smart_ptr'}} \
+                        // expected-note {{variable 'p' aliases the storage of 'smart_ptr'}}
   }                     // expected-note {{destroyed here}}
   (void)*p;             // expected-note {{later used here}}
 }
@@ -1379,8 +1379,8 @@ void test_user_defined_deref_with_view() {
     MyObj obj;
     SmartPtr<MyObj> smart_ptr(&obj);
     v = *smart_ptr;  // expected-warning {{object whose reference is captured does not live long enough}} \
-                     // expected-note {{expression aliases the storage of variable 'smart_ptr'}} \
-                     // expected-note {{variable 'v' aliases the storage of variable 'smart_ptr'}}
+                     // expected-note {{expression aliases the storage of 'smart_ptr'}} \
+                     // expected-note {{variable 'v' aliases the storage of 'smart_ptr'}}
   }                  // expected-note {{destroyed here}}
   v.use();           // expected-note {{later used here}}
 }
@@ -1391,8 +1391,8 @@ void test_user_defined_deref_arrow() {
     MyObj obj;
     SmartPtr<MyObj> smart_ptr(&obj);
     p = smart_ptr.operator->();  // expected-warning {{object whose reference is captured does not live long enough}} \
-                                 // expected-note {{function call result aliases the storage of variable 'smart_ptr'}} \
-                                 // expected-note {{variable 'p' aliases the storage of variable 'smart_ptr'}}
+                                 // expected-note {{function call result aliases the storage of 'smart_ptr'}} \
+                                 // expected-note {{variable 'p' aliases the storage of 'smart_ptr'}}
   }                              // expected-note {{destroyed here}}
   (void)*p;                      // expected-note {{later used here}}
 }
@@ -1403,8 +1403,8 @@ void test_user_defined_deref_chained() {
     MyObj obj;
     SmartPtr<SmartPtr<MyObj>> double_ptr;
     p = &(**double_ptr);  // expected-warning {{object whose reference is captured does not live long enough}} \
-                          // expected-note {{expression aliases the storage of variable 'double_ptr'}} \
-                          // expected-note {{variable 'p' aliases the storage of variable 'double_ptr'}}
+                          // expected-note {{expression aliases the storage of 'double_ptr'}} \
+                          // expected-note {{variable 'p' aliases the storage of 'double_ptr'}}
   }                       // expected-note {{destroyed here}}
   (void)*p;               // expected-note {{later used here}}
 }
@@ -1454,17 +1454,17 @@ MyObj* call_max_with_obj_error() {
 const MyObj* call_max_with_ref_obj_error() {
   MyObj oa, ob;
   const MyObj& refa = oa;     // expected-warning {{address of stack memory is returned later}} \
-                              // expected-note {{variable 'refa' aliases the storage of variable 'oa'}}
+                              // expected-note {{variable 'refa' aliases the storage of 'oa'}}
   const MyObj& refb = ob;     // expected-warning {{address of stack memory is returned later}} \
-                              // expected-note {{variable 'refb' aliases the storage of variable 'ob'}}
+                              // expected-note {{variable 'refb' aliases the storage of 'ob'}}
   return  &MaxT(refa, refb);  // expected-note 2 {{returned here}}
 }
 const MyObj& call_max_with_ref_obj_return_ref_error() {
   MyObj oa, ob;
   const MyObj& refa = oa;     // expected-warning {{address of stack memory is returned later}} \
-                              // expected-note {{variable 'refa' aliases the storage of variable 'oa'}}
+                              // expected-note {{variable 'refa' aliases the storage of 'oa'}}
   const MyObj& refb = ob;     // expected-warning {{address of stack memory is returned later}} \
-                              // expected-note {{variable 'refb' aliases the storage of variable 'ob'}}
+                              // expected-note {{variable 'refb' aliases the storage of 'ob'}}
   return  MaxT(refa, refb);   // expected-note 2 {{returned here}}
 }
 
@@ -1497,45 +1497,45 @@ namespace MultiPointerTypes {
 int** return_2p() {
   int a = 1;
   int* b = &a;  // expected-warning {{address of stack memory is returned later}} \
-                // expected-note {{variable 'b' aliases the storage of variable 'a'}}
+                // expected-note {{variable 'b' aliases the storage of 'a'}}
   int** c = &b; // expected-warning {{address of stack memory is returned later}} \
-                // expected-note {{variable 'c' aliases the storage of variable 'a'}} \
-                // expected-note {{variable 'c' aliases the storage of variable 'b'}}
+                // expected-note {{variable 'c' aliases the storage of 'a'}} \
+                // expected-note {{variable 'c' aliases the storage of 'b'}}
   return c;     // expected-note 2 {{returned here}}
 }
 
 int** return_2p_one_is_safe(int& a) {
   int* b = &a;
   int** c = &b; // expected-warning {{address of stack memory is returned later}} \
-                // expected-note {{variable 'c' aliases the storage of variable 'b'}}
+                // expected-note {{variable 'c' aliases the storage of 'b'}}
   return c;     // expected-note {{returned here}}
 }
 
 int*** return_3p() {
   int a = 1;
   int* b = &a;    // expected-warning {{address of stack memory is returned later}} \
-                  // expected-note {{variable 'b' aliases the storage of variable 'a'}}
+                  // expected-note {{variable 'b' aliases the storage of 'a'}}
   int** c = &b;   // expected-warning {{address of stack memory is returned later}} \
-                  // expected-note {{variable 'c' aliases the storage of variable 'a'}} \
-                  // expected-note {{variable 'c' aliases the storage of variable 'b'}}
+                  // expected-note {{variable 'c' aliases the storage of 'a'}} \
+                  // expected-note {{variable 'c' aliases the storage of 'b'}}
   int*** d = &c;  // expected-warning {{address of stack memory is returned later}} \
-                  // expected-note {{variable 'd' aliases the storage of variable 'a'}} \
-                  // expected-note {{variable 'd' aliases the storage of variable 'b'}} \
-                  // expected-note {{variable 'd' aliases the storage of variable 'c'}}
+                  // expected-note {{variable 'd' aliases the storage of 'a'}} \
+                  // expected-note {{variable 'd' aliases the storage of 'b'}} \
+                  // expected-note {{variable 'd' aliases the storage of 'c'}}
   return d;       // expected-note 3 {{returned here}}
 }
 
 View** return_view_p() {
   MyObj a;
   View b = a;     // expected-warning {{address of stack memory is returned later}} \
-                  // expected-note {{variable 'b' aliases the storage of variable 'a'}}
+                  // expected-note {{variable 'b' aliases the storage of 'a'}}
   View* c = &b;   // expected-warning {{address of stack memory is returned later}} \
-                  // expected-note {{variable 'c' aliases the storage of variable 'a'}} \
-                  // expected-note {{variable 'c' aliases the storage of variable 'b'}}
+                  // expected-note {{variable 'c' aliases the storage of 'a'}} \
+                  // expected-note {{variable 'c' aliases the storage of 'b'}}
   View** d = &c;  // expected-warning {{address of stack memory is returned later}} \
-                  // expected-note {{variable 'd' aliases the storage of variable 'a'}} \
-                  // expected-note {{variable 'd' aliases the storage of variable 'b'}} \
-                  // expected-note {{variable 'd' aliases the storage of variable 'c'}}
+                  // expected-note {{variable 'd' aliases the storage of 'a'}} \
+                  // expected-note {{variable 'd' aliases the storage of 'b'}} \
+                  // expected-note {{variable 'd' aliases the storage of 'c'}}
   return d;       // expected-note 3 {{returned here}}
 }
 
@@ -1576,7 +1576,7 @@ void strict_warn_on_move() {
   {
     MyObj a;
     v = a;            // expected-warning-re {{object whose reference {{.*}} may have been moved}} \
-                      // expected-note {{variable 'v' aliases the storage of variable 'a'}}
+                      // expected-note {{variable 'v' aliases the storage of 'a'}}
     b = std::move(a); // expected-note {{potentially moved here}}
   }                   // expected-note {{destroyed here}}
   (void)v;            // expected-note {{later used here}}
@@ -1590,7 +1590,7 @@ void flow_sensitive(bool c) {
       MyObj b = std::move(a);
       return;
     }
-    v = a;  // expected-warning {{object whose reference}} expected-note {{variable 'v' aliases the storage of variable 'a'}}
+    v = a;  // expected-warning {{object whose reference}} expected-note {{variable 'v' aliases the storage of 'a'}}
   }         // expected-note {{destroyed here}}
   (void)v;  // expected-note {{later used here}}
 }
@@ -1601,8 +1601,8 @@ void detect_conditional(bool cond) {
   {
     MyObj a, b;
     v = cond ? a : b; // expected-warning-re 2 {{object whose reference {{.*}} may have been moved}} \
-                      // expected-note {{variable 'v' aliases the storage of variable 'b'}} \
-                      // expected-note {{variable 'v' aliases the storage of variable 'a'}}
+                      // expected-note {{variable 'v' aliases the storage of 'b'}} \
+                      // expected-note {{variable 'v' aliases the storage of 'a'}}
     take(std::move(cond ? a : b)); // expected-note 2 {{potentially moved here}}
   }         // expected-note 2 {{destroyed here}}
   (void)v;  // expected-note 2 {{later used here}}
@@ -1613,16 +1613,16 @@ void wrong_use_of_move_is_permissive() {
   {
     MyObj a;
     v = std::move(a); // expected-warning {{object whose reference is captured does not live long enough}} \
-                      // expected-note {{function call result aliases the storage of variable 'a'}} \
-                      // expected-note {{variable 'v' aliases the storage of variable 'a'}}
+                      // expected-note {{function call result aliases the storage of 'a'}} \
+                      // expected-note {{variable 'v' aliases the storage of 'a'}}
   }         // expected-note {{destroyed here}}
   (void)v;  // expected-note {{later used here}}
   const int* p;
   {
     MyObj a;
     p = std::move(a).getData(); // expected-warning {{object whose reference is captured does not live long enough}} \
-                                // expected-note 2 {{function call result aliases the storage of variable 'a'}} \
-                                // expected-note {{variable 'p' aliases the storage of variable 'a'}}
+                                // expected-note 2 {{function call result aliases the storage of 'a'}} \
+                                // expected-note {{variable 'p' aliases the storage of 'a'}}
   }         // expected-note {{destroyed here}}
   (void)p;  // expected-note {{later used here}}
 }
@@ -1634,8 +1634,8 @@ void test_release_no_uaf() {
   {
     std::unique_ptr<int> p;
     r = p.get();        // expected-warning-re {{object whose reference {{.*}} may have been moved}} \
-                        // expected-note {{function call result aliases the storage of variable 'p'}} \
-                        // expected-note {{variable 'r' aliases the storage of variable 'p'}}
+                        // expected-note {{function call result aliases the storage of 'p'}} \
+                        // expected-note {{variable 'r' aliases the storage of 'p'}}
     take(p.release());  // expected-note {{potentially moved here}}
   }                     // expected-note {{destroyed here}}
   (void)*r;             // expected-note {{later used here}}
@@ -1658,8 +1658,8 @@ void bar() {
     {
         S s;
         x = s.x();        // expected-warning {{object whose reference is captured does not live long enough}} \
-                          // expected-note {{function call result aliases the storage of variable 's'}} \
-                          // expected-note {{variable 'x' aliases the storage of variable 's'}}
+                          // expected-note {{function call result aliases the storage of 's'}} \
+                          // expected-note {{variable 'x' aliases the storage of 's'}}
         View y = S().x(); // expected-warning {{object whose reference is captured does not live long enough}} \
                           // expected-note {{destroyed here}} \
                           // expected-note {{function call result aliases the storage of the temporary}} \
@@ -1673,29 +1673,29 @@ void bar() {
 namespace DereferenceViews {
 const MyObj& testDeref(MyObj obj) {
   View v = obj; // expected-warning {{address of stack memory is returned later}} \
-                // expected-note {{variable 'v' aliases the storage of variable 'obj'}}
+                // expected-note {{variable 'v' aliases the storage of 'obj'}}
   return *v;    // expected-note {{returned here}}
 }
 const MyObj* testDerefAddr(MyObj obj) {
   View v = obj; // expected-warning {{address of stack memory is returned later}} \
-                // expected-note {{variable 'v' aliases the storage of variable 'obj'}}
+                // expected-note {{variable 'v' aliases the storage of 'obj'}}
   return &*v;   // expected-note {{returned here}}
 }
 const MyObj* testData(MyObj obj) {
   View v = obj;     // expected-warning {{address of stack memory is returned later}} \
-                    // expected-note {{variable 'v' aliases the storage of variable 'obj'}}
+                    // expected-note {{variable 'v' aliases the storage of 'obj'}}
   return v.data();  // expected-note {{returned here}}
 }
 const int* testLifetimeboundAccessorOfMyObj(MyObj obj) {
   View v = obj;           // expected-warning {{address of stack memory is returned later}} \
-                          // expected-note {{variable 'v' aliases the storage of variable 'obj'}}
-  const MyObj* ptr = v.data(); // expected-note {{function call result aliases the storage of variable 'obj'}} \
-                               // expected-note {{variable 'ptr' aliases the storage of variable 'obj'}}
+                          // expected-note {{variable 'v' aliases the storage of 'obj'}}
+  const MyObj* ptr = v.data(); // expected-note {{function call result aliases the storage of 'obj'}} \
+                               // expected-note {{variable 'ptr' aliases the storage of 'obj'}}
   return ptr->getData();  // expected-note {{returned here}}
 }
 const int* testLifetimeboundAccessorOfMyObjThroughDeref(MyObj obj) {
   View v = obj;         // expected-warning {{address of stack memory is returned later}} \
-                        // expected-note {{variable 'v' aliases the storage of variable 'obj'}}
+                        // expected-note {{variable 'v' aliases the storage of 'obj'}}
   return v->getData();  // expected-note {{returned here}}
 }
 } // namespace DereferenceViews
@@ -1720,8 +1720,8 @@ MyObj Global;
 
 const MyObj& ContainerMyObjReturnRef(Container<MyObj> c) {
   for (const MyObj& x : c) {  // expected-warning {{address of stack memory is returned later}} \
-                              // expected-note {{function call result aliases the storage of variable 'c'}} \
-                              // expected-note {{variable '__begin1' aliases the storage of variable 'c'}}
+                              // expected-note {{function call result aliases the storage of 'c'}} \
+                              // expected-note {{variable '__begin1' aliases the storage of 'c'}}
     return x;                 // expected-note {{returned here}}
   }
   return Global;
@@ -1729,13 +1729,13 @@ const MyObj& ContainerMyObjReturnRef(Container<MyObj> c) {
 
 View ContainerMyObjReturnView(Container<MyObj> c) {
   for (const MyObj& x : c) {  // expected-warning {{address of stack memory is returned later}} \
-                              // expected-note {{function call result aliases the storage of variable 'c'}} \
-                              // expected-note {{variable '__begin1' aliases the storage of variable 'c'}}
+                              // expected-note {{function call result aliases the storage of 'c'}} \
+                              // expected-note {{variable '__begin1' aliases the storage of 'c'}}
     return x;                 // expected-note {{returned here}}
   }
   for (View x : c) {  // expected-warning {{address of stack memory is returned later}} \
-                      // expected-note {{function call result aliases the storage of variable 'c'}} \
-                      // expected-note {{variable '__begin1' aliases the storage of variable 'c'}}
+                      // expected-note {{function call result aliases the storage of 'c'}} \
+                      // expected-note {{variable '__begin1' aliases the storage of 'c'}}
     return x;         // expected-note {{returned here}}
   }
   return Global;
@@ -1779,9 +1779,9 @@ void test_temporary() {
   {
     S s;
     const std::string& zz = s.x(); // expected-warning {{object whose reference is captured does not live long enough}} \
-                                   // expected-note {{function call result aliases the storage of variable 's'}} \
-                                   // expected-note {{variable 'zz' aliases the storage of variable 's'}}
-    z = zz;                        // expected-note {{variable 'z' aliases the storage of variable 's'}}
+                                   // expected-note {{function call result aliases the storage of 's'}} \
+                                   // expected-note {{variable 'zz' aliases the storage of 's'}}
+    z = zz;                        // expected-note {{variable 'z' aliases the storage of 's'}}
   } // expected-note {{destroyed here}}
   (void)z; // expected-note {{later used here}}
 }
@@ -1817,8 +1817,8 @@ void uaf() {
   {
     S str;
     S* p = &str;  // expected-warning {{object whose reference is captured does not live long enough}} \
-                  // expected-note {{variable 'p' aliases the storage of variable 'str'}}
-    view = p->s;  // expected-note {{variable 'view' aliases the storage of variable 'str'}}
+                  // expected-note {{variable 'p' aliases the storage of 'str'}}
+    view = p->s;  // expected-note {{variable 'view' aliases the storage of 'str'}}
   } // expected-note {{destroyed here}}
   (void)view;  // expected-note {{later used here}}
 }
@@ -1844,8 +1844,8 @@ void uaf_union() {
   {
     U u = U{"hello"};
     U* up = &u;  // expected-warning {{object whose reference is captured does not live long enough}} \
-                 // expected-note {{variable 'up' aliases the storage of variable 'u'}}
-    view = up->s; // expected-note {{variable 'view' aliases the storage of variable 'u'}}
+                 // expected-note {{variable 'up' aliases the storage of 'u'}}
+    view = up->s; // expected-note {{variable 'view' aliases the storage of 'u'}}
   } // expected-note {{destroyed here}}
   (void)view;  // expected-note {{later used here}}
 }
@@ -1862,8 +1862,8 @@ void uaf_anonymous_union() {
   {
     AnonymousUnion au;
     AnonymousUnion* up = &au;  // expected-warning {{object whose reference is captured does not live long enough}} \
-                               // expected-note {{variable 'up' aliases the storage of variable 'au'}}
-    ip = &up->x; // expected-note {{variable 'ip' aliases the storage of variable 'au'}}
+                               // expected-note {{variable 'up' aliases the storage of 'au'}}
+    ip = &up->x; // expected-note {{variable 'ip' aliases the storage of 'au'}}
   } // expected-note {{destroyed here}}
   (void)ip;  // expected-note {{later used here}}
 }
@@ -1953,13 +1953,13 @@ View test1(std::string a) {
 
 View test2(std::string a) {
   View b = View(a); // expected-warning {{address of stack memory is returned later}} \
-                    // expected-note {{variable 'b' aliases the storage of variable 'a'}}
+                    // expected-note {{variable 'b' aliases the storage of 'a'}}
   return b;         // expected-note {{returned here}}
 }
 
 View test3(std::string a) {
   const View& b = View(a);  // expected-warning {{address of stack memory is returned later}} \
-                            // expected-note {{variable 'b' aliases the storage of variable 'a'}}
+                            // expected-note {{variable 'b' aliases the storage of 'a'}}
   return b;                 // expected-note {{returned here}}
 }
 } // namespace non_trivial_views
@@ -1970,9 +1970,9 @@ void test_optional_arrow() {
   {
     std::optional<std::string> opt;
     p = opt->data();  // expected-warning {{object whose reference is captured does not live long enough}} \
-                      // expected-note {{expression aliases the storage of variable 'opt'}} \
-                      // expected-note {{function call result aliases the storage of variable 'opt'}} \
-                      // expected-note {{variable 'p' aliases the storage of variable 'opt'}}
+                      // expected-note {{expression aliases the storage of 'opt'}} \
+                      // expected-note {{function call result aliases the storage of 'opt'}} \
+                      // expected-note {{variable 'p' aliases the storage of 'opt'}}
   }                   // expected-note {{destroyed here}}
   (void)*p;           // expected-note {{later used here}}
 }
@@ -1982,9 +1982,9 @@ void test_optional_arrow_lifetimebound() {
   {
     std::optional<MyObj> opt;
     v = opt->getView();  // expected-warning {{object whose reference is captured does not live long enough}} \
-                         // expected-note {{expression aliases the storage of variable 'opt'}} \
-                         // expected-note {{function call result aliases the storage of variable 'opt'}} \
-                         // expected-note {{variable 'v' aliases the storage of variable 'opt'}}
+                         // expected-note {{expression aliases the storage of 'opt'}} \
+                         // expected-note {{function call result aliases the storage of 'opt'}} \
+                         // expected-note {{variable 'v' aliases the storage of 'opt'}}
   }                      // expected-note {{destroyed here}}
   v.use();               // expected-note {{later used here}}
 }
@@ -1994,9 +1994,9 @@ void test_unique_ptr_arrow() {
   {
     std::unique_ptr<std::string> up;
     p = up->data();  // expected-warning {{object whose reference is captured does not live long enough}} \
-                     // expected-note {{expression aliases the storage of variable 'up'}} \
-                     // expected-note {{function call result aliases the storage of variable 'up'}} \
-                     // expected-note {{variable 'p' aliases the storage of variable 'up'}}
+                     // expected-note {{expression aliases the storage of 'up'}} \
+                     // expected-note {{function call result aliases the storage of 'up'}} \
+                     // expected-note {{variable 'p' aliases the storage of 'up'}}
   }                  // expected-note {{destroyed here}}
   (void)*p;          // expected-note {{later used here}}
 }
@@ -2015,7 +2015,7 @@ namespace lambda_captures {
 auto return_ref_capture() {
   int local = 1;
   auto lambda = [&local]() { return local; }; // expected-warning {{address of stack memory is returned later}} \
-                                              // expected-note {{variable 'lambda' aliases the storage of variable 'local'}}
+                                              // expected-note {{variable 'lambda' aliases the storage of 'local'}}
   return lambda; // expected-note {{returned here}}
 }
 
@@ -2034,8 +2034,8 @@ auto capture_int_by_value() {
 auto capture_view_by_value() {
   MyObj obj;
   View v(obj); // expected-warning {{address of stack memory is returned later}} \
-               // expected-note {{variable 'v' aliases the storage of variable 'obj'}}
-  auto lambda = [v]() { return v; }; // expected-note {{variable 'lambda' aliases the storage of variable 'obj'}}
+               // expected-note {{variable 'v' aliases the storage of 'obj'}}
+  auto lambda = [v]() { return v; }; // expected-note {{variable 'lambda' aliases the storage of 'obj'}}
   return lambda; // expected-note {{returned here}}
 }
 
@@ -2050,14 +2050,14 @@ auto capture_pointer_by_ref() {
   MyObj obj;
   MyObj* p = &obj;
   auto lambda = [&p]() { return p; }; // expected-warning {{address of stack memory is returned later}} \\
-                                      // expected-note {{variable 'lambda' aliases the storage of variable 'p'}}
+                                      // expected-note {{variable 'lambda' aliases the storage of 'p'}}
   return lambda; // expected-note {{returned here}}
 }
 
 auto capture_multiple() {
   int a, b;
-  auto lambda = [ // expected-note {{variable 'lambda' aliases the storage of variable 'b'}} \
-                  // expected-note {{variable 'lambda' aliases the storage of variable 'a'}}
+  auto lambda = [ // expected-note {{variable 'lambda' aliases the storage of 'b'}} \
+                  // expected-note {{variable 'lambda' aliases the storage of 'a'}}
     &a,  // expected-warning {{address of stack memory is returned later}}
     &b   // expected-warning {{address of stack memory is returned later}}
   ]() { return a + b; };
@@ -2067,47 +2067,47 @@ auto capture_multiple() {
 auto capture_raw_pointer_by_value() {
   int x;
   int* p = &x; // expected-warning {{address of stack memory is returned later}} \
-               // expected-note {{variable 'p' aliases the storage of variable 'x'}}
-  auto lambda = [p]() { return p; }; // expected-note {{variable 'lambda' aliases the storage of variable 'x'}}
+               // expected-note {{variable 'p' aliases the storage of 'x'}}
+  auto lambda = [p]() { return p; }; // expected-note {{variable 'lambda' aliases the storage of 'x'}}
   return lambda; // expected-note {{returned here}}
 }
 
 auto capture_raw_pointer_init_capture() {
   int x;
   int* p = &x; // expected-warning {{address of stack memory is returned later}} \
-               // expected-note {{variable 'p' aliases the storage of variable 'x'}}
-  auto lambda = [q = p]() { return q; }; // expected-note {{variable 'lambda' aliases the storage of variable 'x'}}
+               // expected-note {{variable 'p' aliases the storage of 'x'}}
+  auto lambda = [q = p]() { return q; }; // expected-note {{variable 'lambda' aliases the storage of 'x'}}
   return lambda; // expected-note {{returned here}}
 }
 
 auto capture_view_init_capture() {
   MyObj obj;
   View v(obj); // expected-warning {{address of stack memory is returned later}} \
-               // expected-note {{variable 'v' aliases the storage of variable 'obj'}}
-  auto lambda = [w = v]() { return w; }; // expected-note {{variable 'lambda' aliases the storage of variable 'obj'}}
+               // expected-note {{variable 'v' aliases the storage of 'obj'}}
+  auto lambda = [w = v]() { return w; }; // expected-note {{variable 'lambda' aliases the storage of 'obj'}}
   return lambda; // expected-note {{returned here}}
 }
 
 auto capture_lambda() {
   int x;
   auto inner = [&x]() { return x; }; // expected-warning {{address of stack memory is returned later}} \
-                                     // expected-note {{variable 'inner' aliases the storage of variable 'x'}}
-  auto outer = [inner]() { return inner(); }; // expected-note {{variable 'outer' aliases the storage of variable 'x'}}
+                                     // expected-note {{variable 'inner' aliases the storage of 'x'}}
+  auto outer = [inner]() { return inner(); }; // expected-note {{variable 'outer' aliases the storage of 'x'}}
   return outer; // expected-note {{returned here}}
 }
 
 auto return_copied_lambda() {
   int local = 1;
   auto lambda = [&local]() { return local; }; // expected-warning {{address of stack memory is returned later}} \
-                                              // expected-note {{variable 'lambda' aliases the storage of variable 'local'}}
-  auto lambda_copy = lambda;                  // expected-note {{variable 'lambda_copy' aliases the storage of variable 'local'}}
+                                              // expected-note {{variable 'lambda' aliases the storage of 'local'}}
+  auto lambda_copy = lambda;                  // expected-note {{variable 'lambda_copy' aliases the storage of 'local'}}
   return lambda_copy; // expected-note {{returned here}}
 }
 
 auto implicit_ref_capture() {
   int local = 1;
   auto lambda = [&]() { return local; }; // expected-warning {{address of stack memory is returned later}} \
-                                         // expected-note {{variable 'lambda' aliases the storage of variable 'local'}}
+                                         // expected-note {{variable 'lambda' aliases the storage of 'local'}}
   return lambda; // expected-note {{returned here}}
 }
 
@@ -2117,16 +2117,16 @@ auto implicit_ref_capture() {
 auto implicit_ref_capture_multiple() {
   int local = 1, local2 = 2;
   auto lambda = [&]() { return local + local2; }; // expected-warning 2 {{address of stack memory is returned later}} \
-                                                  // expected-note {{variable 'lambda' aliases the storage of variable 'local'}} \
-                                                  // expected-note {{variable 'lambda' aliases the storage of variable 'local2'}}
+                                                  // expected-note {{variable 'lambda' aliases the storage of 'local'}} \
+                                                  // expected-note {{variable 'lambda' aliases the storage of 'local2'}}
   return lambda; // expected-note 2 {{returned here}}
 }
 
 auto implicit_value_capture() {
   MyObj obj;
   View v(obj); // expected-warning {{address of stack memory is returned later}} \
-               // expected-note {{variable 'v' aliases the storage of variable 'obj'}}
-  auto lambda = [=]() { return v; }; // expected-note {{variable 'lambda' aliases the storage of variable 'obj'}}
+               // expected-note {{variable 'v' aliases the storage of 'obj'}}
+  auto lambda = [=]() { return v; }; // expected-note {{variable 'lambda' aliases the storage of 'obj'}}
   return lambda; // expected-note {{returned here}}
 }
 
@@ -2158,21 +2158,21 @@ auto capture_static_address_by_ref() {
   static int local = 1;
   int* p = &local;
   auto lambda = [&p]() { return p; }; // expected-warning {{address of stack memory is returned later}} \
-                                      // expected-note {{variable 'lambda' aliases the storage of variable 'p'}}
+                                      // expected-note {{variable 'lambda' aliases the storage of 'p'}}
   return lambda; // expected-note {{returned here}}
 }
 
 auto capture_multilevel_pointer() {
   int x;
   int *p = &x;   // expected-warning {{address of stack memory is returned later}} \
-                 // expected-note {{variable 'p' aliases the storage of variable 'x'}}
+                 // expected-note {{variable 'p' aliases the storage of 'x'}}
   int **q = &p;  // expected-warning {{address of stack memory is returned later}} \
-                 // expected-note {{variable 'q' aliases the storage of variable 'p'}}
+                 // expected-note {{variable 'q' aliases the storage of 'p'}}
   int ***r = &q; // expected-warning {{address of stack memory is returned later}} \
-                 // expected-note {{variable 'r' aliases the storage of variable 'q'}}
-  auto lambda = [=]() { return *p + **q + ***r; }; // expected-note {{variable 'lambda' aliases the storage of variable 'x'}} \
-                                                   // expected-note {{variable 'lambda' aliases the storage of variable 'q'}} \
-                                                   // expected-note {{variable 'lambda' aliases the storage of variable 'p'}}
+                 // expected-note {{variable 'r' aliases the storage of 'q'}}
+  auto lambda = [=]() { return *p + **q + ***r; }; // expected-note {{variable 'lambda' aliases the storage of 'x'}} \
+                                                   // expected-note {{variable 'lambda' aliases the storage of 'q'}} \
+                                                   // expected-note {{variable 'lambda' aliases the storage of 'p'}}
   return lambda; // expected-note 3 {{returned here}}
 }
 } // namespace lambda_captures
@@ -2207,8 +2207,8 @@ void multi_level_pointer_in_loop() {
     MyObj** pp;
     if (i > 5) {
       p = &obj; // expected-warning {{object whose reference is captured does not live long enough}} \
-                // expected-note {{variable 'p' aliases the storage of variable 'obj'}}
-      pp = &p;  // expected-note {{variable 'pp' aliases the storage of variable 'obj'}}
+                // expected-note {{variable 'p' aliases the storage of 'obj'}}
+      pp = &p;  // expected-note {{variable 'pp' aliases the storage of 'obj'}}
     }
     (void)**pp; // expected-note {{later used here}}
   }             // expected-note {{destroyed here}}
@@ -2220,7 +2220,7 @@ void outer_pointer_outlives_inner_pointee() {
   for (int i = 0; i < 10; ++i) {
     MyObj obj;
     view = &obj;     // expected-warning {{object whose reference is captured does not live long enough}} \
-                     // expected-note {{variable 'view' aliases the storage of variable 'obj'}}
+                     // expected-note {{variable 'view' aliases the storage of 'obj'}}
   }                  // expected-note {{destroyed here}}
   (void)*view;       // expected-note {{later used here}}
 }
@@ -2234,7 +2234,7 @@ void element_use_after_scope() {
   {
     int a[10]{};
     p = &a[2]; // expected-warning {{object whose reference is captured does not live long enough}} \
-               // expected-note {{variable 'p' aliases the storage of variable 'a'}}
+               // expected-note {{variable 'p' aliases the storage of 'a'}}
   }            // expected-note {{destroyed here}}
   (void)*p;    // expected-note {{later used here}}
 }
@@ -2242,7 +2242,7 @@ void element_use_after_scope() {
 int* element_use_after_return() {
   int a[10]{};
   int* p = &a[0]; // expected-warning {{address of stack memory is returned later}} \
-                  // expected-note {{variable 'p' aliases the storage of variable 'a'}}
+                  // expected-note {{variable 'p' aliases the storage of 'a'}}
   return p;       // expected-note {{returned here}}
 }
 
@@ -2268,7 +2268,7 @@ void multidimensional_use_after_scope() {
   {
     int a[3][4]{};
     p = &a[1][2]; // expected-warning {{object whose reference is captured does not live long enough}} \
-                  // expected-note {{variable 'p' aliases the storage of variable 'a'}}
+                  // expected-note {{variable 'p' aliases the storage of 'a'}}
   }               // expected-note {{destroyed here}}
   (void)*p;       // expected-note {{later used here}}
 }
@@ -2282,7 +2282,7 @@ void member_array_element_use_after_scope() {
   {
     S s;
     p = &s.arr[0]; // expected-warning {{object whose reference is captured does not live long enough}} \
-                   // expected-note {{variable 'p' aliases the storage of variable 's'}}
+                   // expected-note {{variable 'p' aliases the storage of 's'}}
   }                // expected-note {{destroyed here}}
   (void)*p;        // expected-note {{later used here}}
 }
@@ -2292,7 +2292,7 @@ void array_of_pointers_use_after_scope() {
   {
     int* a[10]{};
     p = a;  // expected-warning {{object whose reference is captured does not live long enough}} \
-            // expected-note {{variable 'p' aliases the storage of variable 'a'}}
+            // expected-note {{variable 'p' aliases the storage of 'a'}}
   }         // expected-note {{destroyed here}}
   (void)*p; // expected-note {{later used here}}
 }
@@ -2302,7 +2302,7 @@ void reversed_subscript_use_after_scope() {
   {
     int a[10]{};
     p = &(0[a]); // expected-warning {{object whose reference is captured does not live long enough}} \
-                 // expected-note {{variable 'p' aliases the storage of variable 'a'}}
+                 // expected-note {{variable 'p' aliases the storage of 'a'}}
   }              // expected-note {{destroyed here}}
   (void)*p;      // expected-note {{later used here}}
 }
@@ -2310,7 +2310,7 @@ void reversed_subscript_use_after_scope() {
 int* return_decayed_array() {
   int a[10]{};
   int *p = a; // expected-warning {{address of stack memory is returned later}} \
-              // expected-note {{variable 'p' aliases the storage of variable 'a'}}
+              // expected-note {{variable 'p' aliases the storage of 'a'}}
   return p;   // expected-note {{returned here}}
 }
 
@@ -2330,11 +2330,11 @@ void pointer_arithmetic_use_after_scope() {
   {
     int a[10]{};
     p = a + 5;  // expected-warning {{object whose reference is captured does not live long enough}} \
-                // expected-note {{variable 'p' aliases the storage of variable 'a'}}
+                // expected-note {{variable 'p' aliases the storage of 'a'}}
     p2 = a - 5; // expected-warning {{object whose reference is captured does not live long enough}} \
-                // expected-note {{variable 'p2' aliases the storage of variable 'a'}}
+                // expected-note {{variable 'p2' aliases the storage of 'a'}}
     p3 = 5 + a; // expected-warning {{object whose reference is captured does not live long enough}} \
-                // expected-note {{variable 'p3' aliases the storage of variable 'a'}}
+                // expected-note {{variable 'p3' aliases the storage of 'a'}}
   }             // expected-note 3 {{destroyed here}}
   (void)*p;     // expected-note {{later used here}}
   (void)*p2;    // expected-note {{later used here}}
@@ -2446,8 +2446,8 @@ void from_lifetimebound_this_method() {
   {
     Factory f;
     value = f.makeThis(); // expected-warning {{object whose reference is captured does not live long enough}} \
-                          // expected-note {{function call result aliases the storage of variable 'f'}} \
-                          // expected-note {{variable 'value' aliases the storage of variable 'f'}}
+                          // expected-note {{function call result aliases the storage of 'f'}} \
+                          // expected-note {{variable 'value' aliases the storage of 'f'}}
   }                       // expected-note {{destroyed here}}
   use(value);             // expected-note {{later used here}}
 }
@@ -2457,8 +2457,8 @@ void across_scope() {
   {
     std::string str{"abc"};
     s = getS(str); // expected-warning {{object whose reference is captured does not live long enough}} \
-                   // expected-note {{function call result aliases the storage of variable 'str'}} \
-                   // expected-note {{variable 's' aliases the storage of variable 'str'}}
+                   // expected-note {{function call result aliases the storage of 'str'}} \
+                   // expected-note {{variable 's' aliases the storage of 'str'}}
   }                // expected-note {{destroyed here}}
   use(s);          // expected-note {{later used here}}
 }
@@ -2472,9 +2472,9 @@ void same_scope() {
 S copy_propagation() {
   std::string str{"abc"};
   S a = getS(str); // expected-warning {{address of stack memory is returned later}} \
-                   // expected-note {{function call result aliases the storage of variable 'str'}} \
-                   // expected-note {{variable 'a' aliases the storage of variable 'str'}}
-  S b = a;         // expected-note {{variable 'b' aliases the storage of variable 'str'}}
+                   // expected-note {{function call result aliases the storage of 'str'}} \
+                   // expected-note {{variable 'a' aliases the storage of 'str'}}
+  S b = a;         // expected-note {{variable 'b' aliases the storage of 'str'}}
   return b; // expected-note {{returned here}}
 }
 
@@ -2483,9 +2483,9 @@ void assignment_propagation() {
   {
     std::string str{"abc"};
     a = getS(str); // expected-warning {{object whose reference is captured does not live long enough}} \
-                   // expected-note {{function call result aliases the storage of variable 'str'}} \
-                   // expected-note {{variable 'a' aliases the storage of variable 'str'}}
-    b = a;         // expected-note {{variable 'b' aliases the storage of variable 'str'}}
+                   // expected-note {{function call result aliases the storage of 'str'}} \
+                   // expected-note {{variable 'a' aliases the storage of 'str'}}
+    b = a;         // expected-note {{variable 'b' aliases the storage of 'str'}}
   }                // expected-note {{destroyed here}}
   use(b);          // expected-note {{later used here}}
 }
@@ -2515,8 +2515,8 @@ S multiple_lifetimebound_params() {
                                          // expected-warning {{object whose reference is captured does not live long enough}} \
                                          // expected-note {{function call result aliases the storage of the temporary}} \
                                          // expected-note {{variable 's' aliases the storage of the temporary}} \
-                                         // expected-note {{function call result aliases the storage of variable 'str'}} \
-                                         // expected-note {{variable 's' aliases the storage of variable 'str'}} \
+                                         // expected-note {{function call result aliases the storage of 'str'}} \
+                                         // expected-note {{variable 's' aliases the storage of 'str'}} \
                                          // expected-note {{destroyed here}}
   return s;                              // expected-note {{returned here}} \
                                          // expected-note {{later used here}}
@@ -2638,9 +2638,9 @@ DefaultedOuter getDefaultedOuter(const std::string &s [[clang::lifetimebound]]);
 DefaultedOuter nested_defaulted_outer_with_user_defined_inner() {
   std::string str{"abc"};
   DefaultedOuter o = getDefaultedOuter(str); // expected-warning {{address of stack memory is returned later}} \
-                                             // expected-note {{function call result aliases the storage of variable 'str'}} \
-                                             // expected-note {{variable 'o' aliases the storage of variable 'str'}}
-  DefaultedOuter copy = o;                   // expected-note {{variable 'copy' aliases the storage of variable 'str'}}
+                                             // expected-note {{function call result aliases the storage of 'str'}} \
+                                             // expected-note {{variable 'o' aliases the storage of 'str'}}
+  DefaultedOuter copy = o;                   // expected-note {{variable 'copy' aliases the storage of 'str'}}
   return copy; // expected-note {{returned here}}
 }
 
@@ -2689,10 +2689,10 @@ std::string_view return_dangling_view_through_owner() {
   std::string local;
   auto ups = getUniqueS(local);
   S* s = ups.get(); // expected-warning {{address of stack memory is returned later}} \
-                    // expected-note {{function call result aliases the storage of variable 'ups'}} \
-                    // expected-note {{variable 's' aliases the storage of variable 'ups'}}
-  std::string_view sv = s->getData(); // expected-note {{function call result aliases the storage of variable 'ups'}} \
-                                      // expected-note {{variable 'sv' aliases the storage of variable 'ups'}}
+                    // expected-note {{function call result aliases the storage of 'ups'}} \
+                    // expected-note {{variable 's' aliases the storage of 'ups'}}
+  std::string_view sv = s->getData(); // expected-note {{function call result aliases the storage of 'ups'}} \
+                                      // expected-note {{variable 'sv' aliases the storage of 'ups'}}
   return sv; // expected-note {{returned here}}
 }
 



More information about the cfe-commits mailing list