llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang-analysis

Author: Gábor Horváth (Xazax-hun)

<details>
<summary>Changes</summary>

Previously every DeclRefExpr was a use, so naming a pointer, taking its address
or copying it counted as reading what it points to. Writes were then exempted
after the fact through a UseFact -&gt; Expr map and a special case for writes
through references.

Now a use is an access: an lvalue-to-rvalue conversion, a write through an
assignment, increment or asm output, or a copy of a class object from a glvalue.
It is recorded on the accessed lvalue's outer origin, the loans saying which
storage it may name. The visitors for `*p`, `p-&gt;f` and `p[i]` already flow 
the
base pointer there, so dereferences need no special handling. Reads of a value
go through readValue(), which records the access; writes peel the outer origin
directly. Values handed to opaque code still use every level.

Consequences:
  - Copying a pointer, taking an address, `(void)p` and `p++` are not uses.
  - Writing through a dangling pointer (`*p = 1`, `p-&gt;f = 1`) is now 
diagnosed.
  - An access of an origin that names a declaration outright is skipped: it
    only holds a loan to that declaration, which is valid wherever it is named.
  - UseFact::IsWritten and markUseAsWrite are removed; kills on assignment
    already come from the destination's OriginFlowFact or KillOriginFact.

Fewer use facts are generated, e.g. on the lifetime-safety lit tests:
  safety.cpp          1886 -&gt; 882
  invalidations.cpp    616 -&gt; 451
  nocfg.cpp            544 -&gt; 415
  capture-by.cpp       395 -&gt; 324

Assisted by: Opus 5.5

---

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


24 Files Affected:

- (modified) clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h (-6) 
- (modified) 
clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h (+13-11) 
- (modified) 
clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h (+2) 
- (modified) clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h 
(+4) 
- (modified) clang/lib/Analysis/LifetimeSafety/Checker.cpp (+15-6) 
- (modified) clang/lib/Analysis/LifetimeSafety/Facts.cpp (+1-1) 
- (modified) clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp (+87-92) 
- (modified) clang/lib/Analysis/LifetimeSafety/LifetimeAnnotations.cpp (+1-4) 
- (modified) clang/lib/Analysis/LifetimeSafety/LiveOrigins.cpp (+5-13) 
- (modified) clang/lib/Analysis/LifetimeSafety/Origins.cpp (+11-1) 
- (modified) clang/test/Sema/LifetimeSafety/Inputs/lifetime-analysis.h (+5) 
- (modified) clang/test/Sema/LifetimeSafety/annotation-suggestions.cpp (+7-7) 
- (modified) clang/test/Sema/LifetimeSafety/capture-by.cpp (+66-66) 
- (modified) clang/test/Sema/LifetimeSafety/cfg-bailout.cpp (+3-1) 
- (modified) clang/test/Sema/LifetimeSafety/dangling-field.cpp (+18-3) 
- (modified) clang/test/Sema/LifetimeSafety/dangling-global.cpp (+1-1) 
- (modified) clang/test/Sema/LifetimeSafety/inapplicable-lifetimebound.cpp 
(+1-1) 
- (modified) clang/test/Sema/LifetimeSafety/invalidations.cpp (+37-37) 
- (modified) clang/test/Sema/LifetimeSafety/lifetime-facts.cpp (+66-9) 
- (modified) clang/test/Sema/LifetimeSafety/lifetimebound-violation.cpp (+1-1) 
- (modified) clang/test/Sema/LifetimeSafety/nocfg.cpp (+2-3) 
- (modified) clang/test/Sema/LifetimeSafety/noescape-violation.cpp (+1-1) 
- (modified) clang/test/Sema/LifetimeSafety/safety.cpp (+528-209) 
- (modified) clang/unittests/Analysis/LifetimeSafetyTest.cpp (+101-9) 


``````````diff
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h 
b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h
index 794e0cd30b9e5f..16fe31a577fa1b 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h
@@ -246,9 +246,6 @@ class GlobalEscapeFact : public OriginEscapesFact {
 class UseFact : public Fact {
   const Expr *UseExpr;
   const OriginList *OList;
-  // True if this use is a write operation (e.g., left-hand side of 
assignment).
-  // Write operations are exempted from use-after-free checks.
-  bool IsWritten = false;
 
 public:
   static bool classof(const Fact *F) { return F->getKind() == Kind::Use; }
@@ -257,10 +254,7 @@ class UseFact : public Fact {
       : Fact(Kind::Use), UseExpr(UseExpr), OList(OList) {}
 
   const OriginList *getUsedOrigins() const { return OList; }
-  void setUsedOrigins(const OriginList *NewList) { OList = NewList; }
   const Expr *getUseExpr() const { return UseExpr; }
-  void markAsWritten() { IsWritten = true; }
-  bool isWritten() const { return IsWritten; }
 
   void dump(llvm::raw_ostream &OS, const LoanManager &, const OriginManager 
&OM,
             const LoanPropagationAnalysis *LPA = nullptr) const override;
diff --git 
a/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h 
b/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h
index ec5027965002e4..e9f2a4789241c0 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h
@@ -57,6 +57,9 @@ class FactsGenerator : public 
ConstStmtVisitor<FactsGenerator> {
   void VisitArraySubscriptExpr(const ArraySubscriptExpr *ASE);
   void VisitCXXNewExpr(const CXXNewExpr *NE);
   void VisitCXXDeleteExpr(const CXXDeleteExpr *DE);
+  void VisitCXXThrowExpr(const CXXThrowExpr *TE);
+  void VisitGCCAsmStmt(const GCCAsmStmt *AS);
+  void VisitCXXTypeidExpr(const CXXTypeidExpr *TE);
   void VisitStmtExpr(const StmtExpr *SE);
 
 private:
@@ -138,12 +141,17 @@ class FactsGenerator : public 
ConstStmtVisitor<FactsGenerator> {
   /// If so, creates a `TestPointFact` and returns true.
   bool handleTestPoint(const CXXFunctionalCastExpr *FCE);
 
-  // Treats an expression as a use of the referenced object. It will be
-  // checked for use-after-free unless it is later marked as being written to
-  // (e.g. on the left-hand side of an assignment in the case of a 
DeclRefExpr).
-  void handleUse(const Expr *E);
+  bool namesDeclStorage(const OriginList *List) const;
+
+  OriginList *readValue(const Expr *E);
 
-  void markUseAsWrite(const DeclRefExpr *DRE);
+  /// Records an access (read or write) of the storage \p E designates, or that
+  /// a prvalue pointer \p E points to.
+  void handleAccess(const Expr *E);
+
+  /// Records that \p E's value is handed to opaque code, which may dereference
+  /// it to any depth.
+  void handleUse(const Expr *E);
 
   bool escapesViaReturn(OriginID OID) const;
 
@@ -155,12 +163,6 @@ class FactsGenerator : public 
ConstStmtVisitor<FactsGenerator> {
   // appended at the end of CurrentBlockFacts to ensure they appear after
   // ExpireFact entries.
   llvm::SmallVector<Fact *> EscapesInCurrentBlock;
-  // To distinguish between reads and writes for use-after-free checks, this 
map
-  // stores the `UseFact` for each `DeclRefExpr`. We initially identify all
-  // `DeclRefExpr`s as "read" uses. When an assignment is processed, the use
-  // corresponding to the left-hand side is updated to be a "write", thereby
-  // exempting it from the check.
-  llvm::DenseMap<const Expr *, UseFact *> UseFacts;
   const CFGBlock *CurrentBlock;
   bool IsCMode = false;
 };
diff --git 
a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h 
b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
index 68e84961010ddf..18e5e8473e4144 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
@@ -74,6 +74,8 @@ class LifetimeSafetySemaHelper {
                                    SourceLocation FreeLoc,
                                    llvm::ArrayRef<const Expr *> ExprChain) {}
 
+  // TODO: Pass the expiry location and aliasing chain like
+  // reportUseAfterScope.
   virtual void reportUseAfterReturn(const Expr *IssueExpr,
                                     const Expr *ReturnExpr,
                                     const Expr *MovedExpr) {}
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h 
b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h
index 6ab2f59283ad3c..b4a7ec2832d712 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h
@@ -53,6 +53,10 @@ struct Origin {
   /// Null for synthetic lvalue origins (e.g., outer origin of DeclRefExpr).
   const Type *Ty;
 
+  /// True if this origin only holds a loan to a declaration named in scope, so
+  /// it can never hold an expired loan.
+  bool NamesDeclStorage = false;
+
   Origin(OriginID ID, const clang::ValueDecl *D, const Type *QT)
       : ID(ID), Ptr(D), Ty(QT) {}
   Origin(OriginID ID, const clang::Expr *E, const Type *QT)
diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp 
b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
index c4cc872dcd568d..a590491df23e74 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -24,6 +24,7 @@
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Basic/SourceManager.h"
 #include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/TimeProfiler.h"
 
@@ -557,14 +558,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.
+  ///
+  /// Until the chain reaches a declaration it is inside the use expression,
+  /// where casts just load the used variable.
   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);
-    return rs;
+    llvm::SmallVector<const Expr *> Chain;
+    bool InUse = true;
+    for (const OriginID CurrOID : OriginFlowChain) {
+      const Expr *CurrExpr =
+          FactMgr.getOriginMgr().getOrigin(CurrOID).getExpr();
+      if (!CurrExpr)
+        InUse = false;
+      else if (!InUse || !isa<ImplicitCastExpr>(CurrExpr))
+        Chain.push_back(CurrExpr);
+    }
+    return Chain;
   }
 };
 } // namespace
diff --git a/clang/lib/Analysis/LifetimeSafety/Facts.cpp 
b/clang/lib/Analysis/LifetimeSafety/Facts.cpp
index a56774327731c2..2d3c161ae8f113 100644
--- a/clang/lib/Analysis/LifetimeSafety/Facts.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Facts.cpp
@@ -167,7 +167,7 @@ void UseFact::dump(llvm::raw_ostream &OS, const LoanManager 
&,
     if (I < NumUsedOrigins - 1)
       OS << ", ";
   }
-  OS << ", " << (isWritten() ? "Write" : "Read") << ")\n";
+  OS << ")\n";
 }
 
 void InvalidateOriginFact::dump(llvm::raw_ostream &OS, const LoanManager &,
diff --git a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp 
b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
index 98760dba188821..091935df1a509e 100644
--- a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
@@ -153,17 +153,17 @@ void FactsGenerator::run() {
   FactMgr.computePersistentOrigins(Cfg);
 }
 
-/// Simulates LValueToRValue conversion by peeling the outer lvalue origin
-/// if the expression is a GLValue. For pointer/view GLValues, this strips
-/// the origin representing the storage location to get the origins of the
-/// pointed-to value.
+/// Returns the origins of the value \p E evaluates to, recording the read of a
+/// glvalue. Writes peel the outer origin directly instead.
 ///
 /// Example: For `View& v`, returns the origin of what v points to, not v's
 /// storage.
-static OriginList *getRValueOrigins(const Expr *E, OriginList *List) {
-  if (!List)
-    return nullptr;
-  return E->isGLValue() ? List->peelOuterOrigin() : List;
+OriginList *FactsGenerator::readValue(const Expr *E) {
+  OriginList *List = getOriginsList(*E);
+  if (!E->isGLValue())
+    return List;
+  handleAccess(E);
+  return List ? List->peelOuterOrigin() : nullptr;
 }
 
 void FactsGenerator::VisitDeclStmt(const DeclStmt *DS) {
@@ -184,7 +184,6 @@ void FactsGenerator::VisitDeclRefExpr(const DeclRefExpr 
*DRE) {
   // GLValues (like EnumConstants).
   if (DRE->getFoundDecl()->isFunctionOrFunctionTemplate() || !DRE->isGLValue())
     return;
-  handleUse(DRE);
   // For all declarations with storage (non-references), we issue a loan
   // representing the borrow of the variable's storage itself.
   //
@@ -218,7 +217,7 @@ void FactsGenerator::VisitCXXConstructExpr(const 
CXXConstructExpr *CCE) {
       CCE->getConstructor()->isDefaulted() && CCE->getNumArgs() == 1 &&
       hasOrigins(CCE->getType())) {
     const Expr *Arg = CCE->getArg(0);
-    if (OriginList *ArgList = getRValueOrigins(Arg, getOriginsList(*Arg))) {
+    if (OriginList *ArgList = readValue(Arg)) {
       flow(getOriginsList(*CCE), ArgList, /*Kill=*/true);
       return;
     }
@@ -228,7 +227,7 @@ void FactsGenerator::VisitCXXConstructExpr(const 
CXXConstructExpr *CCE) {
   if (const auto *RD = CCE->getType()->getAsCXXRecordDecl();
       RD && isStdCallableWrapperType(RD) && CCE->getNumArgs() == 1) {
     const Expr *Arg = CCE->getArg(0);
-    if (OriginList *ArgList = getRValueOrigins(Arg, getOriginsList(*Arg))) {
+    if (OriginList *ArgList = readValue(Arg)) {
       flow(getOriginsList(*CCE), ArgList, /*Kill=*/true);
       return;
     }
@@ -288,10 +287,17 @@ void FactsGenerator::VisitCXXNullPtrLiteralExpr(
 }
 
 void FactsGenerator::VisitCastExpr(const CastExpr *CE) {
+  const Expr *SubExpr = CE->getSubExpr();
+  const CastKind Kind = CE->getCastKind();
+  const bool Loads =
+      Kind == CK_LValueToRValue || Kind == CK_LValueToRValueBitCast;
+  OriginList *Loaded = Loads ? readValue(SubExpr) : nullptr;
+  if (Kind == CK_Dynamic)
+    handleAccess(SubExpr);
+
   OriginList *Dest = getOriginsList(*CE);
   if (!Dest)
     return;
-  const Expr *SubExpr = CE->getSubExpr();
   OriginList *Src = getOriginsList(*SubExpr);
 
   switch (CE->getCastKind()) {
@@ -302,10 +308,8 @@ void FactsGenerator::VisitCastExpr(const CastExpr *CE) {
     assert(Src && "LValue being cast to RValue has no origin list");
     // The result of an LValue-to-RValue cast on a pointer lvalue (like `q` in
     // `int *p, *q; p = q;`) should propagate the inner origin (what the 
pointer
-    // points to), not the outer origin (the pointer's storage location). Strip
-    // the outer lvalue origin.
-    flow(getOriginsList(*CE), getRValueOrigins(SubExpr, Src),
-         /*Kill=*/true);
+    // points to), not the outer origin (the pointer's storage location).
+    flow(Dest, Loaded, /*Kill=*/true);
     return;
   case CK_NullToPointer:
     getOriginsList(*CE);
@@ -351,7 +355,7 @@ void FactsGenerator::VisitCastExpr(const CastExpr *CE) {
     // lvalue level first. A bit-cast that materializes a pointer from a
     // non-pointer representation has no matching source origin and is
     // untracked.
-    OriginList *RVSrc = getRValueOrigins(SubExpr, Src);
+    OriginList *RVSrc = Loads ? Loaded : Src;
     if (RVSrc && Dest->getLength() == RVSrc->getLength())
       flow(Dest, RVSrc, /*Kill=*/true);
     return;
@@ -393,18 +397,17 @@ void FactsGenerator::VisitUnaryOperator(const 
UnaryOperator *UO) {
     if (!UO->getType()->isPointerType())
       return;
     const Expr *SubExpr = UO->getSubExpr();
-    flow(getOriginsList(*UO),
-         getRValueOrigins(SubExpr, getOriginsList(*SubExpr)), /*Kill=*/true);
+    flow(getOriginsList(*UO), readValue(SubExpr), /*Kill=*/true);
     return;
   }
   case UO_PreInc:
   case UO_PostInc:
   case UO_PreDec:
   case UO_PostDec: {
+    handleAccess(UO->getSubExpr());
     // Inc/dec keeps a pointer in the same allocation, so the result carries 
the
     // operand's loans. Peel the operand's storage origin when the *result* is 
a
-    // prvalue (post-inc/dec, or any form in C) -- the inverse of
-    // getRValueOrigins, which peels when its own argument is a glvalue.
+    // prvalue (post-inc/dec, or any form in C).
     if (!UO->getType()->isPointerType())
       return;
     OriginList *SubList = getOriginsList(*UO->getSubExpr());
@@ -430,6 +433,8 @@ void FactsGenerator::handleAssignment(const Expr 
*TargetExpr,
                                       const Expr *LHSExpr,
                                       const Expr *RHSExpr) {
   LHSExpr = LHSExpr->IgnoreParenImpCasts();
+  handleAccess(LHSExpr);
+  OriginList *RHSList = readValue(RHSExpr);
   OriginList *LHSList = nullptr;
 
   if (const auto *DRE_LHS = dyn_cast<DeclRefExpr>(LHSExpr)) {
@@ -445,37 +450,7 @@ void FactsGenerator::handleAssignment(const Expr 
*TargetExpr,
   }
   if (!LHSList)
     return;
-  OriginList *RHSList = getOriginsList(*RHSExpr);
-  // For operator= with reference parameters (e.g.,
-  // `View& operator=(const View&)`), the RHS argument stays an lvalue,
-  // unlike built-in assignment where LValueToRValue cast strips the outer
-  // lvalue origin. Strip it manually to get the actual value origins being
-  // assigned.
-  RHSList = getRValueOrigins(RHSExpr, RHSList);
 
-  if (const auto *DRE_LHS = dyn_cast<DeclRefExpr>(LHSExpr)) {
-    QualType QT = DRE_LHS->getDecl()->getType();
-    if (QT->isReferenceType()) {
-      if (hasOrigins(QT->getPointeeType())) {
-        // Writing through a reference uses the binding but overwrites the
-        // pointee. Model this as a Read of the outer origin (keeping the
-        // binding live) and a Write of the inner origins (killing the 
pointee's
-        // liveness).
-        if (UseFact *UF = UseFacts.lookup(DRE_LHS)) {
-          const OriginList *FullList = UF->getUsedOrigins();
-          assert(FullList);
-          UF->setUsedOrigins(FactMgr.getOriginMgr().createSingleOriginList(
-              FullList->getOuterOriginID()));
-          if (const OriginList *InnerList = FullList->peelOuterOrigin()) {
-            UseFact *WriteUF = FactMgr.createFact<UseFact>(DRE_LHS, InnerList);
-            WriteUF->markAsWritten();
-            CurrentBlockFacts.push_back(WriteUF);
-          }
-        }
-      }
-    } else
-      markUseAsWrite(DRE_LHS);
-  }
   if (!RHSList) {
     // RHS has no tracked origins (e.g., assigning a callable without origins
     // to std::function). Clear loans of the destination.
@@ -492,7 +467,7 @@ void FactsGenerator::handleAssignment(const Expr 
*TargetExpr,
   // In C, assignment expressions are not GLValues, so the assignment result 
has
   // the assigned value origins, not the LHS storage origin.
   if (IsCMode)
-    LHSList = getRValueOrigins(LHSExpr, LHSList);
+    LHSList = LHSList->peelOuterOrigin();
   flow(getOriginsList(*TargetExpr), LHSList, /*Kill=*/true);
 }
 
@@ -519,14 +494,12 @@ void FactsGenerator::VisitBinaryOperator(const 
BinaryOperator *BO) {
     // counterpart in the object's origin -- so the lists may differ in length
     // and we flow just the top level, leaving the member's value untouched.
     OriginList *Dst = getOriginsList(*BO);
-    OriginList *ObjSrc =
-        BO->getOpcode() == BO_PtrMemD
-            ? getOriginsList(*BO->getLHS())
-            : getRValueOrigins(BO->getLHS(), getOriginsList(*BO->getLHS()));
+    OriginList *ObjSrc = BO->getOpcode() == BO_PtrMemD
+                             ? getOriginsList(*BO->getLHS())
+                             : readValue(BO->getLHS());
     if (Dst && ObjSrc)
       CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
           Dst->getOuterOriginID(), ObjSrc->getOuterOriginID(), /*Kill=*/true));
-    handleUse(BO->getLHS());
     return;
   }
   if (BO->getOpcode() == BO_Comma) {
@@ -534,6 +507,7 @@ void FactsGenerator::VisitBinaryOperator(const 
BinaryOperator *BO) {
     return;
   }
   if (BO->isCompoundAssignmentOp()) {
+    handleAccess(BO->getLHS());
     // A pointer compound additive assignment (`p += n`) carries the LHS's 
loans
     // like inc/dec above; in C the result is a prvalue, so peel its outer
     // (storage) origin.
@@ -546,10 +520,9 @@ void FactsGenerator::VisitBinaryOperator(const 
BinaryOperator *BO) {
   }
   if (BO->getType()->isPointerType() && BO->isAdditiveOp())
     handlePointerArithmetic(BO);
-  handleUse(BO->getRHS());
   if (BO->isAssignmentOp())
     handleAssignment(BO, BO->getLHS(), BO->getRHS());
-  // TODO: Handle assignments involving dereference like `*p = q`.
+  // TODO: Propagate origins for assignments through a dereference (`*p = q`).
 }
 
 static const CFGBlock *findPredBlockForExpr(const CFGBlock *MergeBlock,
@@ -666,7 +639,7 @@ void FactsGenerator::VisitMaterializeTemporaryExpr(
           MTEList->getLength() == (SubExprList->getLength() + 1)) &&
          "MTE top level origin should contain a loan to the MTE itself");
 
-  OriginList *RValMTEList = getRValueOrigins(MTE, MTEList);
+  OriginList *RValMTEList = MTEList->peelOuterOrigin();
   flow(RValMTEList, SubExprList, /*Kill=*/true);
   OriginID OuterMTEID = MTEList->getOuterOriginID();
   if (MTE->getStorageDuration() == SD_FullExpression) {
@@ -702,6 +675,8 @@ void FactsGenerator::VisitLambdaExpr(const LambdaExpr *LE) {
   for (const Expr *Init : LE->capture_inits()) {
     if (!Init)
       continue;
+    // The lambda body may dereference a capture to any depth.
+    handleUse(Init);
     OriginList *InitList = getOriginsList(*Init);
     if (!InitList)
       continue;
@@ -758,6 +733,8 @@ bool FactsGenerator::handlePlacementNew(const CXXNewExpr 
*NE,
   // FIXME: General placement arguments need separate handling to overwrite
   // the right origins.
 
+  handleAccess(PlacementArg);
+
   // The pointer returned by placement new comes from the placement
   // argument.
   if (PlacementList)
@@ -796,7 +773,30 @@ void FactsGenerator::VisitCXXNewExpr(const CXXNewExpr *NE) 
{
     flow(NewList, InitList, true);
 }
 
+// TODO: An escape fact may fit `throw` and asm better than a use.
+void FactsGenerator::VisitCXXThrowExpr(const CXXThrowExpr *TE) {
+  if (const Expr *Sub = TE->getSubExpr())
+    handleUse(Sub);
+}
+
+void FactsGenerator::VisitGCCAsmStmt(const GCCAsmStmt *AS) {
+  for (const Expr *Input : AS->inputs())
+    handleUse(Input);
+  for (unsigned I = 0, N = AS->getNumOutputs(); I != N; ++I)
+    if (AS->isOutputPlusConstraint(I)) // Also read.
+      handleUse(AS->getOutputExpr(I));
+    else
+      handleAccess(AS->getOutputExpr(I));
+}
+
+void FactsGenerator::VisitCXXTypeidExpr(const CXXTypeidExpr *TE) {
+  if (TE->isPotentiallyEvaluated())
+    handleAccess(TE->getExprOperand());
+}
+
 void FactsGenerator::VisitCXXDeleteExpr(const CXXDeleteExpr *DE) {
+  // The destructor may dereference to any depth.
+  handleUse(DE->getArgument());
   OriginList *List = getOriginsList(*DE->getArgument());
   CurrentBlockFacts.push_back(
       FactMgr.createFact<InvalidateOriginFact>(List->getOuterOriginID(), DE));
@@ -813,7 +813,7 @@ void FactsGenerator::VisitStmtExpr(const StmtExpr *SE) {
   if (!Last)
     return;
   if (OriginList *Dst = getOriginsList(*SE))
-    if (OriginList *Src = getRValueOrigins(Last, getOriginsList(*Last)))
+    if (OriginList *Src = readValue(Last))
       flow(Dst, Src, /*Kill=*/true);
 }
 
@@ -877,13 +877,12 @@ void FactsGenerator::handleGSLPointerConstruction(const 
CXXConstructExpr *CCE) {
 
   const Expr *Arg = CCE->getArg(0);
   if (isGslPointerType(Arg->getType())) {
-    OriginList *ArgList = getOriginsList(*Arg);
-    assert(ArgList && "GSL pointer argument should have an origin list");
     // GSL pointer is constructed from another gsl pointer.
     // Example:
     //  View(View v);
     //  View(const View &v);
-    ArgList = getRValueOrigins(Arg, ArgList);
+    OriginList *ArgList = readValue(Arg);
+    assert(ArgList && "GSL pointer argument should have an...
[truncated]

``````````

</details>


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

Reply via email to