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

via cfe-commits cfe-commits at lists.llvm.org
Wed Mar 25 04:53:23 PDT 2026


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

Fixes #177986

## Summary

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.

For the following code:

```cpp
#include <cstdio>

int foo() {
  int *s;
  {
    int tgt = 2;
    int *a = &tgt;
    int *c = a;
    int *b = a;
    int *e = b;
    s = e;
  }
  printf("s: %d\n", *s);
  return 0;
}
```

Before this patch:

```bash
$ clang++ -Wlifetime-safety test-simple.cpp 
test-simple.cpp:7:15: warning: object whose reference is captured does not live long enough [-Wlifetime-safety-use-after-scope]
    7 |     int *a = &tgt;
      |               ^~~
test-simple.cpp:12:3: note: destroyed here
   12 |   }
      |   ^
test-simple.cpp:13:22: note: later used here
   13 |   printf("s: %d\n", *s);
      |                      ^
1 warning generated.

```

After this patch:

```bash
$clang++ -Wlifetime-safety test-simple.cpp 
test-simple.cpp:7:15: warning: object whose reference is captured does not live long enough [-Wlifetime-safety-use-after-scope]
    7 |     int *a = &tgt;
      |               ^~~
test-simple.cpp:12:3: note: destroyed here
   12 |   }
      |   ^
test-simple.cpp:7:15: note: variable `a` is now an alias of `tgt`
    7 |     int *a = &tgt;
      |               ^
test-simple.cpp:9:14: note: variable `b` is now an alias of `a`
    9 |     int *b = a;
      |              ^
test-simple.cpp:10:14: note: variable `e` is now an alias of `b`
   10 |     int *e = b;
      |              ^
test-simple.cpp:11:9: note: variable `s` is now an alias of `e`
   11 |     s = e;
      |         ^
test-simple.cpp:13:22: note: later used here
   13 |   printf("s: %d\n", *s);
      |                      ^
1 warning generated.
```

## Details

The implementation initiates the search from the CFG Block containing `UF->getUseExpr()`. To facilitate this, I have cached `AnalysisDeclContext &ADC` to retrieve the block via `ADC.getCFGStmtMap()->getBlock(UF->getUseExpr())`.

The search process employs BFS to traverse CFG blocks in reverse order. Within each block, Facts are traversed backward, specifically focusing on `OriginFlowFact` and `IssueFact`:

- OriginFlowFact: Generally, I would check if the current OFF->getDestOriginID() is what I want. If it is, then I would prepare to record it. The matched format is similar to `ValueDecl = Expr`.
- IssueFact: When encountering `IssueFact`, it checks if it is the Loan from the error. If so, it records `IF->getOriginID()`, and when it finds this `OriginID` in `OriginFlowFact`, it records it as the last assignment statement being found.
    - This logic specifically addresses loop back edges, where `Block->preds()` might point to the loop header rather than the loop body after a branch convergence. 

The logic for intra-block Fact traversal is encapsulated into a standalone function for better modularity. This also allows the analysis to handle cases where an `IssueFact` and `UseFact` reside within the same Block by invoking this function directly, eliminating the assumption of multi-block spans.

I will use the following code to iterate through the `UsedOrigins` of `UseFact` to ensure an assignment chain is found:

```cpp
for (const OriginList *Cur = UF->getUsedOrigins(); Cur;
         Cur = Cur->peelOuterOrigin())
```

## Testing

I didn't add any extra test cases; I simply used the existing ones. Below are the results of my local test:

```bash
$ cmake --build build/ -t check-clang-sema
[79/80] Running lit suite /var/home/suoyuan/codepjt/cpp/llvm-project/clang/test/Sema
llvm-lit: /var/home/suoyuan/codepjt/cpp/llvm-project/llvm/utils/lit/lit/llvm/config.py:569: note: using clang: /var/home/suoyuan/codepjt/cpp/llvm-project/build/bin/clang
llvm-lit: /var/home/suoyuan/codepjt/cpp/llvm-project/llvm/utils/lit/lit/llvm/subst.py:130: note: Did not find cir-opt in /var/home/suoyuan/codepjt/cpp/llvm-project/build/bin:/var/home/suoyuan/codepjt/cpp/llvm-project/build/bin

Testing Time: 10.56s

Total Discovered Tests: 1331
  Unsupported:  200 (15.03%)
  Passed     : 1131 (84.97%)

$ cmake --build build/ -t check-clang
[12/3016] Building native llvm-min-tblgen...
[8/8] Linking CXX executable bin/llvm-min-tblgen
[25/2964] Building native clang-tblgen...
[1/1] Linking CXX executable bin/clang-tblgen
[191/624] Building native llvm-tblgen...
[24/24] Linking CXX executable bin/llvm-tblgen
[327/328] Running the Clang regression tests
llvm-lit: /var/home/suoyuan/codepjt/cpp/llvm-project/llvm/utils/lit/lit/llvm/config.py:569: note: using clang: /var/home/suoyuan/codepjt/cpp/llvm-project/build/bin/clang
llvm-lit: /var/home/suoyuan/codepjt/cpp/llvm-project/llvm/utils/lit/lit/llvm/subst.py:130: note: Did not find cir-opt in /var/home/suoyuan/codepjt/cpp/llvm-project/build/bin:/var/home/suoyuan/codepjt/cpp/llvm-project/build/bin

Testing Time: 1336.82s

Total Discovered Tests: 51373
  Skipped          :     6 (0.01%)
  Unsupported      :  2597 (5.06%)
  Passed           : 48745 (94.88%)
  Expectedly Failed:    25 (0.05%)
```



>From 35940ebe476a5fc46c479ec00d87d7a72aaba064 Mon Sep 17 00:00:00 2001
From: suoyuan666 <suoyuan666 at s5n.xyz>
Date: Mon, 16 Mar 2026 09:55:36 +0800
Subject: [PATCH] [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 | 213 +++++++++-
 clang/lib/Sema/SemaLifetimeSafety.h           |  49 +++
 .../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, 579 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 e766d6e1dcf06..5a38d89e228ef 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -10984,6 +10984,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..cb21e11a3ca3f 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,195 @@ class LifetimeChecker {
     }
   }
 
+  std::optional<llvm::SmallVector<AssignmentPair>>
+  getAliasListInMultiBlock(const CFGBlock *StartBlock, const LoanID EndLoanID,
+                           OriginID *StartOID) {
+    const ValueDecl *LastDestDecl = nullptr;
+    std::queue<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(StartBlock);
+
+    while (!PendingBlocks.empty()) {
+      const CFGBlock *CurrBlock = PendingBlocks.front();
+      PendingBlocks.pop();
+
+      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(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 +440,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..0f75e52e6c120 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,54 @@ 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 outString;
+        llvm::raw_string_ostream ss(outString);
+
+        LangOptions lo;
+        PrintingPolicy policy(lo);
+
+        if (const Expr *callee = CurrCallExpr->getCallee()) {
+          callee->IgnoreParenCasts()->printPretty(ss, nullptr, policy);
+        }
+
+        ss << "(";
+
+        for (unsigned i = 0; i < CurrCallExpr->getNumArgs(); ++i) {
+          const Expr *arg = CurrCallExpr->getArg(i);
+          if (arg) {
+            arg->printPretty(ss, nullptr, policy);
+          }
+
+          if (i < CurrCallExpr->getNumArgs() - 1) {
+            ss << ", ";
+          }
+        }
+
+        ss << ")";
+        S.Diag(CurrCallExpr->getExprLoc(),
+               diag::note_lifetime_safety_note_alias_chain)
+            << (*AliasStmt).second->getNameAsString() << ss.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 a725119444e2f..247349cdb0cfb 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 22c4222022ebf..75a828e8d6f9f 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 76d43445f8636..2e2004e574830 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}}
 }
@@ -995,7 +1046,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}}
 
@@ -1011,8 +1063,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}}
 }
@@ -1021,10 +1075,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}}
 }
@@ -1033,7 +1091,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}}
@@ -1043,7 +1103,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}}
@@ -1053,7 +1115,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}}
@@ -1065,29 +1131,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}}
 
@@ -1096,20 +1164,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}}
 }
 
@@ -1151,7 +1219,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}}
 }
@@ -1170,8 +1238,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}}
@@ -1191,7 +1260,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}}
@@ -1224,7 +1294,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}}
 }
@@ -1241,7 +1312,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}}
 }
@@ -1251,7 +1323,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}}
 }
@@ -1261,7 +1334,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}}
 }
@@ -1295,15 +1369,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}}
 }
@@ -1412,7 +1486,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}}
@@ -1426,7 +1501,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}}
 }
@@ -1436,7 +1511,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}}
@@ -1446,13 +1523,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}}
 }
@@ -1463,7 +1542,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}}
@@ -1485,9 +1565,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}}
@@ -1575,17 +1656,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}}
 }
@@ -1593,12 +1679,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
@@ -1614,8 +1704,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}}
 }
@@ -1640,8 +1731,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}}
 }
@@ -1657,8 +1749,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}}
 }
@@ -1716,9 +1808,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}}
@@ -1753,7 +1851,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}}
 }
@@ -1762,7 +1861,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}}
 }
@@ -1771,7 +1871,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}}
 }
@@ -1962,8 +2063,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}}
@@ -1974,7 +2076,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}}
 }
@@ -1987,7 +2090,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}}
 }
@@ -2019,7 +2123,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}}
 }
@@ -2032,7 +2137,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}}
 }
@@ -2041,7 +2147,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}}
 }
@@ -2050,7 +2157,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}}
 }
@@ -2118,9 +2226,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}}
 



More information about the cfe-commits mailing list