[clang] [clang][bytecode] Use opaque pointers for expr-based dummy pointers (PR #221218)

Timm Baeder via cfe-commits cfe-commits at lists.llvm.org
Fri Sep 11 07:41:25 PDT 2026


https://github.com/tbaederr updated https://github.com/llvm/llvm-project/pull/221218

>From 8acc64ac58ca1c2b110e634b8a68c9250c7ebcc8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Fri, 4 Sep 2026 08:07:34 +0200
Subject: [PATCH] opaque Expr

---
 clang/lib/AST/ByteCode/Compiler.cpp           | 19 +----
 clang/lib/AST/ByteCode/DeclOrExpr.h           |  7 ++
 clang/lib/AST/ByteCode/Disasm.cpp             |  6 +-
 clang/lib/AST/ByteCode/EvaluationResult.cpp   |  4 +-
 clang/lib/AST/ByteCode/Interp.cpp             | 78 +++----------------
 clang/lib/AST/ByteCode/Interp.h               | 33 ++++----
 clang/lib/AST/ByteCode/InterpBlock.cpp        | 11 +--
 clang/lib/AST/ByteCode/InterpBlock.h          | 14 +---
 .../AST/ByteCode/InterpBuiltinObjectSize.cpp  |  4 +-
 clang/lib/AST/ByteCode/InterpHelpers.h        |  1 -
 clang/lib/AST/ByteCode/Opcodes.td             |  3 +-
 clang/lib/AST/ByteCode/Pointer.cpp            | 60 ++++++++------
 clang/lib/AST/ByteCode/Pointer.h              | 34 ++++----
 clang/lib/AST/ByteCode/Program.cpp            | 63 ---------------
 clang/lib/AST/ByteCode/Program.h              |  6 --
 15 files changed, 96 insertions(+), 247 deletions(-)

diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index 473494c694a98..64570635b7b3b 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -8734,24 +8734,7 @@ bool Compiler<Emitter>::emitDestructionPop(const Descriptor *Desc,
 template <class Emitter>
 bool Compiler<Emitter>::emitDummyPtr(DeclOrExpr D, const Expr *E, bool CU) {
   assert(!DiscardResult && "Should've been checked before");
-
-  if (const auto *VD = D.asValueDecl())
-    return this->emitGetOpaquePtr(VD, CU, E);
-
-  assert(D.asExpr());
-  unsigned DummyID = P.getOrCreateDummy(D, CU);
-  if (!this->emitGetPtrGlobal(DummyID, E))
-    return false;
-  if (E->getType()->isVoidType())
-    return true;
-
-  // Convert the dummy pointer to another pointer type if we have to.
-  if (PrimType PT = classifyPrim(E); PT != PT_Ptr) {
-    if (isPtrType(PT))
-      return this->emitDecayPtr(PT_Ptr, PT, E);
-    return false;
-  }
-  return true;
+  return this->emitGetOpaquePtr(D, CU, E);
 }
 
 template <class Emitter>
diff --git a/clang/lib/AST/ByteCode/DeclOrExpr.h b/clang/lib/AST/ByteCode/DeclOrExpr.h
index e170b52c6e51d..b844c5644a233 100644
--- a/clang/lib/AST/ByteCode/DeclOrExpr.h
+++ b/clang/lib/AST/ByteCode/DeclOrExpr.h
@@ -28,6 +28,7 @@ struct DeclOrExpr {
   bool isExpr() const { return isa_and_nonnull<const Expr *>(V); }
   bool isDecl() const { return isa_and_nonnull<const Decl *>(V); }
   bool isValueDecl() const { return isa_and_nonnull<ValueDecl>(asDecl()); }
+  bool isVarDecl() const { return isa_and_nonnull<VarDecl>(asDecl()); }
 
   const Expr *asExpr() const { return V.dyn_cast<const Expr *>(); }
   const Decl *asDecl() const { return V.dyn_cast<const Decl *>(); }
@@ -49,6 +50,12 @@ struct DeclOrExpr {
       return VD->getType();
     return asExpr()->getType();
   }
+
+  SourceLocation getLocation() const {
+    if (const auto *VD = asValueDecl())
+      return VD->getLocation();
+    return asExpr()->getExprLoc();
+  }
 };
 static_assert(sizeof(DeclOrExpr) == sizeof(void *));
 
diff --git a/clang/lib/AST/ByteCode/Disasm.cpp b/clang/lib/AST/ByteCode/Disasm.cpp
index 03187529541d8..c319591b1fee9 100644
--- a/clang/lib/AST/ByteCode/Disasm.cpp
+++ b/clang/lib/AST/ByteCode/Disasm.cpp
@@ -345,7 +345,6 @@ LLVM_DUMP_METHOD void Program::dump(llvm::raw_ostream &OS) const {
     // All the maps.
     Bytes += GlobalIndices.getMemorySize();
     Bytes += Records.getMemorySize();
-    Bytes += DummyVariables.getMemorySize();
 
     // All Records.
     for (const Record *R : Records.values()) {
@@ -372,8 +371,6 @@ LLVM_DUMP_METHOD void Program::dump(llvm::raw_ostream &OS) const {
                         : TerminalColor{llvm::raw_ostream::RED, false});
       OS << (GP.isInitialized() ? "initialized " : "uninitialized ");
     }
-    if (GP.block()->isDummy())
-      OS << "dummy ";
     Desc->dump(OS);
 
     if (GP.isInitialized() && Desc->IsTemporary) {
@@ -402,7 +399,7 @@ LLVM_DUMP_METHOD void Program::dump(llvm::raw_ostream &OS) const {
     }
 
     OS << "\n";
-    if (GP.isInitialized() && Desc->isPrimitive() && !G->block()->isDummy()) {
+    if (GP.isInitialized() && Desc->isPrimitive()) {
       OS << "   ";
       {
         ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_CYAN, false});
@@ -634,7 +631,6 @@ LLVM_DUMP_METHOD void Block::dump(llvm::raw_ostream &OS) const {
   OS << "  Extern: " << isExtern() << "\n";
   OS << "  Initialized: " << IsInitialized << "\n";
   OS << "  Weak: " << isWeak() << "\n";
-  OS << "  Dummy: " << isDummy() << '\n';
   OS << "  Dynamic: " << isDynamic() << "\n";
   OS << "  Metadata: " << MDSize << '\n';
 }
diff --git a/clang/lib/AST/ByteCode/EvaluationResult.cpp b/clang/lib/AST/ByteCode/EvaluationResult.cpp
index bc939c9a5c8fc..5d232c5414e04 100644
--- a/clang/lib/AST/ByteCode/EvaluationResult.cpp
+++ b/clang/lib/AST/ByteCode/EvaluationResult.cpp
@@ -179,8 +179,8 @@ static void collectBlocks(PtrView Ptr,
            P.isDereferencable() && !P.isUnknownSizeArray() && !P.isOnePastEnd();
   };
 
-  if (!Ptr.isLive() || Ptr.isZero() || Ptr.isDummy() ||
-      Ptr.isUnknownSizeArray() || Ptr.isOnePastEnd())
+  if (!Ptr.isLive() || Ptr.isZero() || Ptr.isUnknownSizeArray() ||
+      Ptr.isOnePastEnd())
     return;
 
   Blocks.insert(Ptr.Pointee);
diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp
index 160cc745c89b6..2b7694e1f7111 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -111,7 +111,7 @@ static void noteValueLocation(InterpState &S, const Pointer &Ptr) {
   }
 
   if (Ptr.isOpaquePointer())
-    S.Note(Ptr.asOpaquePointer().Base->getLocation(), diag::note_declared_at);
+    S.Note(Ptr.asOpaquePointer().Base.getLocation(), diag::note_declared_at);
 }
 
 static void diagnoseNonConstVariable(InterpState &S, CodePtr OpPC,
@@ -217,13 +217,8 @@ static void diagnoseNonConstVariable(InterpState &S, CodePtr OpPC,
   S.Note(VD->getLocation(), diag::note_declared_at);
 }
 
-static bool CheckTemporary(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
+static bool CheckTemporary(InterpState &S, CodePtr OpPC, const Block *B,
                            AccessKinds AK) {
-
-  if (!Ptr.isBlockPointer())
-    return true;
-
-  const Block *B = Ptr.block();
   if (B->getDeclID()) {
     if (!(B->isStatic() && B->isTemporary()))
       return true;
@@ -249,31 +244,11 @@ static bool CheckTemporary(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
   return true;
 }
 
-static bool CheckTemporary(InterpState &S, CodePtr OpPC, const Block *B,
+static bool CheckTemporary(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
                            AccessKinds AK) {
-  if (B->getDeclID()) {
-    if (!(B->isStatic() && B->isTemporary()))
-      return true;
-
-    const auto *MTE = dyn_cast_if_present<MaterializeTemporaryExpr>(
-        B->getDescriptor()->asExpr());
-    if (!MTE)
-      return true;
-
-    // FIXME(perf): Since we do this check on every Load from a static
-    // temporary, it might make sense to cache the value of the
-    // isUsableInConstantExpressions call.
-    if (S.checkingConstantDestruction() ||
-        (B->getEvalID() != S.EvalID &&
-         !MTE->isUsableInConstantExpressions(S.getASTContext()))) {
-      const SourceInfo &E = S.Current->getSource(OpPC);
-      S.FFDiag(E, diag::note_constexpr_access_static_temporary, 1) << AK;
-      noteValueLocation(S, B);
-      return false;
-    }
-  }
-
-  return true;
+  if (!Ptr.isBlockPointer())
+    return true;
+  return CheckTemporary(S, OpPC, Ptr.block(), AK);
 }
 
 static bool CheckGlobal(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
@@ -348,8 +323,6 @@ void cleanupAfterFunctionCall(InterpState &S, const Function *Func) {
 }
 
 bool isConstexprUnknown(const Block *B) {
-  if (B->isDummy())
-    return isa_and_nonnull<ParmVarDecl>(B->getDescriptor()->asValueDecl());
   return B->getDescriptor()->IsConstexprUnknown;
 }
 
@@ -876,8 +849,6 @@ bool CheckGlobalLoad(InterpState &S, CodePtr OpPC, const Block *B) {
   if (!B->isAccessible()) {
     if (!CheckExtern(S, OpPC, Pointer(const_cast<Block *>(B))))
       return false;
-    if (!CheckDummy(S, OpPC, B, AK_Read))
-      return false;
     return CheckWeak(S, OpPC, B);
   }
 
@@ -953,8 +924,6 @@ bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
       return false;
     if (!CheckExtern(S, OpPC, Ptr))
       return false;
-    if (!CheckDummy(S, OpPC, Ptr.block(), AK))
-      return false;
     return CheckWeak(S, OpPC, Ptr.block());
   }
 
@@ -1020,8 +989,6 @@ bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
       return false;
     if (!CheckExtern(S, OpPC, Ptr))
       return false;
-    if (!CheckDummy(S, OpPC, Ptr.block(), AK_Read))
-      return false;
     return CheckWeak(S, OpPC, Ptr.block());
   }
 
@@ -1057,9 +1024,7 @@ bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
   if (!Ptr.block()->isAccessible()) {
     if (!CheckLive(S, OpPC, Ptr, AK_Assign))
       return false;
-    if (!CheckExtern(S, OpPC, Ptr))
-      return false;
-    return CheckDummy(S, OpPC, Ptr.block(), AK_Assign);
+    return CheckExtern(S, OpPC, Ptr);
   }
   if (!WillBeActivated && !CheckLifetime(S, OpPC, Ptr, AK_Assign))
     return false;
@@ -1381,25 +1346,6 @@ bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
   return false;
 }
 
-// FIXME: Remove this once all dummy pointers are opaque pointers.
-bool CheckDummy(InterpState &S, CodePtr OpPC, const Block *B, AccessKinds AK) {
-  if (!B->isDummy())
-    return true;
-
-  const ValueDecl *D = B->getDescriptor()->asValueDecl();
-  if (!D)
-    return false;
-
-  if (AK == AK_Read || AK == AK_Increment || AK == AK_Decrement)
-    return diagnoseUnknownDecl(S, OpPC, D, AK);
-
-  if (AK == AK_Destroy || S.getLangOpts().CPlusPlus14) {
-    const SourceInfo &E = S.Current->getSource(OpPC);
-    S.FFDiag(E, diag::note_constexpr_modify_global);
-  }
-  return false;
-}
-
 static bool CheckNonNullArgs(InterpState &S, CodePtr OpPC, const Function *F,
                              const CallExpr *CE, unsigned ArgSize) {
   auto Args = ArrayRef(CE->getArgs(), CE->getNumArgs());
@@ -2648,7 +2594,7 @@ static void setLifeStateRecurse(PtrView Ptr, Lifetime L) {
 /// Ends the lifetime of the peek'd pointer.
 bool EndLifetime(InterpState &S, CodePtr OpPC) {
   const auto &Ptr = S.Stk.peek<Pointer>();
-  if (Ptr.isBlockPointer() && !CheckDummy(S, OpPC, Ptr.block(), AK_Destroy))
+  if (!CheckDummy(S, OpPC, Ptr, AK_Destroy))
     return false;
 
   setLifeStateRecurse(Ptr.view().narrow(), Lifetime::Ended);
@@ -2666,7 +2612,7 @@ bool PseudoDtor(InterpState &S, CodePtr OpPC) {
 
 bool MarkDestroyed(InterpState &S, CodePtr OpPC) {
   const auto &Ptr = S.Stk.peek<Pointer>();
-  if (Ptr.isBlockPointer() && !CheckDummy(S, OpPC, Ptr.block(), AK_Destroy))
+  if (!CheckDummy(S, OpPC, Ptr, AK_Destroy))
     return false;
 
   setLifeStateRecurse(Ptr.view().narrow(), Lifetime::Destroyed);
@@ -2863,12 +2809,6 @@ bool CheckPointerToIntegralCast(InterpState &S, CodePtr OpPC,
     return Ptr.isRoot();
   }
 
-  if (Ptr.isDummy()) {
-    if (!CheckIntegralAddressCast(S, OpPC, BitWidth))
-      return false;
-    return Ptr.getIndex() == 0;
-  }
-
   if (!Ptr.isZero()) {
     // Only allow based lvalue casts if they are lossless.
     if (!CheckIntegralAddressCast(S, OpPC, BitWidth))
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index 343883872728b..a208f8d1eed0a 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -2274,7 +2274,7 @@ inline bool LoadPopL(InterpState &S, CodePtr OpPC) {
     if (Ptr.isOpaquePointer()) {
       const OpaquePointer &OP = Ptr.asOpaquePointer();
 
-      if (!Ptr.asOpaquePointer().Base->getType()->isPointerType())
+      if (!Ptr.asOpaquePointer().Base.getType()->isPointerType())
         return false;
 
       QualType T = Ptr.getType();
@@ -2747,9 +2747,9 @@ bool SubOffset(InterpState &S, CodePtr OpPC) {
   return false;
 }
 
-inline bool GetOpaquePtr(InterpState &S, const ValueDecl *VD,
+inline bool GetOpaquePtr(InterpState &S, DeclOrExpr DOE,
                          bool ConstexprUnknown) {
-  S.Stk.push<Pointer>(VD, ConstexprUnknown);
+  S.Stk.push<Pointer>(DOE, ConstexprUnknown);
   return true;
 }
 
@@ -3072,8 +3072,8 @@ inline bool AddrOf(InterpState &S, CodePtr OpPC) {
   if (Ptr.isOpaquePointer()) {
     const OpaquePointer &OP = Ptr.asOpaquePointer();
     QualType T = QualType(OP.FieldType.getPointer(), 0);
-    T = S.getASTContext().getPointerType(T);
 
+    T = S.getASTContext().getPointerType(T);
     S.Stk.push<Pointer>(OP.withFieldType(T.getTypePtr(), OP.isOnePastEnd()));
   } else {
     S.Stk.push<Pointer>(Ptr);
@@ -3098,23 +3098,18 @@ bool CastPointerIntegral(InterpState &S, CodePtr OpPC) {
     S.Stk.push<T>(T::from(Ptr.getIntegerRepresentation()));
   } else if constexpr (isIntegralOrPointer<T>()) {
     if (Ptr.isBlockPointer()) {
-      IntegralKind Kind = IntegralKind::Address;
-      const void *PtrVal;
-      if (Ptr.isDummy()) {
-        if (const Expr *E = Ptr.getRootExpr()) {
-          PtrVal = E;
-          if (isa<AddrLabelExpr>(E))
-            Kind = IntegralKind::LabelAddress;
-        } else {
-          PtrVal = Ptr.getDeclDesc()->asDecl();
-        }
+      S.Stk.push<T>(IntegralKind::BlockAddress, Ptr.block(), /*Offset=*/0);
+    } else if (Ptr.isOpaquePointer()) {
+      if (const Expr *BaseExpr = Ptr.asOpaquePointer().getBaseExpr()) {
+        IntegralKind Kind = IntegralKind::ExprAddress;
+        if (isa<AddrLabelExpr>(BaseExpr))
+          Kind = IntegralKind::LabelAddress;
+        S.Stk.push<T>(Kind, BaseExpr, 0);
       } else {
-        PtrVal = Ptr.block();
-        Kind = IntegralKind::BlockAddress;
+        S.Stk.push<T>(IntegralKind::Address,
+                      Ptr.asOpaquePointer().Base.asVarDecl(), 0);
       }
-      S.Stk.push<T>(Kind, PtrVal, /*Offset=*/0);
-    } else if (Ptr.isOpaquePointer()) {
-      S.Stk.push<T>(IntegralKind::Address, Ptr.asOpaquePointer().Base, 0);
+
     } else if (Ptr.isFunctionPointer()) {
       const void *FuncDecl = Ptr.asFunctionPointer().Func->getDecl();
       S.Stk.push<T>(IntegralKind::FunctionAddress, FuncDecl, /*Offset=*/0);
diff --git a/clang/lib/AST/ByteCode/InterpBlock.cpp b/clang/lib/AST/ByteCode/InterpBlock.cpp
index f43b477dff7f9..888a660719590 100644
--- a/clang/lib/AST/ByteCode/InterpBlock.cpp
+++ b/clang/lib/AST/ByteCode/InterpBlock.cpp
@@ -102,20 +102,11 @@ bool Block::hasPointer(const Pointer *P) const {
 
 void Block::movePointersTo(Block *B) {
   assert(B != this);
-  unsigned MDDiff = static_cast<int>(B->MDSize) - static_cast<int>(MDSize);
 
   while (Pointers) {
     Pointer *P = Pointers;
-
     this->removePointer(P);
     P->BS.Pointee = B;
-
-    // If the metadata size changed between the two blocks, move the pointer
-    // base/offset. Realistically, this should only happen when we move pointers
-    // from a dummy pointer to a global one.
-    P->BS.Base += MDDiff;
-    P->Offset += MDDiff;
-
     B->addPointer(P);
   }
   assert(!this->hasPointers());
@@ -135,7 +126,7 @@ void Block::removePointers() {
 
 DeadBlock::DeadBlock(DeadBlock *&Root, Block *Blk)
     : Root(Root), B(~0u, Blk->Desc, Blk->MDSize, Blk->isExtern(), Blk->IsStatic,
-                    Blk->isWeak(), Blk->isDummy(),
+                    Blk->isWeak(),
                     /*IsDead=*/true) {
   // Add the block to the chain of dead blocks.
   if (Root)
diff --git a/clang/lib/AST/ByteCode/InterpBlock.h b/clang/lib/AST/ByteCode/InterpBlock.h
index ffb4bf2e75654..4d6a2ecf81321 100644
--- a/clang/lib/AST/ByteCode/InterpBlock.h
+++ b/clang/lib/AST/ByteCode/InterpBlock.h
@@ -45,7 +45,6 @@ class Block final {
   static constexpr uint8_t ExternFlag = 1 << 0;
   static constexpr uint8_t DeadFlag = 1 << 1;
   static constexpr uint8_t WeakFlag = 1 << 2;
-  static constexpr uint8_t DummyFlag = 1 << 3;
 
 public:
   static constexpr uint8_t InlineDescMD = sizeof(InlineDescriptor);
@@ -54,23 +53,20 @@ class Block final {
   /// Creates a new block.
   Block(unsigned EvalID, UnsignedOrNone DeclID, const Descriptor *Desc,
         unsigned MDSize = 0, bool IsStatic = false, bool IsExtern = false,
-        bool IsWeak = false, bool IsDummy = false)
+        bool IsWeak = false)
       : Desc(Desc), DeclID(DeclID), EvalID(EvalID), MDSize(MDSize),
         IsStatic(IsStatic) {
     assert(Desc);
     AccessFlags |= (ExternFlag * IsExtern);
     AccessFlags |= (WeakFlag * IsWeak);
-    AccessFlags |= (DummyFlag * IsDummy);
   }
 
   Block(unsigned EvalID, const Descriptor *Desc, unsigned MDSize = 0,
-        bool IsStatic = false, bool IsExtern = false, bool IsWeak = false,
-        bool IsDummy = false)
+        bool IsStatic = false, bool IsExtern = false, bool IsWeak = false)
       : Desc(Desc), EvalID(EvalID), MDSize(MDSize), IsStatic(IsStatic) {
     assert(Desc);
     AccessFlags |= (ExternFlag * IsExtern);
     AccessFlags |= (WeakFlag * IsWeak);
-    AccessFlags |= (DummyFlag * IsDummy);
   }
 
   /// Returns the block's descriptor.
@@ -85,7 +81,6 @@ class Block final {
   bool isTemporary() const { return Desc->IsTemporary; }
   bool isWeak() const { return AccessFlags & WeakFlag; }
   bool isDynamic() const { return (DynAllocId != std::nullopt); }
-  bool isDummy() const { return AccessFlags & DummyFlag; }
   bool isDead() const { return AccessFlags & DeadFlag; }
   /// Returns the size of the block, including metadata.
   unsigned getSize() const { return Desc->getAllocSize() + MDSize; }
@@ -168,13 +163,12 @@ class Block final {
   friend class Program;
 
   Block(unsigned EvalID, const Descriptor *Desc, unsigned MDSize, bool IsExtern,
-        bool IsStatic, bool IsWeak, bool IsDummy, bool IsDead)
+        bool IsStatic, bool IsWeak, bool IsDead)
       : Desc(Desc), EvalID(EvalID), MDSize(MDSize), IsStatic(IsStatic) {
     assert(Desc);
     AccessFlags |= (ExternFlag * IsExtern);
     AccessFlags |= (DeadFlag * IsDead);
     AccessFlags |= (WeakFlag * IsWeak);
-    AccessFlags |= (DummyFlag * IsDummy);
   }
 
   /// To be called by DynamicAllocator.
@@ -200,7 +194,7 @@ class Block final {
   const unsigned EvalID = ~0u;
   /// Allocation ID for this dynamic allocation, if it is one.
   UnsignedOrNone DynAllocId = std::nullopt;
-  /// AccessFlags containing IsExtern, IsDead, IsWeak, and IsDummy bits.
+  /// AccessFlags containing IsExtern, IsDead and IsWeak bits.
   uint8_t AccessFlags = 0;
   /// Size of the metadata.
   const uint8_t MDSize = 0;
diff --git a/clang/lib/AST/ByteCode/InterpBuiltinObjectSize.cpp b/clang/lib/AST/ByteCode/InterpBuiltinObjectSize.cpp
index c1a69e03c0e73..1483dbbedeb29 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltinObjectSize.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltinObjectSize.cpp
@@ -352,7 +352,7 @@ computeOpaqueSize(const ASTContext &ASTCtx, const Pointer &Ptr,
     return TypeSize.getQuantity();
 
   // Check if we need to add the flexible array member size.
-  const VarDecl *Base = dyn_cast<VarDecl>(OP.Base);
+  const VarDecl *Base = OP.getBaseDecl();
   if (!Base)
     return TypeSize.getQuantity();
 
@@ -390,7 +390,7 @@ UnsignedOrNone evaluateBuiltinObjectSize(const ASTContext &ASTCtx,
   if (Ptr.isOpaquePointer()) {
     bool UseClosestSurroundingVariable = (Kind == 1) || (Kind == 3);
     const OpaquePointer &OP = Ptr.asOpaquePointer();
-    InvalidBase = OP.Base->getType()->isPointerType();
+    InvalidBase = OP.Base.getType()->isPointerType();
     bool DetermineForCompleteObject = pointsToCompleteObject(ASTCtx, Ptr);
     bool WritingOffTheEnd = isUserWritingOffTheEnd(ASTCtx, OP);
 
diff --git a/clang/lib/AST/ByteCode/InterpHelpers.h b/clang/lib/AST/ByteCode/InterpHelpers.h
index f183efb5b19d1..703dec4d43d72 100644
--- a/clang/lib/AST/ByteCode/InterpHelpers.h
+++ b/clang/lib/AST/ByteCode/InterpHelpers.h
@@ -40,7 +40,6 @@ bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
                AccessKinds AK);
 
 /// Checks if a pointer is a dummy pointer.
-bool CheckDummy(InterpState &S, CodePtr OpPC, const Block *B, AccessKinds AK);
 bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
                 AccessKinds AK);
 
diff --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td
index 1831dc161f0a5..a3aaeff67e301 100644
--- a/clang/lib/AST/ByteCode/Opcodes.td
+++ b/clang/lib/AST/ByteCode/Opcodes.td
@@ -72,6 +72,7 @@ def ArgDesc : ArgType { let Name = "const Descriptor *"; }
 def ArgPrimType : ArgType { let Name = "PrimType"; }
 def ArgEnumDecl : ArgType { let Name = "const EnumDecl *"; }
 def ArgTypePtr : ArgType { let Name = "const Type *"; }
+def ArgDeclOrExpr : ArgType { let Name = "DeclOrExpr"; }
 
 //===----------------------------------------------------------------------===//
 // Classes of types instructions operate on.
@@ -618,7 +619,7 @@ def AddOffset : Opcode {
 }
 
 def GetOpaquePtr : SuccessOpcode {
-  let Args = [ArgValueDecl, ArgBool];
+  let Args = [ArgDeclOrExpr, ArgBool];
 }
 
 // [Pointer, Integral] -> [Pointer]
diff --git a/clang/lib/AST/ByteCode/Pointer.cpp b/clang/lib/AST/ByteCode/Pointer.cpp
index 9a068071df570..bdc73c7cb1efd 100644
--- a/clang/lib/AST/ByteCode/Pointer.cpp
+++ b/clang/lib/AST/ByteCode/Pointer.cpp
@@ -286,7 +286,7 @@ APValue Pointer::toAPValue(const ASTContext &ASTCtx) const {
                    CharUnits::fromQuantity(Offset * elemSize()), Path,
                    /*OnePastTheEnd=*/false, /*IsNull=*/false);
   case Storage::Opaque: {
-    if (!Opaque.Base->getType()->isPointerType()) {
+    if (!Opaque.Base.getType()->isPointerType()) {
       for (const PointerPathEntry &Entry : Opaque.path()) {
         switch (Entry.Kind) {
         case PointerPathEntry::Field:
@@ -307,9 +307,15 @@ APValue Pointer::toAPValue(const ASTContext &ASTCtx) const {
     }
     size_t LayoutOffset = Opaque.computeLayoutOffset(ASTCtx).value_or(0);
     auto Offset = CharUnits::fromQuantity(LayoutOffset + getByteOffset());
-    auto Result =
-        APValue(Opaque.Base, Offset, Path,
-                /*IsOnePastEnd=*/Opaque.isOnePastEnd(), /*IsNullPtr=*/false);
+    APValue Result;
+    if (const Expr *E = Opaque.Base.asExpr())
+      Result =
+          APValue(E, Offset, Path,
+                  /*IsOnePastEnd=*/Opaque.isOnePastEnd(), /*IsNullPtr=*/false);
+    else
+      Result =
+          APValue(Opaque.Base.asValueDecl(), Offset, Path,
+                  /*IsOnePastEnd=*/Opaque.isOnePastEnd(), /*IsNullPtr=*/false);
     Result.setConstexprUnknown(Opaque.isConstexprUnknown());
     return Result;
   }
@@ -951,15 +957,16 @@ bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) {
   // We allow comparisons between opaque pointers and block pointers, provided
   // they have the same declaration as base.
   if (A.StorageKind != B.StorageKind) {
-    if (A.isOpaquePointer() && B.isBlockPointer()) {
+    if (A.isOpaquePointer() && A.Opaque.Base.isVarDecl() &&
+        B.isBlockPointer()) {
       if (const VarDecl *BDecl = B.block()->getDescriptor()->asVarDecl())
-        return BDecl == A.Opaque.Base->getMostRecentDecl();
-
+        return BDecl == A.Opaque.Base.asVarDecl()->getMostRecentDecl();
       return false;
     }
-    if (B.isOpaquePointer() && A.isBlockPointer()) {
+    if (B.isOpaquePointer() && B.Opaque.Base.isVarDecl() &&
+        A.isBlockPointer()) {
       if (const VarDecl *ADecl = A.block()->getDescriptor()->asVarDecl())
-        return ADecl == B.Opaque.Base->getMostRecentDecl();
+        return ADecl == B.Opaque.Base.asVarDecl()->getMostRecentDecl();
       return false;
     }
     return false;
@@ -969,8 +976,7 @@ bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) {
   case Storage::Int:
     return true;
   case Storage::Block:
-    // See below.
-    break;
+    return A.BS.Pointee == B.BS.Pointee;
   case Storage::Fn:
     return true;
   case Storage::Typeid:
@@ -978,11 +984,14 @@ bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) {
   case Storage::String:
     return A.Str.ID == B.Str.ID && A.Str.getLiteral() == B.Str.getLiteral();
   case Storage::Opaque:
-    return A.asOpaquePointer().Base->getMostRecentDecl() ==
-           B.asOpaquePointer().Base->getMostRecentDecl();
+    if (A.Opaque.Base.isExpr())
+      return B.Opaque.Base.isExpr() && A.Opaque.Base == B.Opaque.Base;
+    if (A.Opaque.Base.isVarDecl())
+      return B.Opaque.Base.isVarDecl() &&
+             A.Opaque.Base.asVarDecl()->getMostRecentDecl() ==
+                 B.Opaque.Base.asVarDecl()->getMostRecentDecl();
+    return false;
   }
-
-  return A.asBlockPointer().Pointee == B.asBlockPointer().Pointee;
 }
 
 bool Pointer::pointToSameBlock(const Pointer &A, const Pointer &B) {
@@ -1032,23 +1041,24 @@ bool Pointer::elemsOfSameArray(const Pointer &A, const Pointer &B) {
   return true;
 }
 
+// FIXME: This should return true for string pointers.
 bool Pointer::pointsToLiteral() const {
-  if (isZero() || !isBlockPointer())
+  if (isZero())
     return false;
 
-  if (block()->isDynamic())
+  if (isDynamic())
     return false;
 
-  const Expr *E = block()->getDescriptor()->asExpr();
+  const Expr *E = getRootExpr();
   return E && !isa<MaterializeTemporaryExpr, StringLiteral>(E);
 }
 
 bool Pointer::pointsToLabel() const {
-  if (isZero() || !isBlockPointer())
+  if (isZero())
     return false;
 
-  if (const Expr *E = BS.Pointee->getDescriptor()->asExpr())
-    return isa<AddrLabelExpr>(E);
+  if (isOpaquePointer())
+    return isa_and_nonnull<AddrLabelExpr>(Opaque.Base.asExpr());
   return false;
 }
 
@@ -1106,7 +1116,7 @@ static bool toRValue(const Context &Ctx, QualType Ty, PtrView Ptr, APValue &R) {
     Ty = AT->getValueType();
 
   // Invalid pointers.
-  if (Ptr.isDummy() || !Ptr.isLive() || Ptr.isPastEnd())
+  if (!Ptr.isLive() || Ptr.isPastEnd())
     return false;
 
   // Primitives should never end up here.
@@ -1304,7 +1314,7 @@ const VarDecl *Pointer::getRootVarDecl() const {
   if (isBlockPointer())
     return getDeclDesc()->asVarDecl();
   if (isOpaquePointer())
-    return dyn_cast<VarDecl>(Opaque.Base);
+    return Opaque.getBaseDecl();
   return nullptr;
 }
 
@@ -1313,6 +1323,8 @@ const Expr *Pointer::getRootExpr() const {
     return getDeclDesc()->asExpr();
   if (isStringPointer())
     return Str.getLiteral();
+  if (isOpaquePointer())
+    return Opaque.getBaseExpr();
   return nullptr;
 }
 
@@ -1508,7 +1520,7 @@ bool OpaquePointer::isUnknownSizeArray() const {
   // base to see if this array is a flexible array member _and_ has actually
   // been initialized by data we know the size of.
   if (isa<IncompleteArrayType>(FieldType)) {
-    const VarDecl *Base = cast<VarDecl>(this->Base);
+    const VarDecl *Base = this->Base.asVarDecl();
     if (!Base || !Base->getType()->isRecordType() || !Base->hasInit())
       Result = true;
     else
diff --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h
index 5b43df9db49c4..c890961224483 100644
--- a/clang/lib/AST/ByteCode/Pointer.h
+++ b/clang/lib/AST/ByteCode/Pointer.h
@@ -42,7 +42,6 @@ struct PtrView {
 
   bool isZero() const { return !Pointee; }
   bool isLive() const { return Pointee && !Pointee->isDead(); }
-  bool isDummy() const { return Pointee && Pointee->isDummy(); }
   bool isActive() const { return isRoot() || getInlineDesc()->IsActive; }
   bool isArrayRoot() const { return inArray() && Offset == Base; }
   bool isElementPastEnd() const { return Offset == PastEndMark; }
@@ -430,13 +429,15 @@ struct PointerPathEntry {
 };
 
 struct OpaquePointer {
-  const ValueDecl *Base = nullptr;
+  DeclOrExpr Base;
   // FieldType and IsOnePastEnd/IsConstexprUnknown bits.
   llvm::PointerIntPair<const Type *, 2, unsigned> FieldType = {};
   const PointerPathEntry *Path = nullptr;
   unsigned PathLength = 0;
 
   ArrayRef<PointerPathEntry> path() const { return ArrayRef(Path, PathLength); }
+  const VarDecl *getBaseDecl() const { return Base.asVarDecl(); }
+  const Expr *getBaseExpr() const { return Base.asExpr(); }
 
   OpaquePointer
   withFieldType(const Type *FieldTy,
@@ -467,14 +468,14 @@ struct OpaquePointer {
   }
 
   QualType getObjectType() const {
-    QualType T = Base->getType();
+    QualType T = Base.getType();
     if (T->isPointerOrReferenceType())
       return T->getPointeeType();
     return T;
   }
 
   QualType getFieldType() const {
-    if (FieldType.getPointer()->isPointerOrReferenceType())
+    if (FieldType.getPointer()->isPointerOrReferenceType() && Base.isDecl())
       return FieldType.getPointer()->getPointeeType();
     return QualType(FieldType.getPointer(), 0);
   }
@@ -549,11 +550,11 @@ class Pointer {
       : Offset(0), StorageKind(Storage::String), Str{Base, Id} {}
   Pointer(StringPointer Str, uint64_t Offset = 0)
       : Offset(Offset), StorageKind(Storage::String), Str(Str) {}
-  Pointer(const ValueDecl *Base, bool ConstexprUnknown = false)
+
+  Pointer(DeclOrExpr DOE, bool ConstexprUnknown = false)
       : Offset(0), StorageKind(Storage::Opaque) {
-    Opaque.Base = Base;
-    Opaque.FieldType = {Base->getType().getTypePtr(),
-                        ConstexprUnknown ? 2u : 0u};
+    Opaque.Base = DOE;
+    Opaque.FieldType = {DOE.getType().getTypePtr(), ConstexprUnknown ? 2u : 0u};
     Opaque.Path = nullptr;
     Opaque.PathLength = 0;
   }
@@ -907,8 +908,11 @@ class Pointer {
       return Fn.Func->getDecl()->isWeak();
     }
 
-    if (isOpaquePointer())
-      return Opaque.Base->isWeak();
+    if (isOpaquePointer()) {
+      if (const VarDecl *BaseDecl = Opaque.getBaseDecl())
+        return BaseDecl->isWeak();
+      return false;
+    }
     if (!isBlockPointer())
       return false;
 
@@ -929,9 +933,7 @@ class Pointer {
   bool isDummy() const {
     if (isOpaquePointer())
       return true;
-    if (!isBlockPointer())
-      return false;
-    return view().isDummy();
+    return false;
   }
 
   /// Checks if an object or a subfield is mutable.
@@ -1278,9 +1280,7 @@ class Pointer {
   bool pointsToLabel() const;
   /// Returns the AddrLabelExpr the Pointer points to, if any.
   const AddrLabelExpr *getPointedToLabel() const {
-    if (const Descriptor *Desc = getDeclDesc())
-      return dyn_cast_if_present<AddrLabelExpr>(Desc->asExpr());
-    return nullptr;
+    return dyn_cast_if_present<AddrLabelExpr>(getRootExpr());
   }
 
   /// Prints the pointer.
@@ -1367,7 +1367,7 @@ inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Pointer &P) {
   } else if (P.isBlockPointer() && P.isArrayRoot())
     OS << " arrayroot";
 
-  if (P.isBlockPointer() && P.block() && P.block()->isDummy())
+  if (P.isDummy())
     OS << " dummy";
   if (!P.isLive())
     OS << " dead";
diff --git a/clang/lib/AST/ByteCode/Program.cpp b/clang/lib/AST/ByteCode/Program.cpp
index f7bb9540570a7..744d8a64e414d 100644
--- a/clang/lib/AST/ByteCode/Program.cpp
+++ b/clang/lib/AST/ByteCode/Program.cpp
@@ -60,60 +60,6 @@ UnsignedOrNone Program::getOrCreateGlobal(const ValueDecl *VD,
   return std::nullopt;
 }
 
-unsigned Program::getOrCreateDummy(DeclOrExpr D, bool IsConstexprUnknown) {
-  assert(D);
-
-  if (const auto *VD = D.asVarDecl())
-    D = VD->getFirstDecl();
-
-  // Dedup blocks since they are immutable and pointers cannot be compared.
-  if (auto It = DummyVariables.find(D.getOpaqueValue());
-      It != DummyVariables.end())
-    return It->second;
-
-  QualType QT;
-  bool IsWeak = false;
-  if (const auto *E = D.asExpr()) {
-    QT = E->getType();
-  } else {
-    const auto *VD = D.asValueDecl();
-    IsWeak = VD->isWeak();
-    QT = VD->getType();
-
-    if (QT->isReferenceType())
-      QT = QT->getPointeeType();
-  }
-
-  assert(!QT.isNull());
-
-  Descriptor *Desc;
-  if (OptPrimType T = Ctx.classify(QT))
-    Desc = createDescriptor(D, *T, /*SourceTy=*/nullptr,
-                            /*IsConst=*/QT.isConstQualified());
-  else
-    Desc = createDescriptor(D, QT.getTypePtr(),
-                            /*IsConst=*/QT.isConstQualified());
-  if (!Desc)
-    Desc = allocateDescriptor(D);
-
-  Desc->IsConstexprUnknown = IsConstexprUnknown;
-
-  assert(Desc);
-
-  // Allocate a block for storage.
-  unsigned I = Globals.size();
-
-  auto *G = new (Allocator, Desc->getAllocSize())
-      Global(Ctx.getEvalID(), getCurrentDecl(), Desc, /*MDSize=*/0u,
-             /*IsStatic=*/true, /*IsExtern=*/false, IsWeak, /*IsDummy=*/true);
-  G->block()->invokeCtor();
-  assert(G->block()->isDummy());
-
-  Globals.push_back(G);
-  DummyVariables[D.getOpaqueValue()] = I;
-  return I;
-}
-
 UnsignedOrNone Program::createGlobal(const ValueDecl *VD, const Expr *Init,
                                      bool IsConstexprUnknown) {
   bool IsStatic, IsExtern;
@@ -142,15 +88,6 @@ UnsignedOrNone Program::createGlobal(const ValueDecl *VD, const Expr *Init,
 
   for (const Decl *Redecl = VD->getPreviousDecl(); Redecl;
        Redecl = Redecl->getPreviousDecl()) {
-    // If this redecl was registered as a dummy variable, it is now a proper
-    // global variable and points to the block we just created.
-    if (auto DummyIt = DummyVariables.find(Redecl);
-        DummyIt != DummyVariables.end()) {
-      Global *Dummy = Globals[DummyIt->second];
-      Dummy->block()->movePointersTo(NewGlobal->block());
-      Globals[DummyIt->second] = NewGlobal;
-      DummyVariables.erase(DummyIt);
-    }
     // If the redeclaration hasn't been registered yet at all, we just set its
     // global index to Idx. If it has been registered yet, it might have
     // pointers pointing to it and we need to transfer those pointers to the new
diff --git a/clang/lib/AST/ByteCode/Program.h b/clang/lib/AST/ByteCode/Program.h
index 6c9a21728775d..ccd6720cce738 100644
--- a/clang/lib/AST/ByteCode/Program.h
+++ b/clang/lib/AST/ByteCode/Program.h
@@ -81,9 +81,6 @@ class Program final {
   UnsignedOrNone getOrCreateGlobal(const ValueDecl *VD,
                                    const Expr *Init = nullptr);
 
-  /// Returns or creates a dummy value for unknown declarations.
-  unsigned getOrCreateDummy(DeclOrExpr D, bool IsConstexprUnknown = false);
-
   /// Creates a global and returns its index.
   UnsignedOrNone createGlobal(const ValueDecl *VD, const Expr *Init,
                               bool IsConstexprUnknown = false);
@@ -211,9 +208,6 @@ class Program final {
   /// Mapping from decls to record metadata.
   llvm::DenseMap<const RecordDecl *, Record *> Records;
 
-  /// Dummy parameter to generate pointers from.
-  llvm::DenseMap<const void *, unsigned> DummyVariables;
-
   /// Creates a new descriptor.
   template <typename... Ts> Descriptor *allocateDescriptor(Ts &&...Args) {
     return new (Allocator) Descriptor(std::forward<Ts>(Args)...);



More information about the cfe-commits mailing list