llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Timm Baeder (tbaederr) <details> <summary>Changes</summary> This way, we can check a single uint8_t for != 0 to know whether this block is accessible or not. If not, we still need to figure out why not and diagnose appropriately of course. --- Patch is 20.19 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/152590.diff 11 Files Affected: - (modified) clang/lib/AST/ByteCode/Compiler.cpp (-4) - (modified) clang/lib/AST/ByteCode/Descriptor.cpp (+4-3) - (modified) clang/lib/AST/ByteCode/Descriptor.h (-7) - (modified) clang/lib/AST/ByteCode/Disasm.cpp (+5-6) - (modified) clang/lib/AST/ByteCode/Interp.cpp (+77-34) - (modified) clang/lib/AST/ByteCode/InterpBlock.cpp (+3-3) - (modified) clang/lib/AST/ByteCode/InterpBlock.h (+34-20) - (modified) clang/lib/AST/ByteCode/InterpBuiltin.cpp (+7) - (modified) clang/lib/AST/ByteCode/InterpState.cpp (+4-1) - (modified) clang/lib/AST/ByteCode/Pointer.h (+4-5) - (modified) clang/lib/AST/ByteCode/Program.cpp (+2-4) ``````````diff diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index cc99efa01b83e..67b9a569ba9b1 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -7142,10 +7142,6 @@ bool Compiler<Emitter>::emitDestruction(const Descriptor *Desc, assert(!Desc->isPrimitive()); assert(!Desc->isPrimitiveArray()); - // Can happen if the decl is invalid. - if (Desc->isDummy()) - return true; - // Arrays. if (Desc->isArray()) { const Descriptor *ElemDesc = Desc->ElemDesc; diff --git a/clang/lib/AST/ByteCode/Descriptor.cpp b/clang/lib/AST/ByteCode/Descriptor.cpp index 629c1ffa3602e..67ec6b17efc8d 100644 --- a/clang/lib/AST/ByteCode/Descriptor.cpp +++ b/clang/lib/AST/ByteCode/Descriptor.cpp @@ -367,7 +367,7 @@ Descriptor::Descriptor(const DeclTy &D, const Record *R, MetadataSize MD, Descriptor::Descriptor(const DeclTy &D, MetadataSize MD) : Source(D), ElemSize(1), Size(1), MDSize(MD.value_or(0)), AllocSize(MDSize), ElemRecord(nullptr), IsConst(true), IsMutable(false), - IsTemporary(false), IsDummy(true) { + IsTemporary(false) { assert(Source && "Missing source"); } @@ -453,7 +453,7 @@ SourceInfo Descriptor::getLoc() const { } bool Descriptor::hasTrivialDtor() const { - if (isPrimitive() || isPrimitiveArray() || isDummy()) + if (isPrimitive() || isPrimitiveArray()) return true; if (isRecord()) { @@ -462,8 +462,9 @@ bool Descriptor::hasTrivialDtor() const { return !Dtor || Dtor->isTrivial(); } + if (!ElemDesc) + return true; // Composite arrays. - assert(ElemDesc); return ElemDesc->hasTrivialDtor(); } diff --git a/clang/lib/AST/ByteCode/Descriptor.h b/clang/lib/AST/ByteCode/Descriptor.h index cd34e11a67151..4a808c0a2d216 100644 --- a/clang/lib/AST/ByteCode/Descriptor.h +++ b/clang/lib/AST/ByteCode/Descriptor.h @@ -166,8 +166,6 @@ struct Descriptor final { const bool IsVolatile = false; /// Flag indicating if the block is an array. const bool IsArray = false; - /// Flag indicating if this is a dummy descriptor. - bool IsDummy = false; bool IsConstexprUnknown = false; /// Storage management methods. @@ -203,9 +201,6 @@ struct Descriptor final { /// Allocates a dummy descriptor. Descriptor(const DeclTy &D, MetadataSize MD = std::nullopt); - /// Make this descriptor a dummy descriptor. - void makeDummy() { IsDummy = true; } - QualType getType() const; QualType getElemQualType() const; QualType getDataType(const ASTContext &Ctx) const; @@ -273,8 +268,6 @@ struct Descriptor final { bool isRecord() const { return !IsArray && ElemRecord; } /// Checks if the descriptor is of a union. bool isUnion() const; - /// Checks if this is a dummy descriptor. - bool isDummy() const { return IsDummy; } /// Whether variables of this descriptor need their destructor called or not. bool hasTrivialDtor() const; diff --git a/clang/lib/AST/ByteCode/Disasm.cpp b/clang/lib/AST/ByteCode/Disasm.cpp index 5049a6545eef6..8eb785d4521a2 100644 --- a/clang/lib/AST/ByteCode/Disasm.cpp +++ b/clang/lib/AST/ByteCode/Disasm.cpp @@ -338,7 +338,7 @@ LLVM_DUMP_METHOD void Program::dump(llvm::raw_ostream &OS) const { } OS << "\n"; - if (GP.isInitialized() && Desc->isPrimitive() && !Desc->isDummy()) { + if (GP.isInitialized() && Desc->isPrimitive() && !G->block()->isDummy()) { OS << " "; { ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_CYAN, false}); @@ -394,8 +394,6 @@ LLVM_DUMP_METHOD void Descriptor::dump(llvm::raw_ostream &OS) const { else if (isUnknownSizeArray()) OS << " unknown-size-array"; - if (isDummy()) - OS << " dummy"; if (IsConstexprUnknown) OS << " constexpr-unknown"; } @@ -541,11 +539,12 @@ LLVM_DUMP_METHOD void Block::dump(llvm::raw_ostream &OS) const { else OS << "-\n"; OS << " Pointers: " << NPointers << "\n"; - OS << " Dead: " << IsDead << "\n"; + OS << " Dead: " << isDead() << "\n"; OS << " Static: " << IsStatic << "\n"; - OS << " Extern: " << IsExtern << "\n"; + OS << " Extern: " << isExtern() << "\n"; OS << " Initialized: " << IsInitialized << "\n"; - OS << " Weak: " << IsWeak << "\n"; + OS << " Weak: " << isWeak() << "\n"; + OS << " Dummy: " << isDummy() << '\n'; OS << " Dynamic: " << IsDynamic << "\n"; } diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp index 6999fee64b655..b4d51597d57d3 100644 --- a/clang/lib/AST/ByteCode/Interp.cpp +++ b/clang/lib/AST/ByteCode/Interp.cpp @@ -738,19 +738,21 @@ static bool CheckWeak(InterpState &S, CodePtr OpPC, const Block *B) { bool CheckGlobalLoad(InterpState &S, CodePtr OpPC, const Block *B) { const auto &Desc = *reinterpret_cast<const GlobalInlineDescriptor *>(B->rawData()); - if (!CheckExtern(S, OpPC, Pointer(const_cast<Block *>(B)))) - return false; + 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); + } + if (!CheckConstant(S, OpPC, B->getDescriptor())) return false; - if (!CheckDummy(S, OpPC, B, AK_Read)) - return false; if (Desc.InitState != GlobalInitState::Initialized) return DiagnoseUninitialized(S, OpPC, B->isExtern(), B->getDescriptor(), AK_Read); if (!CheckTemporary(S, OpPC, B, AK_Read)) return false; - if (!CheckWeak(S, OpPC, B)) - return false; if (B->getDescriptor()->IsVolatile) { if (!S.getLangOpts().CPlusPlus) return Invalid(S, OpPC); @@ -790,14 +792,32 @@ bool CheckLocalLoad(InterpState &S, CodePtr OpPC, const Block *B) { bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK) { - if (!CheckLive(S, OpPC, Ptr, AK)) - return false; - if (!CheckExtern(S, OpPC, Ptr)) + if (!Ptr.isBlockPointer()) { + if (Ptr.isZero()) { + const auto &Src = S.Current->getSource(OpPC); + + if (Ptr.isField()) + S.FFDiag(Src, diag::note_constexpr_null_subobject) << CSK_Field; + else + S.FFDiag(Src, diag::note_constexpr_access_null) << AK; + } return false; + } + + // Block pointers are the only ones we can actually read from. + if (!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; + if (!CheckWeak(S, OpPC, Ptr.block())) + return false; + } + if (!CheckConstant(S, OpPC, Ptr)) return false; - if (Ptr.isBlockPointer() && !CheckDummy(S, OpPC, Ptr.block(), AK)) - return false; if (!CheckRange(S, OpPC, Ptr, AK)) return false; if (!CheckActive(S, OpPC, Ptr, AK)) @@ -806,10 +826,9 @@ bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr, return false; if (!Ptr.isInitialized()) return DiagnoseUninitialized(S, OpPC, Ptr, AK); - if (Ptr.isBlockPointer() && !CheckTemporary(S, OpPC, Ptr.block(), AK)) - return false; - if (Ptr.isBlockPointer() && !CheckWeak(S, OpPC, Ptr.block())) + if (!CheckTemporary(S, OpPC, Ptr.block(), AK)) return false; + if (!CheckMutable(S, OpPC, Ptr)) return false; if (!CheckVolatile(S, OpPC, Ptr, AK)) @@ -820,15 +839,32 @@ bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr, /// This is not used by any of the opcodes directly. It's used by /// EvalEmitter to do the final lvalue-to-rvalue conversion. bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { - if (!CheckLive(S, OpPC, Ptr, AK_Read)) + if (!Ptr.isBlockPointer()) { + if (Ptr.isZero()) { + const auto &Src = S.Current->getSource(OpPC); + + if (Ptr.isField()) + S.FFDiag(Src, diag::note_constexpr_null_subobject) << CSK_Field; + else + S.FFDiag(Src, diag::note_constexpr_access_null) << AK_Read; + } return false; + } + + assert(Ptr.isBlockPointer()); + if (!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()); + } + if (!CheckConstant(S, OpPC, Ptr)) return false; - if (Ptr.isBlockPointer() && !CheckDummy(S, OpPC, Ptr.block(), AK_Read)) - return false; - if (!CheckExtern(S, OpPC, Ptr)) - return false; if (!CheckRange(S, OpPC, Ptr, AK_Read)) return false; if (!CheckActive(S, OpPC, Ptr, AK_Read)) @@ -837,9 +873,7 @@ bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { return false; if (!Ptr.isInitialized()) return DiagnoseUninitialized(S, OpPC, Ptr, AK_Read); - if (Ptr.isBlockPointer() && !CheckTemporary(S, OpPC, Ptr.block(), AK_Read)) - return false; - if (Ptr.isBlockPointer() && !CheckWeak(S, OpPC, Ptr.block())) + if (!CheckTemporary(S, OpPC, Ptr.block(), AK_Read)) return false; if (!CheckMutable(S, OpPC, Ptr)) return false; @@ -847,10 +881,14 @@ bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { } bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { - if (!CheckLive(S, OpPC, Ptr, AK_Assign)) - return false; - if (Ptr.isBlockPointer() && !CheckDummy(S, OpPC, Ptr.block(), AK_Assign)) + if (!Ptr.isBlockPointer()) return false; + + if (!Ptr.block()->isAccessible()) { + if (!CheckLive(S, OpPC, Ptr, AK_Assign)) + return false; + return CheckDummy(S, OpPC, Ptr.block(), AK_Assign); + } if (!CheckLifetime(S, OpPC, Ptr.getLifetime(), AK_Assign)) return false; if (!CheckExtern(S, OpPC, Ptr)) @@ -1126,11 +1164,10 @@ bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR) { } bool CheckDummy(InterpState &S, CodePtr OpPC, const Block *B, AccessKinds AK) { - const Descriptor *Desc = B->getDescriptor(); - if (!Desc->isDummy()) + if (!B->isDummy()) return true; - const ValueDecl *D = Desc->asValueDecl(); + const ValueDecl *D = B->getDescriptor()->asValueDecl(); if (!D) return false; @@ -1828,14 +1865,21 @@ bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, const Expr *E, if (Ptr.inUnion() && Ptr.getBase().getRecord()->isUnion()) Ptr.activate(); + if (!Ptr.isBlockPointer()) + return false; + // Similar to CheckStore(), but with the additional CheckTemporary() call and // the AccessKinds are different. + + if (!Ptr.block()->isAccessible()) { + if (!CheckExtern(S, OpPC, Ptr)) + return false; + if (!CheckLive(S, OpPC, Ptr, AK_Construct)) + return false; + return CheckDummy(S, OpPC, Ptr.block(), AK_Construct); + } if (!CheckTemporary(S, OpPC, Ptr.block(), AK_Construct)) return false; - if (!CheckLive(S, OpPC, Ptr, AK_Construct)) - return false; - if (!CheckDummy(S, OpPC, Ptr.block(), AK_Construct)) - return false; // CheckLifetime for this and all base pointers. for (Pointer P = Ptr;;) { @@ -1846,8 +1890,7 @@ bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, const Expr *E, break; P = P.getBase(); } - if (!CheckExtern(S, OpPC, Ptr)) - return false; + if (!CheckRange(S, OpPC, Ptr, AK_Construct)) return false; if (!CheckGlobal(S, OpPC, Ptr)) diff --git a/clang/lib/AST/ByteCode/InterpBlock.cpp b/clang/lib/AST/ByteCode/InterpBlock.cpp index 963b54ec50cff..db0c8e8025cc7 100644 --- a/clang/lib/AST/ByteCode/InterpBlock.cpp +++ b/clang/lib/AST/ByteCode/InterpBlock.cpp @@ -64,7 +64,7 @@ void Block::removePointer(Pointer *P) { } void Block::cleanup() { - if (Pointers == nullptr && IsDead) + if (Pointers == nullptr && isDead()) (reinterpret_cast<DeadBlock *>(this + 1) - 1)->free(); } @@ -113,8 +113,8 @@ bool Block::hasPointer(const Pointer *P) const { #endif DeadBlock::DeadBlock(DeadBlock *&Root, Block *Blk) - : Root(Root), B(~0u, Blk->Desc, Blk->IsStatic, Blk->IsExtern, Blk->IsWeak, - /*isDead=*/true) { + : Root(Root), B(~0u, Blk->Desc, Blk->isExtern(), Blk->IsStatic, + Blk->isWeak(), Blk->isDummy(), /*IsDead=*/true) { // Add the block to the chain of dead blocks. if (Root) Root->Prev = this; diff --git a/clang/lib/AST/ByteCode/InterpBlock.h b/clang/lib/AST/ByteCode/InterpBlock.h index 07194d6d1b3b2..7ded1e8649fdf 100644 --- a/clang/lib/AST/ByteCode/InterpBlock.h +++ b/clang/lib/AST/ByteCode/InterpBlock.h @@ -42,21 +42,32 @@ enum PrimType : unsigned; /// the data size and the metadata size. /// class Block final { +private: + 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: /// Creates a new block. Block(unsigned EvalID, const std::optional<unsigned> &DeclID, const Descriptor *Desc, bool IsStatic = false, bool IsExtern = false, - bool IsWeak = false) - : EvalID(EvalID), DeclID(DeclID), IsStatic(IsStatic), IsExtern(IsExtern), - IsDynamic(false), IsWeak(IsWeak), Desc(Desc) { + bool IsWeak = false, bool IsDummy = false) + : Desc(Desc), DeclID(DeclID), EvalID(EvalID), IsStatic(IsStatic) { assert(Desc); + AccessFlags |= (ExternFlag * IsExtern); + AccessFlags |= (WeakFlag * IsWeak); + AccessFlags |= (DummyFlag * IsDummy); } Block(unsigned EvalID, const Descriptor *Desc, bool IsStatic = false, - bool IsExtern = false, bool IsWeak = false) - : EvalID(EvalID), DeclID((unsigned)-1), IsStatic(IsStatic), - IsExtern(IsExtern), IsDynamic(false), IsWeak(IsWeak), Desc(Desc) { + bool IsExtern = false, bool IsWeak = false, bool IsDummy = false) + : Desc(Desc), DeclID((unsigned)-1), EvalID(EvalID), IsStatic(IsStatic), + IsDynamic(false) { assert(Desc); + AccessFlags |= (ExternFlag * IsExtern); + AccessFlags |= (WeakFlag * IsWeak); + AccessFlags |= (DummyFlag * IsDummy); } /// Returns the block's descriptor. @@ -64,13 +75,15 @@ class Block final { /// Checks if the block has any live pointers. bool hasPointers() const { return Pointers; } /// Checks if the block is extern. - bool isExtern() const { return IsExtern; } + bool isExtern() const { return AccessFlags & ExternFlag; } /// Checks if the block has static storage duration. bool isStatic() const { return IsStatic; } /// Checks if the block is temporary. bool isTemporary() const { return Desc->IsTemporary; } - bool isWeak() const { return IsWeak; } + bool isWeak() const { return AccessFlags & WeakFlag; } bool isDynamic() const { return IsDynamic; } + bool isDummy() const { return AccessFlags & DummyFlag; } + bool isDead() const { return AccessFlags & DeadFlag; } /// Returns the size of the block. unsigned getSize() const { return Desc->getAllocSize(); } /// Returns the declaration ID. @@ -130,6 +143,8 @@ class Block final { void dump() const { dump(llvm::errs()); } void dump(llvm::raw_ostream &OS) const; + bool isAccessible() const { return AccessFlags == 0; } + private: friend class Pointer; friend class DeadBlock; @@ -137,10 +152,13 @@ class Block final { friend class DynamicAllocator; Block(unsigned EvalID, const Descriptor *Desc, bool IsExtern, bool IsStatic, - bool IsWeak, bool IsDead) - : EvalID(EvalID), IsStatic(IsStatic), IsExtern(IsExtern), IsDead(true), - IsDynamic(false), IsWeak(IsWeak), Desc(Desc) { + bool IsWeak, bool IsDummy, bool IsDead) + : Desc(Desc), EvalID(EvalID), IsStatic(IsStatic) { assert(Desc); + AccessFlags |= (ExternFlag * IsExtern); + AccessFlags |= (DeadFlag * IsDead); + AccessFlags |= (WeakFlag * IsWeak); + AccessFlags |= (DummyFlag * IsDummy); } /// Deletes a dead block at the end of its lifetime. @@ -154,27 +172,23 @@ class Block final { bool hasPointer(const Pointer *P) const; #endif - const unsigned EvalID = ~0u; + /// Pointer to the stack slot descriptor. + const Descriptor *Desc; /// Start of the chain of pointers. Pointer *Pointers = nullptr; /// Unique identifier of the declaration. std::optional<unsigned> DeclID; + const unsigned EvalID = ~0u; /// Flag indicating if the block has static storage duration. bool IsStatic = false; - /// Flag indicating if the block is an extern. - bool IsExtern = false; - /// Flag indicating if the pointer is dead. This is only ever - /// set once, when converting the Block to a DeadBlock. - bool IsDead = false; /// Flag indicating if the block contents have been initialized /// via invokeCtor. bool IsInitialized = false; /// Flag indicating if this block has been allocated via dynamic /// memory allocation (e.g. malloc). bool IsDynamic = false; - bool IsWeak = false; - /// Pointer to the stack slot descriptor. - const Descriptor *Desc; + /// AccessFlags containing IsExtern, IsDead, IsWeak, and IsDummy bits. + uint8_t AccessFlags = 0; }; /// Descriptor for a dead block. diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp index c835bd4fb6088..4f1d83fb460f0 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp @@ -1785,6 +1785,13 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC, return false; QualType DestElemType = getElemType(DestPtr); + if (DestElemType->isIncompleteType()) { + S.FFDiag(S.Current->getSource(OpPC), + diag::note_constexpr_ltor_incomplete_type) + << DestElemType; + return false; + } + size_t RemainingDestElems; if (DestPtr.getFieldDesc()->isArray()) { RemainingDestElems = DestPtr.isUnknownSizeArray() diff --git a/clang/lib/AST/ByteCode/InterpState.cpp b/clang/lib/AST/ByteCode/InterpState.cpp index b3c0a67f8ff3e..8a1ca889be3af 100644 --- a/clang/lib/AST/ByteCode/InterpState.cpp +++ b/clang/lib/AST/ByteCode/InterpState.cpp @@ -76,6 +76,9 @@ bool InterpState::reportOverflow(const Expr *E, const llvm::APSInt &Value) { void InterpState::deallocate(Block *B) { assert(B); + assert(!B->isStatic()); + assert(!B->isDead()); + // The block might have a pointer saved in a field in its data // that points to the block itself. We call the dtor first, // which will destroy all the data but leave InlineDescriptors @@ -92,7 +95,7 @@ void InterpState::deallocate(Block *B) { auto *D = new (Memory) DeadBlock(DeadBlocks, B); // Since the block doesn't hold any actual data anymore, we can just // memcpy() everything over. - std::memcpy(D->rawData(), B->rawData(), B->getSize()); + std::memcpy(D->rawData(), B->rawData(), Size); D->B.IsInitialized = B->IsInitialized; // We moved the contents over to the DeadBlock. diff --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h index 5bafc5b108ee9..94c83a0d87bc4 100644 --- a/clang/lib/AST/ByteCode/Pointer.h +++ b/clang/lib/AST/ByteCode/Pointer.h @@ -282,7 +282,7 @@ class Pointer { bool isLive() const { if (!isBlockPointer()) return true; - return asBlockPointer().Pointee && !asBlockPointer().Pointee->IsDead; + return asBlockPointer().Pointee && !asBlockPointer().Pointee->isDead(); } /// Checks if the item is a field in an object. bool isField() const { @@ -568,10 +568,9 @@ class Pointer { if (!isBlockPointer()) return false; - if (!asBlockPointer().Pointee) - return false; - - return getDeclDesc()->isDummy(); + if (const Block *Pointee = asBlockPointer().Pointee) + return Pointee->isDummy(); + return false; } /// Checks if an object or a subfield is mutable. diff --git a/clang/lib/AST/ByteCode/Program.cpp b/clang/lib/AST/ByteCode/Program.cpp index 4daa4ab0d02f9..abc608494020b 100644 --- a/clang/lib/AST/ByteCode/Program.cpp +++ b/clang/lib/AST/ByteCode/Program.cpp @@ -180,17 +180,15 @@ unsigned Program::getOrCreateDummy(const DeclTy &D) { Desc = allocateDescriptor(D); assert(Desc); - Desc->makeDummy(); - - assert(Desc->isDummy()); // Allocate a block for storage. unsigned I = Globals.size(); auto *G = new (Allocator, Desc->getAllocSize()) Global(Ctx.getEvalID(), getCurrentDecl(), Desc, /*IsStatic=*/true, - /*IsExtern=*/false, IsWeak); + ... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/152590 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits