[clang] [clang][bytecode] Use opaque pointers for expr-based dummy pointers (PR #221218)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Sep 4 06:05:27 PDT 2026
Timm =?utf-8?q?Bäder?= <tbaeder at redhat.com>
Message-ID:
In-Reply-To: <llvm.org/llvm/llvm-project/pull/221218 at github.com>
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Timm Baeder (tbaederr)
<details>
<summary>Changes</summary>
Similar to https://github.com/llvm/llvm-project/pull/220917, but for expressions.
The first commit is the one from https://github.com/llvm/llvm-project/pull/220917.
---
Patch is 63.75 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/221218.diff
21 Files Affected:
- (modified) clang/lib/AST/ByteCode/Compiler.cpp (+10-22)
- (modified) clang/lib/AST/ByteCode/DeclOrExpr.h (+7)
- (modified) clang/lib/AST/ByteCode/Disasm.cpp (+1-5)
- (modified) clang/lib/AST/ByteCode/EvaluationResult.cpp (+2-2)
- (modified) clang/lib/AST/ByteCode/Interp.cpp (+138-47)
- (modified) clang/lib/AST/ByteCode/Interp.h (+91-43)
- (modified) clang/lib/AST/ByteCode/InterpBlock.cpp (+1-10)
- (modified) clang/lib/AST/ByteCode/InterpBlock.h (+4-10)
- (modified) clang/lib/AST/ByteCode/InterpBuiltin.cpp (+38-15)
- (modified) clang/lib/AST/ByteCode/InterpBuiltinObjectSize.cpp (+2-2)
- (modified) clang/lib/AST/ByteCode/InterpHelpers.h (+5-1)
- (modified) clang/lib/AST/ByteCode/MemberPointer.h (+2)
- (modified) clang/lib/AST/ByteCode/Opcodes.td (+8-4)
- (modified) clang/lib/AST/ByteCode/Pointer.cpp (+92-21)
- (modified) clang/lib/AST/ByteCode/Pointer.h (+44-23)
- (modified) clang/lib/AST/ByteCode/Program.cpp (-63)
- (modified) clang/lib/AST/ByteCode/Program.h (-6)
- (modified) clang/test/AST/ByteCode/records.cpp (+6)
- (modified) clang/test/CodeGen/pr4349.c (+2-1)
- (modified) clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp (+1)
- (modified) clang/unittests/AST/ByteCode/toAPValue.cpp (-2)
``````````diff
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index 03f9478a6e4e0..d2feac9c03b30 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -7936,12 +7936,18 @@ bool Compiler<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
// check), so that e.g. '&*(int *)0' is not rejected.
if (!Ctx.getLangOpts().CPlusPlus) {
const Expr *Sub = SubExpr->IgnoreParens();
+
if (const auto *Deref = dyn_cast<UnaryOperator>(Sub);
- Deref && Deref->getOpcode() == UO_Deref)
- return this->delegate(Deref->getSubExpr());
+ Deref && Deref->getOpcode() == UO_Deref) {
+ if (DiscardResult)
+ return this->discard(Deref->getSubExpr());
+ return this->visit(Deref->getSubExpr()) && this->emitAddrOf(E);
+ }
}
// We should already have a pointer when we get here.
- return this->delegate(SubExpr);
+ if (DiscardResult)
+ return this->discard(SubExpr);
+ return this->delegate(SubExpr) && this->emitAddrOf(E);
case UO_Deref: // *x
if (DiscardResult)
return this->discard(SubExpr);
@@ -8729,25 +8735,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 (ToLValue) {
- if (const auto *VD = D.asValueDecl())
- return this->emitGetOpaquePtr(VD, CU, E);
- }
-
- 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 a41cc1f5a564b..1c4d0862f8a49 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -97,6 +97,23 @@ static void noteValueLocation(InterpState &S, const Block *B) {
S.Note(Desc->getLocation(), diag::note_declared_at);
}
+static void noteValueLocation(InterpState &S, const Pointer &Ptr) {
+ if (Ptr.isBlockPointer()) {
+ const Block *B = Ptr.block();
+ const Descriptor *Desc = B->getDescriptor();
+ if (B->isDynamic())
+ S.Note(Desc->getLocation(), diag::note_constexpr_dynamic_alloc_here);
+ else if (B->isTemporary())
+ S.Note(Desc->getLocation(), diag::note_constexpr_temporary_here);
+ else
+ S.Note(Desc->getLocation(), diag::note_declared_at);
+ return;
+ }
+
+ if (Ptr.isOpaquePointer())
+ S.Note(Ptr.asOpaquePointer().Base.getLocation(), diag::note_declared_at);
+}
+
static void diagnoseNonConstVariable(InterpState &S, CodePtr OpPC,
const ValueDecl *VD,
AccessKinds AK = AK_Read);
@@ -219,6 +236,13 @@ static bool CheckTemporary(InterpState &S, CodePtr OpPC, const Block *B,
return true;
}
+static bool CheckTemporary(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
+ AccessKinds AK) {
+ if (!Ptr.isBlockPointer())
+ return true;
+ return CheckTemporary(S, OpPC, Ptr.block(), AK);
+}
+
static bool CheckGlobal(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
if (auto ID = Ptr.getDeclID()) {
if (!Ptr.isStatic())
@@ -291,8 +315,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;
}
@@ -452,7 +474,7 @@ bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
} else if (!S.checkingPotentialConstantExpression()) {
S.FFDiag(Src, diag::note_constexpr_access_uninit)
<< AK << /*uninitialized=*/false << S.Current->getRange(OpPC);
- noteValueLocation(S, Ptr.block());
+ noteValueLocation(S, Ptr);
}
return false;
@@ -819,8 +841,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);
}
@@ -889,15 +909,13 @@ bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
}
// Block and string pointers are the only ones we can actually read from.
if (!Ptr.isReadablePointerType())
- return false;
+ return CheckDummy(S, OpPC, Ptr, AK);
if (Ptr.isBlockPointer() && !Ptr.block()->isAccessible()) {
if (!CheckLive(S, OpPC, Ptr, AK))
return false;
if (!CheckExtern(S, OpPC, Ptr))
return false;
- if (!CheckDummy(S, OpPC, Ptr.block(), AK))
- return false;
return CheckWeak(S, OpPC, Ptr.block());
}
@@ -956,15 +974,13 @@ bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
assert(!Ptr.isZero());
if (!Ptr.isReadablePointerType())
- return false;
+ return CheckDummy(S, OpPC, Ptr, AK_Read);
if (Ptr.isBlockPointer() && !Ptr.block()->isAccessible()) {
if (!CheckLive(S, OpPC, Ptr, AK_Read))
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());
}
@@ -988,15 +1004,19 @@ bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
bool WillBeActivated) {
- if (!Ptr.isBlockPointer() || Ptr.isZero())
+ if (Ptr.isZero())
+ return false;
+
+ if (Ptr.isOpaquePointer())
+ return CheckDummy(S, OpPC, Ptr, AK_Assign);
+
+ if (!Ptr.isBlockPointer())
return false;
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;
@@ -1035,6 +1055,8 @@ bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
return false;
if (!CheckRange(S, OpPC, Ptr, AK_Assign))
return false;
+ if (!Ptr.isBlockPointer())
+ return false;
return true;
}
@@ -1255,6 +1277,8 @@ bool CheckNewDeleteForms(InterpState &S, CodePtr OpPC,
bool CheckDeleteSource(InterpState &S, CodePtr OpPC, const Expr *Source,
const Pointer &Ptr) {
+ if (!Ptr.isBlockPointer() && !Ptr.isOpaquePointer())
+ return false;
// Regular new type(...) call.
if (isa_and_nonnull<CXXNewExpr>(Source))
return true;
@@ -1271,7 +1295,7 @@ bool CheckDeleteSource(InterpState &S, CodePtr OpPC, const Expr *Source,
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_delete_not_heap_alloc)
<< Ptr.toDiagnosticString(S.getASTContext());
- noteValueLocation(S, Ptr.block());
+ noteValueLocation(S, Ptr);
return false;
}
@@ -1297,21 +1321,20 @@ bool InvalidDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR,
return CheckDeclRef(S, OpPC, DR);
}
-bool CheckDummy(InterpState &S, CodePtr OpPC, const Block *B, AccessKinds AK) {
- if (!B->isDummy())
+bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
+ AccessKinds AK) {
+ if (!Ptr.isDummy())
return true;
- const ValueDecl *D = B->getDescriptor()->asValueDecl();
+ const VarDecl *D = Ptr.getRootVarDecl();
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);
- }
+ if (AK == AK_Destroy || S.getLangOpts().CPlusPlus14)
+ S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_modify_global);
return false;
}
@@ -1421,7 +1444,7 @@ bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm,
return true;
if (!Ptr.isBlockPointer())
- return false;
+ return CheckDeleteSource(S, OpPC, nullptr, Ptr);
// Remove base casts.
QualType InitialType = Ptr.getType();
@@ -1803,7 +1826,7 @@ static bool diagnoseOutOfLifetimeDestroy(InterpState &S, CodePtr OpPC,
bool checkDestructor(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
if (!CheckLive(S, OpPC, Ptr, AK_Destroy))
return false;
- if (!CheckTemporary(S, OpPC, Ptr.block(), AK_Destroy))
+ if (!CheckTemporary(S, OpPC, Ptr, AK_Destroy))
return false;
if (!CheckRange(S, OpPC, Ptr, AK_Destroy))
return false;
@@ -1819,7 +1842,7 @@ bool checkDestructor(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
return true;
// Can't call a dtor on a global variable.
- if (Ptr.block()->isStatic()) {
+ if (Ptr.isOpaquePointer() || Ptr.block()->isStatic()) {
const SourceInfo &E = S.Current->getSource(OpPC);
S.FFDiag(E, diag::note_constexpr_modify_global);
return false;
@@ -2048,9 +2071,22 @@ bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
return true;
}
-static bool getDynamicDecl(InterpState &S, CodePtr OpPC, PtrView TypePtr,
+static bool getDynamicDecl(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
const CXXRecordDecl *&DynamicDecl) {
+ auto diagUnknownDynamicType = [&](const Pointer &P) -> bool {
+ APValue V = P.toAPValue(S.getASTContext());
+ QualType TT = S.getASTContext().getLValueReferenceType(P.getType());
+ S.FFDiag(S.Current->getSource(OpPC),
+ diag::note_constexpr_polymorphic_unknown_dynamic_type)
+ << AK_MemberCall << V.getAsString(S.getASTContext(), TT);
+ return false;
+ };
+
+ if (!Ptr.isBlockPointer())
+ return diagUnknownDynamicType(Ptr);
+
+ PtrView TypePtr = Ptr.view();
if (S.InitializingPtrs.empty()) {
TypePtr = TypePtr.stripBaseCasts();
} else {
@@ -2082,14 +2118,8 @@ static bool getDynamicDecl(InterpState &S, CodePtr OpPC, PtrView TypePtr,
QualType DynamicType = TypePtr.getType();
if (TypePtr.Pointee->isStatic() || TypePtr.isConst()) {
if (const VarDecl *VD = Pointer(TypePtr).getRootVarDecl();
- VD && !VD->isConstexpr()) {
- const Expr *E = S.Current->getExpr(OpPC);
- APValue V = Pointer(TypePtr).toAPValue(S.getASTContext());
- QualType TT = S.getASTContext().getLValueReferenceType(DynamicType);
- S.FFDiag(E, diag::note_constexpr_polymorphic_unknown_dynamic_type)
- << AK_MemberCall << V.getAsString(S.getASTContext(), TT);
- return false;
- }
+ VD && !VD->isConstexpr())
+ return diagUnknownDynamicType(Pointer(TypePtr));
}
if (DynamicType->isPointerType() || DynamicType->isReferenceType()) {
@@ -2154,7 +2184,7 @@ bool DynamicCast(InterpState &S, CodePtr OpPC, const Type *DestTypePtr,
const auto &Ptr = S.Stk.pop<Pointer>();
QualType TargetType = QualType(DestTypePtr, 0);
- if (Ptr.isConstexprUnknown()) {
+ if (Ptr.isConstexprUnknown() || Ptr.isOpaquePointer()) {
QualType T = Ptr.getType();
const Expr *E = S.Current->getExpr(OpPC);
APValue V = Ptr.toAPValue(S.getASTContext());
@@ -2323,13 +2353,13 @@ bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,
size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);
Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);
- if (!ThisPtr.isBlockPointer())
+ if (!ThisPtr.isBlockPointer() && !ThisPtr.isOpaquePointer())
return false;
const FunctionDecl *Callee = Func->getDecl();
const CXXRecordDecl *DynamicDecl = nullptr;
- if (!getDynamicDecl(S, OpPC, ThisPtr.view(), DynamicDecl))
+ if (!getDynamicDecl(S, OpPC, ThisPtr, DynamicDecl))
return false;
assert(DynamicDecl);
@@ -2556,7 +2586,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);
@@ -2574,7 +2604,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);
@@ -2603,7 +2633,7 @@ bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, const Expr *E,
}
if (!Ptr.isBlockPointer())
- return false;
+ return CheckDummy(S, OpPC, Ptr, AK_Construct);
if (!CheckRange(S, OpPC, Ptr, AK_Construct))
return false;
@@ -2617,9 +2647,9 @@ bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, const Expr *E,
return false;
if (!CheckLive(S, OpPC, Ptr, AK_Construct))
return false;
- return CheckDummy(S, OpPC, Ptr.block(), AK_Construct);
+ return CheckDummy(S, OpPC, Ptr, AK_Construct);
}
- if (!CheckTemporary(S, OpPC, Ptr.block(), AK_Construct))
+ if (!CheckTemporary(S, OpPC, Ptr, AK_Construct))
return false;
// CheckLifetime for this and all base pointers.
@@ -2765,10 +2795,10 @@ bool CheckPointerToIntegralCast(InterpState &S, CodePtr OpPC,
if (Ptr.isIntegralPointer())
return true;
- if (Ptr.isDummy()) {
+ if (Ptr.isOpaquePointer()) {
if (!CheckIntegralAddressCast(S, OpPC, BitWidth))
return false;
- return Ptr.getIndex() == 0;
+ return Ptr.isRoot();
}
if (!Ptr.isZero()) {
@@ -2854,7 +2884,7 @@ bool GetTypeid(InterpState &S, const Type *TypePtr, const Type *TypeInfoType) {
bool GetTypeidPtr(InterpState &S, CodePtr OpPC, const Type *TypeInfoType) {
const auto &P = S.Stk.pop<Pointer>();
- if (!P.isBlockPointer())
+ if (!P.isBlockPointer() && !P.isOpaquePointer())
return false;
if (P.isConstexprUnknown()) {
@@ -2868,7 +2898,12 @@ bool GetTypeidPtr(InterpState &S, CodePtr OpPC, const Type *TypeInfoType) {
}
// Pick the most-derived type.
- CanQualType T = P.stripBaseCasts().getType()->getCanonicalTypeUnqualified();
+ CanQualType T;
+ if (P.isBlockPointer())
+ T = P.stripBaseCasts().getType()->getCanonicalTypeUnqualified();
+ else
+ T = P.getType()->getCanonicalTypeUnqualified();
+
// ... unless we're currently constructing this object.
// FIXME: We have a similar check to this in more places.
if (S.Current->getFunction()) {
@@ -2971,6 +3006,17 @@ static void copyPrimitiveMemory(InterpState &S, PtrView Ptr, PrimType T) {
auto *NewPath = new (S.P) const CXXRecordDecl *[PathLength];
std::copy_n(Val.path(), PathLength, NewPath);
Val.takePath(NewPath);
+ } else if (T == PT_Ptr) {
+ auto &Val = Ptr.deref<Pointer>();
+ if (Val.isOpaquePointer() && Val.asOpaquePointer().PathLength != 0) {
+ const OpaquePointer &OP = Val.asOpaquePointer();
+ auto *NewPath = new (S.P) PointerPathEntry[OP.PathLength];
+ std::memcpy(NewPath, OP.Path, OP.PathLength * sizeof(PointerPathEntry));
+ Val = Pointer(OP.withPath(NewPath, OP.PathLength,
+ OP.getFieldType().getTypePtr(),
+ OP.isOnePastEnd()),
+ Val.getByteOffset());
+ }
}
}
@@ -2983,6 +3029,17 @@ static void copyPrimitiveMemory(InterpState &S, PtrView Ptr) {
auto *NewPath = new (S.P) const CXXRecordDecl *[PathLength];
std::copy_n(Val.path(), PathLength, NewPath);
Val.takePath(NewPath);
+ } else if constexpr (std::is_same_v<T, Pointer>) {
+ auto &Val = Ptr.deref<Pointer>();
+ if (Val.isOpaquePointer() && Val.asOpaquePointer().PathLength != 0) {
+ const OpaquePointer &OP = Val.asOpaquePointer();
+ auto *NewPath = new (S.P) PointerPathEntry[OP.PathLength];
+ std::memcpy(NewPath, OP.Path, OP.PathLength * sizeof(PointerPathEntry));
+ Val = Pointer(OP.withPath(NewPath, OP.PathLength,
+ OP.getFieldType().getTypePtr(),
+ OP.isOnePastEnd()),
+ Val.getByteOffset());
+ }
} else {
auto &Val = Ptr.deref<T>();
if (!Val.singleWord()) {
@@ -3042,6 +3099,8 @@ static void finishGlobalRecurse(InterpState &S, PtrView Ptr) {
bool FinishInitGlobal(InterpState &S) {
const Pointer &Ptr = S.Stk.pop<Pointer>();
+ if (!Ptr.isBlockPointer())
+ return true;
finishGlobalRecurse(S, Ptr.view());
if (Ptr.canBeInitialized()) {
@@ -3404,6 +3463,38 @@ std::o...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/221218
More information about the cfe-commits
mailing list