[clang] [LifetimeSafety][NFC] Refactor OriginList to OriginNode tree (PR #194797)

via cfe-commits cfe-commits at lists.llvm.org
Wed Apr 29 00:18:29 PDT 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang-analysis

Author: Zhijie Wang (aeft)

<details>
<summary>Changes</summary>

1. Most of code is rename `OriginList` to `OriginNode`
2. Enable `OriginNode` to support more than one child
3. Field children support leave to the follow-up PR

NFC PR for #<!-- -->184344

---

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


9 Files Affected:

- (modified) clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h (+5-6) 
- (modified) clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h (+5-5) 
- (modified) clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h (+44-30) 
- (modified) clang/lib/Analysis/LifetimeSafety/Facts.cpp (+3-3) 
- (modified) clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp (+122-123) 
- (modified) clang/lib/Analysis/LifetimeSafety/LiveOrigins.cpp (+3-3) 
- (modified) clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp (+3-3) 
- (modified) clang/lib/Analysis/LifetimeSafety/Origins.cpp (+39-30) 
- (modified) clang/unittests/Analysis/LifetimeSafetyTest.cpp (+3-3) 


``````````diff
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h
index 88b509e1b94df..15d8abfb5439d 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h
@@ -20,7 +20,6 @@
 #include "clang/Analysis/Analyses/LifetimeSafety/Utils.h"
 #include "clang/Analysis/AnalysisDeclContext.h"
 #include "clang/Analysis/CFG.h"
-#include "llvm/ADT/STLFunctionalExtras.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/Support/Debug.h"
 #include <cstdint>
@@ -236,7 +235,7 @@ class GlobalEscapeFact : public OriginEscapesFact {
 
 class UseFact : public Fact {
   const Expr *UseExpr;
-  const OriginList *OList;
+  const OriginNode *ONode;
   // 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;
@@ -244,11 +243,11 @@ class UseFact : public Fact {
 public:
   static bool classof(const Fact *F) { return F->getKind() == Kind::Use; }
 
-  UseFact(const Expr *UseExpr, const OriginList *OList)
-      : Fact(Kind::Use), UseExpr(UseExpr), OList(OList) {}
+  UseFact(const Expr *UseExpr, const OriginNode *ONode)
+      : Fact(Kind::Use), UseExpr(UseExpr), ONode(ONode) {}
 
-  const OriginList *getUsedOrigins() const { return OList; }
-  void setUsedOrigins(const OriginList *NewList) { OList = NewList; }
+  const OriginNode *getUsedOrigins() const { return ONode; }
+  void setUsedOrigins(const OriginNode *NewONode) { ONode = NewONode; }
   const Expr *getUseExpr() const { return UseExpr; }
   void markAsWritten() { IsWritten = true; }
   bool isWritten() const { return IsWritten; }
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h
index 45b16cf1ec31d..b5185ba815b00 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h
@@ -57,13 +57,13 @@ class FactsGenerator : public ConstStmtVisitor<FactsGenerator> {
   void VisitCXXDeleteExpr(const CXXDeleteExpr *DE);
 
 private:
-  OriginList *getOriginsList(const ValueDecl &D);
-  OriginList *getOriginsList(const Expr &E);
+  OriginNode *getOriginNode(const ValueDecl &D);
+  OriginNode *getOriginNode(const Expr &E);
 
   bool hasOrigins(QualType QT) const;
   bool hasOrigins(const Expr *E) const;
 
-  void flow(OriginList *Dst, OriginList *Src, bool Kill);
+  void flow(OriginNode *Dst, OriginNode *Src, bool Kill);
 
   void handleAssignment(const Expr *LHSExpr, const Expr *RHSExpr);
 
@@ -106,12 +106,12 @@ class FactsGenerator : public ConstStmtVisitor<FactsGenerator> {
 
   template <typename Destination, typename Source>
   void flowOrigin(const Destination &D, const Source &S) {
-    flow(getOriginsList(D), getOriginsList(S), /*Kill=*/false);
+    flow(getOriginNode(D), getOriginNode(S), /*Kill=*/false);
   }
 
   template <typename Destination, typename Source>
   void killAndFlowOrigin(const Destination &D, const Source &S) {
-    flow(getOriginsList(D), getOriginsList(S), /*Kill=*/true);
+    flow(getOriginNode(D), getOriginNode(S), /*Kill=*/true);
   }
 
   /// Checks if the expression is a `void("__lifetime_test_point_...")` cast.
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h
index c2db59c579060..f2d94e99d6ac2 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h
@@ -36,7 +36,7 @@ inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, OriginID ID) {
 ///
 /// Each Origin corresponds to a single level of indirection. For complex types
 /// with multiple levels of indirection (e.g., `int**`), multiple Origins are
-/// organized into an OriginList structure (see below).
+/// organized into a tree structure (see below).
 struct Origin {
   OriginID ID;
   /// A pointer to the AST node that this origin represents. This union
@@ -92,30 +92,42 @@ struct Origin {
 ///
 /// The list structure enables the analysis to track how loans flow through
 /// different levels of indirection when assignments and dereferences occur.
-class OriginList {
+///
+/// TODO: Currently list-shaped (each node has at most one pointee child).
+/// Will become tree-shaped once field children are added to support
+/// origin trees for records whose fields have origins.
+class OriginNode {
 public:
-  OriginList(OriginID OID) : OuterOID(OID) {}
+  OriginNode(OriginID OID) : OID(OID) {}
 
-  OriginList *peelOuterOrigin() const { return InnerList; }
-  OriginID getOuterOriginID() const { return OuterOID; }
+  OriginNode *getPointeeChild() const {
+    return NumChildren ? Children[0] : nullptr;
+  }
 
-  void setInnerOriginList(OriginList *Inner) { InnerList = Inner; }
+  OriginID getOriginID() const { return OID; }
 
-  // Used for assertion checks only (to ensure origin lists have matching
+  void setChildren(OriginNode **Arr, unsigned N) {
+    assert(Children == nullptr && "children must be set at most once");
+    Children = Arr;
+    NumChildren = N;
+  }
+
+  // Used for assertion checks only (to ensure pointee chains have matching
   // lengths).
   size_t getLength() const {
     size_t Length = 1;
-    const OriginList *T = this;
-    while (T->InnerList) {
-      T = T->InnerList;
+    const OriginNode *T = this;
+    while (auto *ON = T->getPointeeChild()) {
+      T = ON;
       Length++;
     }
     return Length;
   }
 
 private:
-  OriginID OuterOID;
-  OriginList *InnerList = nullptr;
+  OriginID OID;
+  OriginNode **Children = nullptr;
+  unsigned NumChildren = 0;
 };
 
 bool doesDeclHaveStorage(const ValueDecl *D);
@@ -126,31 +138,31 @@ class OriginManager {
 public:
   explicit OriginManager(const AnalysisDeclContext &AC);
 
-  /// Gets or creates the OriginList for a given ValueDecl.
+  /// Gets or creates the OriginNode for a given ValueDecl.
   ///
   /// Creates a list structure mirroring the levels of indirection in the
   /// declaration's type (e.g., `int** p` creates list of size 2).
   ///
-  /// \returns The OriginList, or nullptr if the type is not pointer-like.
-  OriginList *getOrCreateList(const ValueDecl *D);
+  /// \returns The OriginNode, or nullptr if the type is not pointer-like.
+  OriginNode *getOrCreateNode(const ValueDecl *D);
 
-  /// Gets or creates the OriginList for a given Expr.
+  /// Gets or creates the OriginNode for a given Expr.
   ///
   /// Creates a list based on the expression's type and value category:
   /// - Lvalues get an implicit reference level (modeling addressability)
   /// - Rvalues of non-pointer type return nullptr (no trackable origin)
   /// - DeclRefExpr may reuse the underlying declaration's list
   ///
-  /// \returns The OriginList, or nullptr for non-pointer rvalues.
-  OriginList *getOrCreateList(const Expr *E);
+  /// \returns The OriginNode, or nullptr for non-pointer rvalues.
+  OriginNode *getOrCreateNode(const Expr *E);
 
-  /// Wraps an existing OriginID in a new single-element OriginList, so a fact
-  /// can refer to a single level of an existing OriginList.
-  OriginList *createSingleOriginList(OriginID OID);
+  /// Wraps an existing OriginID in a new single-element OriginNode, so a fact
+  /// can refer to a single level of an existing OriginNode.
+  OriginNode *createSingleOriginNode(OriginID OID);
 
-  /// Returns the OriginList for the implicit 'this' parameter if the current
+  /// Returns the OriginNode for the implicit 'this' parameter if the current
   /// declaration is an instance method.
-  std::optional<OriginList *> getThisOrigins() const { return ThisOrigins; }
+  std::optional<OriginNode *> getThisOrigins() const { return ThisOrigins; }
 
   const Origin &getOrigin(OriginID ID) const;
 
@@ -169,11 +181,13 @@ class OriginManager {
 private:
   OriginID getNextOriginID() { return NextOriginID++; }
 
-  OriginList *createNode(const ValueDecl *D, QualType QT);
-  OriginList *createNode(const Expr *E, QualType QT);
+  OriginNode *createNode(const ValueDecl *D, QualType QT);
+  OriginNode *createNode(const Expr *E, QualType QT);
+
+  void attachPointeeChild(OriginNode *Parent, OriginNode *Pointee);
 
   template <typename T>
-  OriginList *buildListForType(QualType QT, const T *Node);
+  OriginNode *buildNodeForType(QualType QT, const T *Node);
 
   void initializeThisOrigins(const Decl *D);
 
@@ -188,10 +202,10 @@ class OriginManager {
   /// TODO(opt): Profile and evaluate the usefulness of small buffer
   /// optimisation.
   llvm::SmallVector<Origin> AllOrigins;
-  llvm::BumpPtrAllocator ListAllocator;
-  llvm::DenseMap<const clang::ValueDecl *, OriginList *> DeclToList;
-  llvm::DenseMap<const clang::Expr *, OriginList *> ExprToList;
-  std::optional<OriginList *> ThisOrigins;
+  llvm::BumpPtrAllocator Allocator;
+  llvm::DenseMap<const clang::ValueDecl *, OriginNode *> DeclToNode;
+  llvm::DenseMap<const clang::Expr *, OriginNode *> ExprToNode;
+  std::optional<OriginNode *> ThisOrigins;
   /// Types that are not inherently pointer-like but require origin tracking
   /// because of lifetime annotations (currently [[clang::lifetimebound]]) on
   /// functions that return them.
diff --git a/clang/lib/Analysis/LifetimeSafety/Facts.cpp b/clang/lib/Analysis/LifetimeSafety/Facts.cpp
index 3d7fbcdacc830..d04d3e9202952 100644
--- a/clang/lib/Analysis/LifetimeSafety/Facts.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Facts.cpp
@@ -82,9 +82,9 @@ void UseFact::dump(llvm::raw_ostream &OS, const LoanManager &,
   OS << "Use (";
   size_t NumUsedOrigins = getUsedOrigins()->getLength();
   size_t I = 0;
-  for (const OriginList *Cur = getUsedOrigins(); Cur;
-       Cur = Cur->peelOuterOrigin(), ++I) {
-    OM.dump(Cur->getOuterOriginID(), OS);
+  for (const OriginNode *Cur = getUsedOrigins(); Cur;
+       Cur = Cur->getPointeeChild(), ++I) {
+    OM.dump(Cur->getOriginID(), OS);
     if (I < NumUsedOrigins - 1)
       OS << ", ";
   }
diff --git a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
index efdb1a1691ae3..24bf706b62ee3 100644
--- a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
@@ -30,11 +30,12 @@
 namespace clang::lifetimes::internal {
 using llvm::isa_and_present;
 
-OriginList *FactsGenerator::getOriginsList(const ValueDecl &D) {
-  return FactMgr.getOriginMgr().getOrCreateList(&D);
+OriginNode *FactsGenerator::getOriginNode(const ValueDecl &D) {
+  return FactMgr.getOriginMgr().getOrCreateNode(&D);
 }
-OriginList *FactsGenerator::getOriginsList(const Expr &E) {
-  return FactMgr.getOriginMgr().getOrCreateList(&E);
+
+OriginNode *FactsGenerator::getOriginNode(const Expr &E) {
+  return FactMgr.getOriginMgr().getOrCreateNode(&E);
 }
 
 bool FactsGenerator::hasOrigins(QualType QT) const {
@@ -58,7 +59,7 @@ bool FactsGenerator::hasOrigins(const Expr *E) const {
 ///     * Level 1: pp <- p's address
 ///     * Level 2: (*pp) <- what p points to (i.e., &x)
 ///   - `View v = obj;` flows origins from `obj` (depth 1) to `v` (depth 1)
-void FactsGenerator::flow(OriginList *Dst, OriginList *Src, bool Kill) {
+void FactsGenerator::flow(OriginNode *Dst, OriginNode *Src, bool Kill) {
   if (!Dst)
     return;
   assert(Src &&
@@ -68,9 +69,9 @@ void FactsGenerator::flow(OriginList *Dst, OriginList *Src, bool Kill) {
 
   while (Dst && Src) {
     CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
-        Dst->getOuterOriginID(), Src->getOuterOriginID(), Kill));
-    Dst = Dst->peelOuterOrigin();
-    Src = Src->peelOuterOrigin();
+        Dst->getOriginID(), Src->getOriginID(), Kill));
+    Dst = Dst->getPointeeChild();
+    Src = Src->getPointeeChild();
   }
 }
 
@@ -146,22 +147,22 @@ void FactsGenerator::run() {
 ///
 /// 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)
+static OriginNode *getRValueOrigins(const Expr *E, OriginNode *Node) {
+  if (!Node)
     return nullptr;
-  return E->isGLValue() ? List->peelOuterOrigin() : List;
+  return E->isGLValue() ? Node->getPointeeChild() : Node;
 }
 
 void FactsGenerator::VisitDeclStmt(const DeclStmt *DS) {
   for (const Decl *D : DS->decls())
     if (const auto *VD = dyn_cast<VarDecl>(D))
       if (const Expr *InitExpr = VD->getInit()) {
-        OriginList *VDList = getOriginsList(*VD);
-        if (!VDList)
+        OriginNode *VDNode = getOriginNode(*VD);
+        if (!VDNode)
           continue;
-        OriginList *InitList = getOriginsList(*InitExpr);
-        assert(InitList && "VarDecl had origins but InitExpr did not");
-        flow(VDList, InitList, /*Kill=*/true);
+        OriginNode *InitNode = getOriginNode(*InitExpr);
+        assert(InitNode && "VarDecl had origins but InitExpr did not");
+        flow(VDNode, InitNode, /*Kill=*/true);
       }
 }
 
@@ -182,13 +183,13 @@ void FactsGenerator::VisitDeclRefExpr(const DeclRefExpr *DRE) {
   if (doesDeclHaveStorage(DRE->getDecl())) {
     const Loan *L = createLoan(FactMgr, DRE);
     assert(L);
-    OriginList *List = getOriginsList(*DRE);
-    assert(List &&
+    OriginNode *Node = getOriginNode(*DRE);
+    assert(Node &&
            "gl-value DRE of non-pointer type should have an origin list");
     // This loan specifically tracks borrowing the variable's storage location
-    // itself and is issued to outermost origin (List->OID).
+    // itself and is issued to outermost origin (Node->OID).
     CurrentBlockFacts.push_back(
-        FactMgr.createFact<IssueFact>(L->getID(), List->getOuterOriginID()));
+        FactMgr.createFact<IssueFact>(L->getID(), Node->getOriginID()));
   }
 }
 
@@ -204,8 +205,8 @@ 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))) {
-      flow(getOriginsList(*CCE), ArgList, /*Kill=*/true);
+    if (OriginNode *ArgNode = getRValueOrigins(Arg, getOriginNode(*Arg))) {
+      flow(getOriginNode(*CCE), ArgNode, /*Kill=*/true);
       return;
     }
   }
@@ -214,8 +215,8 @@ 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))) {
-      flow(getOriginsList(*CCE), ArgList, /*Kill=*/true);
+    if (OriginNode *ArgNode = getRValueOrigins(Arg, getOriginNode(*Arg))) {
+      flow(getOriginNode(*CCE), ArgNode, /*Kill=*/true);
       return;
     }
   }
@@ -263,14 +264,14 @@ void FactsGenerator::VisitMemberExpr(const MemberExpr *ME) {
   auto *MD = ME->getMemberDecl();
   if (isa<FieldDecl>(MD) && doesDeclHaveStorage(MD)) {
     assert(ME->isGLValue() && "Field member should be GL value");
-    OriginList *Dst = getOriginsList(*ME);
+    OriginNode *Dst = getOriginNode(*ME);
     assert(Dst && "Field member should have an origin list as it is GL value");
-    OriginList *Src = getOriginsList(*ME->getBase());
+    OriginNode *Src = getOriginNode(*ME->getBase());
     assert(Src && "Base expression should be a pointer/reference type");
     // The field's glvalue (outermost origin) holds the same loans as the base
     // expression.
     CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
-        Dst->getOuterOriginID(), Src->getOuterOriginID(),
+        Dst->getOriginID(), Src->getOriginID(),
         /*Kill=*/true));
   }
 }
@@ -284,15 +285,15 @@ void FactsGenerator::VisitCXXNullPtrLiteralExpr(
     const CXXNullPtrLiteralExpr *N) {
   /// TODO: Handle nullptr expr as a special 'null' loan. Uninitialized
   /// pointers can use the same type of loan.
-  getOriginsList(*N);
+  getOriginNode(*N);
 }
 
 void FactsGenerator::VisitCastExpr(const CastExpr *CE) {
-  OriginList *Dest = getOriginsList(*CE);
+  OriginNode *Dest = getOriginNode(*CE);
   if (!Dest)
     return;
   const Expr *SubExpr = CE->getSubExpr();
-  OriginList *Src = getOriginsList(*SubExpr);
+  OriginNode *Src = getOriginNode(*SubExpr);
 
   switch (CE->getCastKind()) {
   case CK_LValueToRValue:
@@ -304,11 +305,11 @@ void FactsGenerator::VisitCastExpr(const CastExpr *CE) {
     // `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),
+    flow(getOriginNode(*CE), getRValueOrigins(SubExpr, Src),
          /*Kill=*/true);
     return;
   case CK_NullToPointer:
-    getOriginsList(*CE);
+    getOriginNode(*CE);
     // TODO: Flow into them a null origin.
     return;
   case CK_NoOp:
@@ -326,7 +327,7 @@ void FactsGenerator::VisitCastExpr(const CastExpr *CE) {
   case CK_ArrayToPointerDecay:
     assert(Src && "Array expression should have origins as it is GL value");
     CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
-        Dest->getOuterOriginID(), Src->getOuterOriginID(), /*Kill=*/true));
+        Dest->getOriginID(), Src->getOriginID(), /*Kill=*/true));
     return;
   case CK_FunctionToPointerDecay:
   case CK_BuiltinFnToFnPtr:
@@ -360,38 +361,38 @@ void FactsGenerator::VisitUnaryOperator(const UnaryOperator *UO) {
 
 void FactsGenerator::VisitReturnStmt(const ReturnStmt *RS) {
   if (const Expr *RetExpr = RS->getRetValue()) {
-    if (OriginList *List = getOriginsList(*RetExpr))
-      for (OriginList *L = List; L != nullptr; L = L->peelOuterOrigin())
-        EscapesInCurrentBlock.push_back(FactMgr.createFact<ReturnEscapeFact>(
-            L->getOuterOriginID(), RetExpr));
+    if (OriginNode *Node = getOriginNode(*RetExpr))
+      for (OriginNode *L = Node; L != nullptr; L = L->getPointeeChild())
+        EscapesInCurrentBlock.push_back(
+            FactMgr.createFact<ReturnEscapeFact>(L->getOriginID(), RetExpr));
   }
 }
 
 void FactsGenerator::handleAssignment(const Expr *LHSExpr,
                                       const Expr *RHSExpr) {
   LHSExpr = LHSExpr->IgnoreParenImpCasts();
-  OriginList *LHSList = nullptr;
+  OriginNode *LHSNode = nullptr;
 
   if (const auto *DRE_LHS = dyn_cast<DeclRefExpr>(LHSExpr)) {
-    LHSList = getOriginsList(*DRE_LHS);
-    assert(LHSList && "LHS is a DRE and should have an origin list");
+    LHSNode = getOriginNode(*DRE_LHS);
+    assert(LHSNode && "LHS is a DRE and should have an origin list");
   }
   // Handle assignment to member fields (e.g., `this->view = s` or `view = s`).
   // This enables detection of dangling fields when local values escape to
   // fields.
   if (const auto *ME_LHS = dyn_cast<MemberExpr>(LHSExpr)) {
-    LHSList = getOriginsList(*ME_LHS);
-    assert(LHSList && "LHS is a MemberExpr and should have an origin list");
+    LHSNode = getOriginNode(*ME_LHS);
+    assert(LHSNode && "LHS is a MemberExpr and should have an origin list");
   }
-  if (!LHSList)
+  if (!LHSNode)
     return;
-  OriginList *RHSList = getOriginsList(*RHSExpr);
+  OriginNode *RHSNode = getOriginNode(*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);
+  RHSNode = getRValueOrigins(RHSExpr, RHSNode);
 
   if (const auto *DRE_LHS = dyn_cast<DeclRefExpr>(LHSExpr)) {
     QualType QT = DRE_LHS->getDecl()->getType();
@@ -402,12 +403,12 @@ void FactsGenerator::handleAssignment(const Expr *LHSExpr,
         // 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(
-              FullLi...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/194797


More information about the cfe-commits mailing list