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

>From bfa790315f83314e8cb7eb226f55e0503aee5cef Mon Sep 17 00:00:00 2001
From: suoyuan666 <[email protected]>
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 <[email protected]>
---
 .../Analyses/LifetimeSafety/AssignmentQuery.h |  48 +++
 .../Analyses/LifetimeSafety/LifetimeSafety.h  |  14 +-
 .../clang/Basic/DiagnosticSemaKinds.td        |   1 +
 .../LifetimeSafety/AssignmentQuery.cpp        | 226 +++++++++++
 .../Analysis/LifetimeSafety/CMakeLists.txt    |   1 +
 clang/lib/Analysis/LifetimeSafety/Checker.cpp |  16 +-
 clang/lib/Sema/SemaLifetimeSafety.h           |  27 +-
 .../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 ++++++++++++------
 11 files changed, 633 insertions(+), 167 deletions(-)
 create mode 100644 
clang/include/clang/Analysis/Analyses/LifetimeSafety/AssignmentQuery.h
 create mode 100644 clang/lib/Analysis/LifetimeSafety/AssignmentQuery.cpp

diff --git 
a/clang/include/clang/Analysis/Analyses/LifetimeSafety/AssignmentQuery.h 
b/clang/include/clang/Analysis/Analyses/LifetimeSafety/AssignmentQuery.h
new file mode 100644
index 0000000000000..dd36b3e8f1bcb
--- /dev/null
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/AssignmentQuery.h
@@ -0,0 +1,48 @@
+//===- AssignmentQuery.cpp - C++ Lifetime Safety Analysis -*- 
C++-*-==========//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines and enforces the lifetime safety policy. It detects
+// use-after-free errors by examining loan expiration points and checking if
+// any live origins hold the expired loans.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_ASSIGNMENTQUERY_H
+#define LLVM_CLANG_ANALYSIS_ANALYSES_ASSIGNMENTQUERY_H
+
+#include "clang/AST/Decl.h"
+#include "clang/AST/Expr.h"
+#include "clang/Analysis/Analyses/LifetimeSafety/Facts.h"
+#include "clang/Analysis/Analyses/LifetimeSafety/LiveOrigins.h"
+#include "clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h"
+#include "clang/Analysis/Analyses/LifetimeSafety/MovedLoans.h"
+
+namespace clang::lifetimes::internal {
+
+using DestOriginExpr =
+    llvm::PointerUnion<const DeclRefExpr *, const CXXTemporaryObjectExpr *,
+                       const CallExpr *>;
+
+struct AssignmentQueryContext {
+  FactManager &FactMgr;
+  AnalysisDeclContext &ADC;
+  const LoanPropagationAnalysis &LoanPropagation;
+  const LiveOriginsAnalysis &LiveOrigins;
+  const MovedLoansAnalysis &MovedLoans;
+};
+
+/// 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.
+const std::optional<llvm::SmallVector<DestOriginExpr>>
+getAssignmentChain(const AssignmentQueryContext &Context,
+                   const Fact *CausingFact, const LoanID &EndLoanID);
+} // namespace clang::lifetimes::internal
+
+#endif // LLVM_CLANG_ANALYSIS_ANALYSES_ASSIGNMENTQUERY_H
diff --git 
a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h 
b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
index 08038dd096685..803f04407d385 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
@@ -21,6 +21,7 @@
 #define LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_H
 
 #include "clang/AST/Decl.h"
+#include "clang/Analysis/Analyses/LifetimeSafety/AssignmentQuery.h"
 #include "clang/Analysis/Analyses/LifetimeSafety/Facts.h"
 #include "clang/Analysis/Analyses/LifetimeSafety/LifetimeStats.h"
 #include "clang/Analysis/Analyses/LifetimeSafety/LiveOrigins.h"
@@ -45,6 +46,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 +66,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 std::optional<llvm::SmallVector<internal::DestOriginExpr>>
+          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 db1e3630435d0..16c64ecadc1d9 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -10999,6 +10999,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/AssignmentQuery.cpp 
b/clang/lib/Analysis/LifetimeSafety/AssignmentQuery.cpp
new file mode 100644
index 0000000000000..cac534de6cd42
--- /dev/null
+++ b/clang/lib/Analysis/LifetimeSafety/AssignmentQuery.cpp
@@ -0,0 +1,226 @@
+//===- AssignmentQuery.cpp - C++ Lifetime Safety Analysis -*- 
C++-*-==========//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines and enforces the lifetime safety policy. It detects
+// use-after-free errors by examining loan expiration points and checking if
+// any live origins hold the expired loans.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/Analyses/LifetimeSafety/AssignmentQuery.h"
+#include "clang/AST/Expr.h"
+#include "clang/Analysis/Analyses/LifetimeSafety/Facts.h"
+#include "clang/Analysis/CFG.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace {
+using namespace clang;
+using namespace clang::lifetimes::internal;
+
+struct AliasAssignmentSearchResult {
+  const llvm::SmallVector<DestOriginExpr> Payload;
+  const bool SearchComplete;
+  const std::optional<OriginID> LastOrigin;
+};
+
+const std::optional<DestOriginExpr> 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;
+}
+
+const AliasAssignmentSearchResult getAssignmentChainCore(
+    const AssignmentQueryContext &Context, const CFGBlock *Block,
+    const LoanID EndLoanID, OriginID *TargetOID,
+    const std::optional<OriginID> LastOriginID = std::nullopt) {
+  llvm::SmallVector<DestOriginExpr> AliasStmts;
+  const auto Facts = Context.FactMgr.getFacts(Block);
+  bool FetchLoan = false;
+  auto IssueOriginID = LastOriginID;
+  const SourceManager &SM = Context.ADC.getASTContext().getSourceManager();
+
+  const auto DestOriginExpr2Expr =
+      [](const DestOriginExpr &TargetExpr) -> const Expr * {
+    if (const auto *DExpr = llvm::dyn_cast<const DeclRefExpr *>(TargetExpr))
+      return DExpr;
+    if (const auto *DCTExpr =
+            llvm::dyn_cast<const CXXTemporaryObjectExpr *>(TargetExpr))
+      return DCTExpr;
+    if (const auto *DCExpr = llvm::dyn_cast<const CallExpr *>(TargetExpr))
+      return DCExpr;
+    return nullptr;
+  };
+
+  for (auto F = Facts.rbegin(), FEnd = Facts.rend(); F != FEnd; ++F) {
+    if (const auto *OFF = (*F)->getAs<OriginFlowFact>()) {
+      OFF->dump(llvm::outs(), Context.FactMgr.getLoanMgr(),
+                Context.FactMgr.getOriginMgr());
+      if (IssueOriginID.has_value() &&
+          OFF->getDestOriginID() == IssueOriginID.value())
+        FetchLoan = true;
+
+      if (OFF->getDestOriginID() == *TargetOID) {
+        const auto HeldLoans =
+            Context.LoanPropagation.getLoans(OFF->getSrcOriginID(), OFF);
+
+        if (HeldLoans.contains(EndLoanID)) {
+          const auto TargetOrigin =
+              Context.FactMgr.getOriginMgr().getOrigin(OFF->getDestOriginID());
+
+          const auto DExpr = getPureSrcExpr(TargetOrigin.getExpr());
+
+          if (DExpr.has_value()) {
+            if (AliasStmts.empty()) {
+              llvm::outs() << "Empty Insert!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n";
+              AliasStmts.push_back(DExpr.value());
+            } else {
+              const Expr *LastExpr =
+                  DestOriginExpr2Expr(AliasStmts[AliasStmts.size() - 1]);
+              const Expr *CurrExpr = DestOriginExpr2Expr(DExpr.value());
+              if (SM.getSpellingLineNumber(LastExpr->getBeginLoc()) ==
+                  SM.getSpellingLineNumber(CurrExpr->getBeginLoc())) {
+                if (llvm::isa<const DeclRefExpr *>(
+                        AliasStmts[AliasStmts.size() - 1]) &&
+                    !llvm::isa<const DeclRefExpr *>(DExpr.value())) {
+                  llvm::outs() << "Replace!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n";
+                  AliasStmts[AliasStmts.size() - 1] = DExpr.value();
+                }
+              } else {
+                llvm::outs() << "Insert!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n";
+                AliasStmts.push_back(DExpr.value());
+              }
+            }
+          }
+          *TargetOID = OFF->getSrcOriginID();
+        }
+      }
+    } else if (const auto *IF = (*F)->getAs<IssueFact>())
+      if (IF->getLoanID() == EndLoanID)
+        IssueOriginID = IF->getOriginID();
+
+    if (FetchLoan)
+      return {AliasStmts, true, IssueOriginID};
+  }
+  return {AliasStmts, false, IssueOriginID};
+}
+
+const std::optional<llvm::SmallVector<DestOriginExpr>>
+getAssignmentChainInMultiBlock(const AssignmentQueryContext &Context,
+                               const CFGBlock *StartBlock,
+                               const LoanID EndLoanID, OriginID *StartOID) {
+  llvm::SmallVector<const CFGBlock *> PendingBlocks;
+  std::optional<DestOriginExpr> StartStmt = std::nullopt;
+  std::optional<DestOriginExpr> EndStmt = std::nullopt;
+  std::optional<OriginID> LastOriginID = std::nullopt;
+  llvm::SmallPtrSet<const CFGBlock *, 32> VistedBlocks;
+  llvm::DenseMap<DestOriginExpr, DestOriginExpr> VistedExprs;
+
+  const auto AliasStmtFilter = [&VistedExprs](const DestOriginExpr StartStmt,
+                                              const DestOriginExpr EndStmt) {
+    llvm::SmallVector<DestOriginExpr> AliasStmts;
+    for (auto Stmt = StartStmt; Stmt != EndStmt; Stmt = VistedExprs.at(Stmt)) {
+      AliasStmts.push_back(Stmt);
+    }
+    AliasStmts.push_back(EndStmt);
+    return AliasStmts;
+  };
+
+  PendingBlocks.push_back(StartBlock);
+
+  for (size_t i = 0; i < PendingBlocks.size(); ++i) {
+    const CFGBlock *CurrBlock = PendingBlocks[i];
+    const auto [BlockAliasList, Success, CurrLastOriginID] =
+        getAssignmentChainCore(Context, CurrBlock, EndLoanID, StartOID,
+                               LastOriginID);
+    if (CurrLastOriginID.has_value())
+      LastOriginID = CurrLastOriginID;
+
+    if (!BlockAliasList.empty()) {
+      if (VistedExprs.empty())
+        StartStmt = BlockAliasList[0];
+
+      for (size_t i = 0; i < BlockAliasList.size() - 1; ++i)
+        VistedExprs.insert({BlockAliasList[i], BlockAliasList[i + 1]});
+
+      if (EndStmt.has_value())
+        VistedExprs.insert({EndStmt.value(), BlockAliasList[0]});
+
+      EndStmt = BlockAliasList[BlockAliasList.size() - 1];
+    }
+
+    if (Success && StartStmt.has_value() && EndStmt.has_value())
+      return AliasStmtFilter(StartStmt.value(), EndStmt.value());
+
+    for (const auto Block : CurrBlock->preds())
+      if (Block && VistedBlocks.insert(Block).second)
+        PendingBlocks.push_back(Block);
+
+    if (VistedBlocks.size() >= 32 && StartStmt.has_value() &&
+        EndStmt.has_value())
+      return AliasStmtFilter(StartStmt.value(), EndStmt.value());
+  }
+
+  if (StartStmt.has_value() && EndStmt.has_value())
+    return AliasStmtFilter(StartStmt.value(), EndStmt.value());
+
+  return std::nullopt;
+}
+
+} // namespace
+
+namespace clang::lifetimes::internal {
+const std::optional<llvm::SmallVector<DestOriginExpr>>
+getAssignmentChain(const AssignmentQueryContext &Context,
+                   const Fact *CausingFact, const LoanID &EndLoanID) {
+  const auto *UF = llvm::dyn_cast<UseFact>(CausingFact);
+  const CFGBlock *StartBlock =
+      Context.ADC.getCFGStmtMap()->getBlock(UF->getUseExpr());
+  assert(StartBlock && "Searching Start CFGBlock failed");
+  const CFGBlock *EndBlock = Context.ADC.getCFGStmtMap()->getBlock(
+      Context.FactMgr.getLoanMgr().getLoan(EndLoanID)->getIssuingExpr());
+  assert(StartBlock && "Searching End CFGBlock failed");
+
+  for (const OriginList *Cur = UF->getUsedOrigins(); Cur;
+       Cur = Cur->peelOuterOrigin()) {
+    auto TargetOID = Cur->getOuterOriginID();
+    if (StartBlock == EndBlock) {
+      AliasAssignmentSearchResult Result =
+          getAssignmentChainCore(Context, StartBlock, EndLoanID, &TargetOID);
+      if (!Result.Payload.empty())
+        return Result.Payload;
+    } else {
+      auto Result = getAssignmentChainInMultiBlock(Context, StartBlock,
+                                                   EndLoanID, &TargetOID);
+      if (Result.has_value())
+        return Result.value();
+    }
+  }
+
+  return std::nullopt;
+}
+} // namespace clang::lifetimes::internal
diff --git a/clang/lib/Analysis/LifetimeSafety/CMakeLists.txt 
b/clang/lib/Analysis/LifetimeSafety/CMakeLists.txt
index 247377c7256d9..6c4d4e123908a 100644
--- a/clang/lib/Analysis/LifetimeSafety/CMakeLists.txt
+++ b/clang/lib/Analysis/LifetimeSafety/CMakeLists.txt
@@ -1,4 +1,5 @@
 add_clang_library(clangAnalysisLifetimeSafety
+  AssignmentQuery.cpp
   Checker.cpp
   Facts.cpp
   FactsGenerator.cpp
diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp 
b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
index 36477c6f67b52..20342d2b80838 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -14,6 +14,7 @@
 #include "clang/Analysis/Analyses/LifetimeSafety/Checker.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/Expr.h"
+#include "clang/Analysis/Analyses/LifetimeSafety/AssignmentQuery.h"
 #include "clang/Analysis/Analyses/LifetimeSafety/Facts.h"
 #include "clang/Analysis/Analyses/LifetimeSafety/LifetimeAnnotations.h"
 #include "clang/Analysis/Analyses/LifetimeSafety/LiveOrigins.h"
@@ -67,6 +68,7 @@ class LifetimeChecker {
   FactManager &FactMgr;
   LifetimeSafetySemaHelper *SemaHelper;
   ASTContext &AST;
+  AnalysisDeclContext &ADC;
 
   static SourceLocation
   GetFactLoc(llvm::PointerUnion<const UseFact *, const OriginEscapesFact *> F) 
{
@@ -89,7 +91,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>())
@@ -243,10 +245,18 @@ class LifetimeChecker {
             SemaHelper->reportUseAfterInvalidation(
                 InvalidatedPVD, UF->getUseExpr(), Warning.InvalidatedByExpr);
 
-        } else
+        } else {
           // Scope-based expiry (use-after-scope).
+          const AssignmentQueryContext AQContext = {
+              FactMgr, ADC, LoanPropagation, LiveOrigins, MovedLoans};
+          const auto AliasExprs = getAssignmentChain(AQContext, UF, LID);
+          if (!AliasExprs.has_value())
+            llvm::dbgs() << "GetAssignmentChain: Search variable assignment "
+                            "chain failed\n";
+
           SemaHelper->reportUseAfterFree(IssueExpr, UF->getUseExpr(), 
MovedExpr,
-                                         ExpiryLoc);
+                                         AliasExprs, 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..ab2b03bc26cb5 100644
--- a/clang/lib/Sema/SemaLifetimeSafety.h
+++ b/clang/lib/Sema/SemaLifetimeSafety.h
@@ -15,10 +15,12 @@
 #ifndef LLVM_CLANG_LIB_SEMA_SEMALIFETIMESAFETY_H
 #define LLVM_CLANG_LIB_SEMA_SEMALIFETIMESAFETY_H
 
+#include "clang/Analysis/Analyses/LifetimeSafety/AssignmentQuery.h"
 #include "clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h"
 #include "clang/Basic/DiagnosticSema.h"
 #include "clang/Lex/Lexer.h"
 #include "clang/Sema/Sema.h"
+#include "llvm/Support/Casting.h"
 
 namespace clang::lifetimes {
 
@@ -43,9 +45,11 @@ class LifetimeSafetySemaHelperImpl : public 
LifetimeSafetySemaHelper {
 public:
   LifetimeSafetySemaHelperImpl(Sema &S) : S(S) {}
 
-  void reportUseAfterFree(const Expr *IssueExpr, const Expr *UseExpr,
-                          const Expr *MovedExpr,
-                          SourceLocation FreeLoc) override {
+  void reportUseAfterFree(
+      const Expr *IssueExpr, const Expr *UseExpr, const Expr *MovedExpr,
+      const std::optional<llvm::SmallVector<internal::DestOriginExpr>>
+          AliasList,
+      SourceLocation FreeLoc) override {
     S.Diag(IssueExpr->getExprLoc(),
            MovedExpr ? diag::warn_lifetime_safety_use_after_scope_moved
                      : diag::warn_lifetime_safety_use_after_scope)
@@ -54,6 +58,23 @@ 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);
+
+    if (AliasList.has_value()) {
+      for (auto AliasStmt = AliasList.value().rbegin(),
+                AliasStmtEnd = AliasList.value().rend();
+           AliasStmt != AliasStmtEnd; ++AliasStmt) {
+        if (const auto *CurrDeclExpr =
+                llvm::dyn_cast<const DeclRefExpr *>((*AliasStmt))) {
+          S.Diag(CurrDeclExpr->getBeginLoc(),
+                 diag::note_lifetime_safety_note_alias_chain)
+              << CurrDeclExpr->getDecl()->getNameAsString()
+              << llvm::dyn_cast<DeclRefExpr>(IssueExpr)
+                     ->getDecl()
+                     ->getNameAsString();
+        }
+      }
+    }
+
     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@-1 
{{destroyed here}}
+                                                   // expected-note@-1 
{{destroyed here}}.
+                                                   // expected-note@-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@-1 
{{destroyed here}}
+                                                   // expected-note@-1 
{{destroyed here}}.
+                                                   // expected-note@-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@-1 {{destroyed 
here}}
+                                            // expected-note@-1 {{destroyed 
here}}.
+                                            // expected-note@-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@-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@-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}}
 

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

Reply via email to