llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang-analysis

Author: PushkarSingh (iitianpushkar)

<details>
<summary>Changes</summary>

## Summary

This improves Lifetime Safety alias-chain diagnostics by explaining when an 
aliasing step comes from a `[[clang::lifetimebound]]` contract.

For example:
```cpp
int *identity(int *p [[clang::lifetimebound]]) {
  return p;
}

void test() {
  int *q;
  {
    int i;
    q = identity(&amp;i);
  }
  (void)*q;
}
```
Instead of only saying:
```text
result of call to 'identity' aliases the storage of local variable 'i'
```
the diagnostic can now say:

```
result of call to 'identity' aliases the storage of local variable 'i' because 
parameter 'p' is marked [[clang::lifetimebound]]
```
## Changes

- Track optional lifetimebound provenance on origin-flow facts.
- Preserve origin-flow facts while building the diagnostic alias chain.
- Extend alias-chain entries with optional lifetimebound information.
  - Emit a more specific note when the aliasing step is caused by:a 
lifetimebound function parameter
  - a lifetimebound implicit object parameter
- Update Lifetime Safety tests for the new diagnostic wording.

Addresses #<!-- -->199667 

---

Patch is 59.83 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/206337.diff


12 Files Affected:

- (modified) clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h 
(+15-2) 
- (modified) 
clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h (+8-1) 
- (modified) 
clang/include/clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h (+14) 
- (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+2) 
- (modified) clang/lib/Analysis/LifetimeSafety/Checker.cpp (+18-8) 
- (modified) clang/lib/Analysis/LifetimeSafety/Facts.cpp (+2) 
- (modified) clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp (+29-10) 
- (modified) clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp (+41-5) 
- (modified) clang/lib/Sema/SemaLifetimeSafety.h (+37-10) 
- (modified) clang/test/Sema/LifetimeSafety/annotation-suggestions.cpp (+6-6) 
- (modified) clang/test/Sema/LifetimeSafety/safety-c.c (+1-1) 
- (modified) clang/test/Sema/LifetimeSafety/safety.cpp (+55-54) 


``````````diff
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h 
b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h
index 5c671a93b149c..1e0ef8680f7db 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h
@@ -131,24 +131,37 @@ class ExpireFact : public Fact {
 };
 
 class OriginFlowFact : public Fact {
+public:
+  struct LifetimeBoundInfo {
+    const Expr *Call = nullptr;
+    const ParmVarDecl *Param = nullptr;
+    bool isImplicitObject = false;
+  };
+
+private:
   OriginID OIDDest;
   OriginID OIDSrc;
   // True if the destination origin should be killed (i.e., its current loans
   // cleared) before the source origin's loans are flowed into it.
   bool KillDest;
+  std::optional<LifetimeBoundInfo> LifetimeBound;
 
 public:
   static bool classof(const Fact *F) {
     return F->getKind() == Kind::OriginFlow;
   }
 
-  OriginFlowFact(OriginID OIDDest, OriginID OIDSrc, bool KillDest)
+  OriginFlowFact(OriginID OIDDest, OriginID OIDSrc, bool KillDest,
+                 std::optional<LifetimeBoundInfo> LifetimeBound = std::nullopt)
       : Fact(Kind::OriginFlow), OIDDest(OIDDest), OIDSrc(OIDSrc),
-        KillDest(KillDest) {}
+        KillDest(KillDest), LifetimeBound(LifetimeBound) {}
 
   OriginID getDestOriginID() const { return OIDDest; }
   OriginID getSrcOriginID() const { return OIDSrc; }
   bool getKillDest() const { return KillDest; }
+  std::optional<LifetimeBoundInfo> getLifetimeBoundInfo() const {
+    return LifetimeBound;
+  }
 
   void dump(llvm::raw_ostream &OS, const LoanManager &,
             const OriginManager &OM) const override;
diff --git 
a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h 
b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
index 80a23f18baebd..c177e9e222bdc 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
@@ -49,6 +49,12 @@ enum class WarningScope {
   IntraTU  // For warnings on functions local to a Translation Unit.
 };
 
+struct LifetimeSafetyAliasChainEntry {
+  const Expr *E = nullptr;
+  const ParmVarDecl *LifetimeBoundParam = nullptr;
+  bool LifetimeBoundImplicitObject = false;
+};
+
 /// Abstract interface for operations requiring Sema access.
 ///
 /// This class exists to break a circular dependency: the LifetimeSafety
@@ -67,7 +73,8 @@ class LifetimeSafetySemaHelper {
   virtual void reportUseAfterScope(const Expr *IssueExpr, const Expr *UseExpr,
                                    const Expr *MovedExpr,
                                    SourceLocation FreeLoc,
-                                   llvm::ArrayRef<const Expr *> ExprChain) {}
+                                   
llvm::ArrayRef<LifetimeSafetyAliasChainEntry>
+                                       AliasChain) {}
 
   virtual void reportUseAfterReturn(const Expr *IssueExpr,
                                     const Expr *ReturnExpr,
diff --git 
a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h 
b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h
index 724c6eee7d3c2..92d69f99c8794 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h
@@ -29,6 +29,11 @@ namespace clang::lifetimes::internal {
 using LoanSet = llvm::ImmutableSet<LoanID>;
 using OriginLoanMap = llvm::ImmutableMap<OriginID, LoanSet>;
 
+struct OriginFlowChainStep {
+  OriginID OID;
+  const OriginFlowFact *FlowFact;
+};
+
 class LoanPropagationAnalysis {
 public:
   LoanPropagationAnalysis(const CFG &C, AnalysisDeclContext &AC, FactManager 
&F,
@@ -51,6 +56,15 @@ class LoanPropagationAnalysis {
   llvm::SmallVector<OriginID>
   buildOriginFlowChain(const UseFact *UF, const LoanID TargetLoan) const;
 
+  llvm::SmallVector<OriginFlowChainStep>
+  buildOriginFlowChainWithFacts(ProgramPoint StartPoint,
+                                const OriginID StartOID,
+                                const LoanID TargetLoan) const;
+
+  llvm::SmallVector<OriginFlowChainStep>
+  buildOriginFlowChainWithFacts(const UseFact *UF,
+                                const LoanID TargetLoan) const;
+
 private:
   class Impl;
   std::unique_ptr<Impl> PImpl;
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 7e20630708312..63d7b54b5e735 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -11069,6 +11069,8 @@ def note_lifetime_safety_escapes_to_global_here: 
Note<"escapes to this global st
 def note_lifetime_safety_escapes_to_static_storage_here: Note<"escapes to this 
static storage">;
 def note_lifetime_safety_lifetimebound_here: Note<"'lifetimebound' attribute 
appears here on the definition">;
 def note_lifetime_safety_aliases_storage : Note<"%0 aliases the storage of 
%1">;
+def note_lifetime_safety_aliases_storage_lifetimebound : Note<
+  "%0 aliases the storage of %1 because %2 is marked 
[[clang::lifetimebound]]">;
 
 def warn_lifetime_safety_intra_tu_param_suggestion
     : Warning<"parameter in intra-TU function should be marked "
diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp 
b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
index 746ebbfb15c39..335ca28861f4f 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -272,7 +272,8 @@ class LifetimeChecker {
           // Scope-based expiry (use-after-scope).
           SemaHelper->reportUseAfterScope(
               IssueExpr, UF->getUseExpr(), MovedExpr, ExpiryLoc,
-              getExprChain(LoanPropagation.buildOriginFlowChain(UF, LID)));
+              getAliasChain(
+                  LoanPropagation.buildOriginFlowChainWithFacts(UF, LID)));
 
       } else if (const auto *OEF =
                      CausingFact.dyn_cast<const OriginEscapesFact *>()) {
@@ -524,13 +525,22 @@ class LifetimeChecker {
   /// Given a chain of origins that shows how a loan propagates, this function
   /// extracts the corresponding expressions for each origin. Origins that 
refer
   /// to declarations (rather than expressions) are skipped.
-  llvm::SmallVector<const Expr *>
-  getExprChain(llvm::ArrayRef<OriginID> OriginFlowChain) {
-    llvm::SmallVector<const Expr *> rs;
-    for (const OriginID CurrOID : OriginFlowChain)
-      if (const Expr *CurrExpr =
-              FactMgr.getOriginMgr().getOrigin(CurrOID).getExpr())
-        rs.push_back(CurrExpr);
+  llvm::SmallVector<LifetimeSafetyAliasChainEntry>
+  getAliasChain(llvm::ArrayRef<OriginFlowChainStep> OriginFlowChain) {
+    llvm::SmallVector<LifetimeSafetyAliasChainEntry> rs;
+    for (const OriginFlowChainStep &Step : OriginFlowChain) {
+      const Expr *CurrExpr = 
FactMgr.getOriginMgr().getOrigin(Step.OID).getExpr();
+      if (!CurrExpr)
+        continue;
+
+      LifetimeSafetyAliasChainEntry Entry;
+      Entry.E = CurrExpr;
+      if (auto Info = Step.FlowFact->getLifetimeBoundInfo()) {
+        Entry.LifetimeBoundParam = Info->Param;
+        Entry.LifetimeBoundImplicitObject = Info->isImplicitObject;
+      }
+      rs.push_back(Entry);
+    }
     return rs;
   }
 };
diff --git a/clang/lib/Analysis/LifetimeSafety/Facts.cpp 
b/clang/lib/Analysis/LifetimeSafety/Facts.cpp
index 3d7fbcdacc830..6c1fb7ba4e214 100644
--- a/clang/lib/Analysis/LifetimeSafety/Facts.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Facts.cpp
@@ -46,6 +46,8 @@ void OriginFlowFact::dump(llvm::raw_ostream &OS, const 
LoanManager &,
   OS << "\tSrc:  ";
   OM.dump(getSrcOriginID(), OS);
   OS << (getKillDest() ? "" : ", Merge");
+  if (getLifetimeBoundInfo())
+    OS << ", LifetimeBound";
   OS << "\n";
 }
 
diff --git a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp 
b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
index 8358c69a5165a..dd6838630947e 100644
--- a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
@@ -1085,28 +1085,46 @@ void FactsGenerator::handleFunctionCall(const Expr 
*Call,
     flow(CallList, getOriginsList(*Args[0]), /*Kill=*/true);
     return;
   }
-  auto IsArgLifetimeBound = [FD, &Args](unsigned I) -> bool {
+  auto GetLifetimeBoundInfo = [FD, Call](unsigned I)
+      -> std::optional<OriginFlowFact::LifetimeBoundInfo> {
     const ParmVarDecl *PVD = nullptr;
     if (const auto *Method = dyn_cast<CXXMethodDecl>(FD);
         Method && Method->isInstance() && !isa<CXXConstructorDecl>(FD)) {
       if (I == 0)
         // For the 'this' argument, the attribute is on the method itself.
-        return implicitObjectParamIsLifetimeBound(Method) ||
-               shouldTrackImplicitObjectArg(
-                   *Args[0], Method, /*RunningUnderLifetimeSafety=*/true);
+        return implicitObjectParamIsLifetimeBound(Method)
+                   ? std::optional<OriginFlowFact::LifetimeBoundInfo>(
+                         OriginFlowFact::LifetimeBoundInfo{
+                             Call, /*Param=*/nullptr,
+                             /*isImplicitObject=*/true})
+                   : std::nullopt;
       if ((I - 1) < Method->getNumParams())
         // For explicit arguments, find the corresponding parameter
         // declaration.
         PVD = Method->getParamDecl(I - 1);
+    } else if (I < FD->getNumParams()) {
+      // For free functions or static methods.
+      PVD = FD->getParamDecl(I);
+    }
+    if (PVD && PVD->hasAttr<clang::LifetimeBoundAttr>())
+      return OriginFlowFact::LifetimeBoundInfo{Call, PVD,
+                                               /*isImplicitObject=*/false};
+    return std::nullopt;
+  };
+  auto IsArgLifetimeBound = [FD, &Args, &GetLifetimeBoundInfo](unsigned I) {
+    if (GetLifetimeBoundInfo(I))
+      return true;
+    if (const auto *Method = dyn_cast<CXXMethodDecl>(FD);
+        Method && Method->isInstance() && !isa<CXXConstructorDecl>(FD)) {
+      if (I == 0)
+        return shouldTrackImplicitObjectArg(
+            *Args[0], Method, /*RunningUnderLifetimeSafety=*/true);
     } else if (I == 0 && shouldTrackFirstArgument(FD)) {
       return true;
     } else if (I == 1 && shouldTrackSecondArgument(FD)) {
       return true;
-    } else if (I < FD->getNumParams()) {
-      // For free functions or static methods.
-      PVD = FD->getParamDecl(I);
     }
-    return PVD ? PVD->hasAttr<clang::LifetimeBoundAttr>() : false;
+    return false;
   };
   auto shouldTrackPointerImplicitObjectArg = [FD, &Args](unsigned I) -> bool {
     const auto *Method = dyn_cast<CXXMethodDecl>(FD);
@@ -1148,7 +1166,7 @@ void FactsGenerator::handleFunctionCall(const Expr *Call,
         // inner origins.
         CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
             CallList->getOuterOriginID(), ArgList->getOuterOriginID(),
-            KillSrc));
+            KillSrc, GetLifetimeBoundInfo(I)));
         KillSrc = false;
       }
     } else if (shouldTrackPointerImplicitObjectArg(I)) {
@@ -1164,7 +1182,8 @@ void FactsGenerator::handleFunctionCall(const Expr *Call,
       // pointer/reference itself must not outlive the arguments. This
       // only constrains the top-level origin.
       CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
-          CallList->getOuterOriginID(), ArgList->getOuterOriginID(), KillSrc));
+          CallList->getOuterOriginID(), ArgList->getOuterOriginID(), KillSrc,
+          GetLifetimeBoundInfo(I)));
       KillSrc = false;
     }
   }
diff --git a/clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp 
b/clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp
index a67b1b3c0f826..01ef3b67e7351 100644
--- a/clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp
@@ -202,14 +202,15 @@ class AnalysisImpl
     return getLoans(getState(P), OID);
   }
 
-  llvm::SmallVector<OriginID>
-  buildOriginFlowChain(ProgramPoint StartPoint, const OriginID StartOID,
-                       const LoanID TargetLoan) const {
+  llvm::SmallVector<OriginFlowChainStep>
+  buildOriginFlowChainWithFacts(ProgramPoint StartPoint,
+                                const OriginID StartOID,
+                                const LoanID TargetLoan) const {
     assert(getLoans(StartOID, StartPoint).contains(TargetLoan) &&
            "TargetLoan must be present in the StartOID at the StartPoint");
 
     OriginID CurrOID = StartOID;
-    llvm::SmallVector<OriginID> OriginFlowChain;
+    llvm::SmallVector<OriginFlowChainStep> OriginFlowChain;
     llvm::ArrayRef<const Fact *> Facts = 
FactMgr.getBlockContaining(StartPoint);
     const auto *StartIt = llvm::find(Facts, StartPoint);
     assert(StartIt != Facts.end());
@@ -231,7 +232,7 @@ class AnalysisImpl
       const OriginID SrcOriginID = OFF->getSrcOriginID();
       if (!getLoans(SrcOriginID, OFF).contains(TargetLoan))
         continue;
-      OriginFlowChain.push_back(SrcOriginID);
+      OriginFlowChain.push_back({SrcOriginID, OFF});
       CurrOID = SrcOriginID;
     }
 
@@ -243,6 +244,28 @@ class AnalysisImpl
     return {};
   }
 
+  llvm::SmallVector<OriginID>
+  buildOriginFlowChain(ProgramPoint StartPoint, const OriginID StartOID,
+                       const LoanID TargetLoan) const {
+    llvm::SmallVector<OriginID> OriginFlowChain;
+    for (const OriginFlowChainStep &Step :
+         buildOriginFlowChainWithFacts(StartPoint, StartOID, TargetLoan))
+      OriginFlowChain.push_back(Step.OID);
+    return OriginFlowChain;
+  }
+
+  llvm::SmallVector<OriginFlowChainStep>
+  buildOriginFlowChainWithFacts(const UseFact *UF,
+                                const LoanID TargetLoan) const {
+    for (const OriginList *Cur = UF->getUsedOrigins(); Cur;
+         Cur = Cur->peelOuterOrigin())
+      if (getLoans(Cur->getOuterOriginID(), UF).contains(TargetLoan))
+        return buildOriginFlowChainWithFacts(UF, Cur->getOuterOriginID(),
+                                             TargetLoan);
+
+    return {};
+  }
+
   llvm::SmallVector<OriginID>
   buildOriginFlowChain(const UseFact *UF, const LoanID TargetLoan) const {
     for (const OriginList *Cur = UF->getUsedOrigins(); Cur;
@@ -315,4 +338,17 @@ LoanPropagationAnalysis::buildOriginFlowChain(const 
UseFact *UF,
                                               const LoanID TargetLoan) const {
   return PImpl->buildOriginFlowChain(UF, TargetLoan);
 }
+
+llvm::SmallVector<OriginFlowChainStep>
+LoanPropagationAnalysis::buildOriginFlowChainWithFacts(
+    ProgramPoint StartPoint, const OriginID StartOID,
+    const LoanID TargetLoan) const {
+  return PImpl->buildOriginFlowChainWithFacts(StartPoint, StartOID, 
TargetLoan);
+}
+
+llvm::SmallVector<OriginFlowChainStep>
+LoanPropagationAnalysis::buildOriginFlowChainWithFacts(
+    const UseFact *UF, const LoanID TargetLoan) const {
+  return PImpl->buildOriginFlowChainWithFacts(UF, TargetLoan);
+}
 } // namespace clang::lifetimes::internal
diff --git a/clang/lib/Sema/SemaLifetimeSafety.h 
b/clang/lib/Sema/SemaLifetimeSafety.h
index a3d546792fe41..3d8ca9e90abff 100644
--- a/clang/lib/Sema/SemaLifetimeSafety.h
+++ b/clang/lib/Sema/SemaLifetimeSafety.h
@@ -103,7 +103,8 @@ class LifetimeSafetySemaHelperImpl : public 
LifetimeSafetySemaHelper {
 
   void reportUseAfterScope(const Expr *IssueExpr, const Expr *UseExpr,
                            const Expr *MovedExpr, SourceLocation FreeLoc,
-                           llvm::ArrayRef<const Expr *> ExprChain) override {
+                           llvm::ArrayRef<LifetimeSafetyAliasChainEntry>
+                               AliasChain) override {
     unsigned DiagID = MovedExpr
                           ? diag::warn_lifetime_safety_use_after_scope_moved
                           : diag::warn_lifetime_safety_use_after_scope;
@@ -117,7 +118,7 @@ class LifetimeSafetySemaHelperImpl : public 
LifetimeSafetySemaHelper {
     S.Diag(FreeLoc, diag::note_lifetime_safety_destroyed_here)
         << DestroyedSubject;
 
-    reportAliasingChain(ExprChain);
+    reportAliasingChain(AliasChain);
 
     S.Diag(UseExpr->getExprLoc(), diag::note_lifetime_safety_used_here)
         << UseExpr->getSourceRange();
@@ -655,20 +656,46 @@ class LifetimeSafetySemaHelperImpl : public 
LifetimeSafetySemaHelper {
     return CurrExpr->getSourceRange() != LastExpr->getSourceRange();
   }
 
-  void reportAliasingChain(llvm::ArrayRef<const Expr *> OriginExprChain) {
+  void reportAliasingChain(
+      llvm::ArrayRef<LifetimeSafetyAliasChainEntry> OriginExprChain) {
     if (OriginExprChain.empty())
       return;
 
-    const Expr *LastExpr = OriginExprChain.back();
+    LifetimeSafetyAliasChainEntry Last = OriginExprChain.back();
+    const Expr *LastExpr = Last.E;
     std::string IssueStr = getDiagSubjectDescription(LastExpr);
 
-    for (const Expr *CurrExpr : reverse(OriginExprChain.drop_back())) {
-      if (!shouldShowInAliasChain(CurrExpr, LastExpr))
+    for (LifetimeSafetyAliasChainEntry Curr :
+         reverse(OriginExprChain.drop_back())) {
+      const Expr *CurrExpr = Curr.E;
+      if (!shouldShowInAliasChain(CurrExpr, LastExpr)) {
+        if (!Last.LifetimeBoundImplicitObject && !Last.LifetimeBoundParam &&
+            (Curr.LifetimeBoundImplicitObject || Curr.LifetimeBoundParam)) {
+          Last.LifetimeBoundImplicitObject = Curr.LifetimeBoundImplicitObject;
+          Last.LifetimeBoundParam = Curr.LifetimeBoundParam;
+        }
         continue;
-      S.Diag(CurrExpr->getBeginLoc(),
-             diag::note_lifetime_safety_aliases_storage)
-          << CurrExpr->getSourceRange() << getDiagSubjectDescription(CurrExpr)
-          << IssueStr;
+      }
+      if (Last.LifetimeBoundImplicitObject || Last.LifetimeBoundParam) {
+        std::string LifetimeBoundSubject = "the implicit object parameter";
+        if (Last.LifetimeBoundParam) {
+          LifetimeBoundSubject = "parameter ";
+          if (Last.LifetimeBoundParam->getIdentifier())
+            LifetimeBoundSubject +=
+                "'" + Last.LifetimeBoundParam->getNameAsString() + "'";
+          else
+            LifetimeBoundSubject += "'<unnamed>'";
+        }
+        S.Diag(CurrExpr->getBeginLoc(),
+               diag::note_lifetime_safety_aliases_storage_lifetimebound)
+            << CurrExpr->getSourceRange() << 
getDiagSubjectDescription(CurrExpr)
+            << IssueStr << LifetimeBoundSubject;
+      } else
+        S.Diag(CurrExpr->getBeginLoc(),
+               diag::note_lifetime_safety_aliases_storage)
+            << CurrExpr->getSourceRange() << 
getDiagSubjectDescription(CurrExpr)
+            << IssueStr;
+      Last = Curr;
       LastExpr = CurrExpr;
     }
   }
diff --git a/clang/test/Sema/LifetimeSafety/annotation-suggestions.cpp 
b/clang/test/Sema/LifetimeSafety/annotation-suggestions.cpp
index 98c528516b8e7..f551f17d8f5e4 100644
--- a/clang/test/Sema/LifetimeSafety/annotation-suggestions.cpp
+++ b/clang/test/Sema/LifetimeSafety/annotation-suggestions.cpp
@@ -278,21 +278,21 @@ View return_view_field(const ViewProvider& v) {    // 
expected-warning {{paramet
 void test_get_on_temporary_pointer() {
   const ReturnsSelf* s_ref = &ReturnsSelf().get(); // expected-warning 
{{temporary object does not live long enough}}.
                                                    // expected-note@-1 
{{temporary object is destroyed here}}
-                                                   // expected-note@-2 
{{result of call to 'get' aliases the storage of temporary object}}
+                                                   // expected-note@-2 
{{result of call to 'get' aliases the storage of temporary object because the 
implicit object parameter is marked [[clang::lifetimebound]]}}
   (void)s_ref;                                     // expected-note {{later 
used here}}
 }
 
 void test_get_on_temporary_ref() {
   const ReturnsSelf& s_ref = ReturnsSelf().get();  // expected-warning 
{{temporary object does not live long enough}}.
                                                    // expected-note@-1 
{{temporary object is destroyed here}}
-                                                   // expected-note@-2 
{{result of call to 'get' aliases the storage of temporary object}}
+                                                   // expected-note@-2 
{{result of call to 'get' aliases the storage of ...
[truncated]

``````````

</details>


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

Reply via email to