[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