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?= <[email protected]> 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)...); _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
