Author: Timm Baeder Date: 2026-11-03T14:06:19+01:00 New Revision: 0224aac7e79571993dfbf565c1ba77bf762a17d2
URL: https://github.com/llvm/llvm-project/commit/0224aac7e79571993dfbf565c1ba77bf762a17d2 DIFF: https://github.com/llvm/llvm-project/commit/0224aac7e79571993dfbf565c1ba77bf762a17d2.diff LOG: [clang][bytecode] Clean up ConstexprUnknown handling (#238281) Move the `IsConstexprUnknown` flag to `interp::Block`. This makes it part of `Block::isAccessible()`. Added: Modified: clang/lib/AST/ByteCode/Block.h clang/lib/AST/ByteCode/ByteCodeEmitter.cpp clang/lib/AST/ByteCode/ByteCodeEmitter.h clang/lib/AST/ByteCode/Compiler.cpp clang/lib/AST/ByteCode/Descriptor.h clang/lib/AST/ByteCode/Disasm.cpp clang/lib/AST/ByteCode/EvalEmitter.cpp clang/lib/AST/ByteCode/EvalEmitter.h clang/lib/AST/ByteCode/Interp.cpp clang/lib/AST/ByteCode/Interp.h clang/lib/AST/ByteCode/Pointer.h clang/lib/AST/ByteCode/Program.cpp clang/lib/AST/ByteCode/Program.h Removed: ################################################################################ diff --git a/clang/lib/AST/ByteCode/Block.h b/clang/lib/AST/ByteCode/Block.h index afdf726e8be26..25514ac126807 100644 --- a/clang/lib/AST/ByteCode/Block.h +++ b/clang/lib/AST/ByteCode/Block.h @@ -28,6 +28,7 @@ struct BlockFlags { static constexpr uint8_t Extern = 1u << 0u; static constexpr uint8_t Dead = 1u << 1u; static constexpr uint8_t Weak = 1u << 2u; + static constexpr uint8_t ConstexprUnknown = 1u << 3u; uint8_t V = 0; constexpr BlockFlags(uint8_t V = 0) : V(V) {} @@ -42,6 +43,9 @@ struct BlockFlags { constexpr BlockFlags withWeak(bool B = true) const { return BlockFlags(V | (B * Weak)); } + constexpr BlockFlags withConstexprUnknown(bool B = true) const { + return BlockFlags(V | (B * ConstexprUnknown)); + } }; /// A memory block, either on the stack or in the heap. @@ -111,6 +115,9 @@ class Block final { return Result; } bool isDead() const { return Flags.V & BlockFlags::Dead; } + bool isConstexprUnknown() const { + return Flags.V & BlockFlags::ConstexprUnknown; + } bool isAccessible() const { return Flags.V == 0; } /// Returns the size of the block, excluding metadata. unsigned getSize() const { return DescSize; } diff --git a/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp b/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp index 0e1544baa97de..fb7b6919c8528 100644 --- a/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp +++ b/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp @@ -88,7 +88,7 @@ void ByteCodeEmitter::compileFunc(const FunctionDecl *FuncDecl, Func->setIsFullyCompiled(true); } -Scope::Local ByteCodeEmitter::createLocal(const Descriptor *D) { +Scope::Local ByteCodeEmitter::createLocal(const Descriptor *D, bool) { NextLocalOffset += sizeof(Block); unsigned Location = NextLocalOffset; assert(aligned(Block::getMetadataSize(Block::Local) + D->getAllocSize())); diff --git a/clang/lib/AST/ByteCode/ByteCodeEmitter.h b/clang/lib/AST/ByteCode/ByteCodeEmitter.h index 4174a26b80464..f76da92553308 100644 --- a/clang/lib/AST/ByteCode/ByteCodeEmitter.h +++ b/clang/lib/AST/ByteCode/ByteCodeEmitter.h @@ -71,7 +71,7 @@ class ByteCodeEmitter { bool constantFolding() const { return false; } /// Callback for local registration. - Local createLocal(const Descriptor *D); + Local createLocal(const Descriptor *D, bool IsConstexprUnknown = false); /// Parameter indices. llvm::DenseMap<const ParmVarDecl *, FuncParam> Params; diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index 12647df7bb5b9..e3232d943ee4d 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -5474,8 +5474,7 @@ unsigned Compiler<Emitter>::allocateLocalPrimitive(DeclOrExpr Src, PrimType Ty, // or isa<MaterializeTemporaryExpr>(). Descriptor *D = P.createDescriptor(Src, Ty, nullptr, IsConst, Src.isExpr(), /*IsMutable=*/false, IsVolatile); - D->IsConstexprUnknown = this->VariablesAreConstexprUnknown; - Scope::Local Local = this->createLocal(D); + Scope::Local Local = this->createLocal(D, this->VariablesAreConstexprUnknown); if (auto *VD = Src.asValueDecl()) Locals.insert({VD, Local}); VarScope->addForScopeKind(Local, SC); @@ -5505,9 +5504,8 @@ UnsignedOrNone Compiler<Emitter>::allocateLocal(DeclOrExpr Src, QualType Ty, /*IsMutable=*/false, /*IsVolatile=*/Ty.isVolatileQualified(), Init); if (!D) return std::nullopt; - D->IsConstexprUnknown = this->VariablesAreConstexprUnknown; - Scope::Local Local = this->createLocal(D); + Scope::Local Local = this->createLocal(D, this->VariablesAreConstexprUnknown); if (Key) Locals.insert({Key, Local}); VarScope->addForScopeKind(Local, SC); @@ -6278,7 +6276,9 @@ bool Compiler<Emitter>::registerRedecl(const VarDecl *VD, const APValue &Val) { if (P.getGlobal(VD)) return true; - UnsignedOrNone GlobalIndex = P.createGlobal(VD, /*Init=*/nullptr); + UnsignedOrNone GlobalIndex = + P.createGlobal(VD, /*Init=*/nullptr, /*IsConstexprUnknown=*/false, + /*CanBeExtern=*/false); if (!GlobalIndex) { llvm_unreachable("Why didn't that work?"); } diff --git a/clang/lib/AST/ByteCode/Descriptor.h b/clang/lib/AST/ByteCode/Descriptor.h index 7af548df7c481..d344f68ef318e 100644 --- a/clang/lib/AST/ByteCode/Descriptor.h +++ b/clang/lib/AST/ByteCode/Descriptor.h @@ -158,7 +158,6 @@ struct Descriptor final { const bool IsVolatile = false; /// Flag indicating if the block is an array. const bool IsArray = false; - bool IsConstexprUnknown = false; /// Storage management methods. const BlockCtorFn CtorFn = nullptr; diff --git a/clang/lib/AST/ByteCode/Disasm.cpp b/clang/lib/AST/ByteCode/Disasm.cpp index af115e8bdc0b0..db5c116d8b3c8 100644 --- a/clang/lib/AST/ByteCode/Disasm.cpp +++ b/clang/lib/AST/ByteCode/Disasm.cpp @@ -456,9 +456,6 @@ LLVM_DUMP_METHOD void Descriptor::dump(llvm::raw_ostream &OS) const { OS << " zero-size-array"; else if (isUnknownSizeArray()) OS << " unknown-size-array"; - - if (IsConstexprUnknown) - OS << " constexpr-unknown"; } /// Dump descriptor, including all valid offsets. diff --git a/clang/lib/AST/ByteCode/EvalEmitter.cpp b/clang/lib/AST/ByteCode/EvalEmitter.cpp index 6a18c8cfee71e..d3d0b9677bc96 100644 --- a/clang/lib/AST/ByteCode/EvalEmitter.cpp +++ b/clang/lib/AST/ByteCode/EvalEmitter.cpp @@ -147,11 +147,14 @@ void EvalEmitter::emitLabel(LabelTy Label) { CurrentLabel = Label; } EvalEmitter::LabelTy EvalEmitter::getLabel() { return NextLabel++; } -Scope::Local EvalEmitter::createLocal(const Descriptor *D) { +Scope::Local EvalEmitter::createLocal(const Descriptor *D, + bool IsConstexprUnknown) { + + BlockFlags Flags = BlockFlags().withConstexprUnknown(IsConstexprUnknown); // Allocate memory for a local. char *Memory = reinterpret_cast<char *>(S.allocate(Block::allocSize(D, Block::Local))); - auto *B = new (Memory) Block(Ctx.getEvalID(), D, Block::Local); + auto *B = new (Memory) Block(Ctx.getEvalID(), D, Block::Local, Flags); B->invokeCtor(); // Initialize local variable inline descriptor. @@ -301,7 +304,7 @@ template <> bool EvalEmitter::emitRet<PT_Ptr>(SourceInfo Info) { ((DeclDesc->asVarDecl() == S.EvaluatingDecl && S.getLangOpts().CPlusPlus23 && S.EvaluatingDecl->getType()->isReferenceType()) || - DeclDesc->IsConstexprUnknown)) { + Ptr.isConstexprUnknown())) { S.FFDiag(Info, diag::note_constexpr_var_init_non_constant, 1) << DeclDesc->asVarDecl(); S.Note(DeclDesc->asVarDecl()->getLocation(), diag::note_declared_at); diff --git a/clang/lib/AST/ByteCode/EvalEmitter.h b/clang/lib/AST/ByteCode/EvalEmitter.h index 2f9507c04628c..023b1d6d1fdb5 100644 --- a/clang/lib/AST/ByteCode/EvalEmitter.h +++ b/clang/lib/AST/ByteCode/EvalEmitter.h @@ -112,7 +112,7 @@ class EvalEmitter : public SourceMapper { } /// Callback for registering a local. - Local createLocal(const Descriptor *D); + Local createLocal(const Descriptor *D, bool IsConstexprUnknown = false); /// Parameter indices. llvm::DenseMap<const ParmVarDecl *, FuncParam> Params; diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp index b759897b83f96..5caede7d1a149 100644 --- a/clang/lib/AST/ByteCode/Interp.cpp +++ b/clang/lib/AST/ByteCode/Interp.cpp @@ -339,16 +339,6 @@ void cleanupAfterFunctionCall(InterpState &S, const Function *Func) { S.Stk.discard<Pointer>(); } -bool isConstexprUnknown(const Block *B) { - return B->getDescriptor()->IsConstexprUnknown; -} - -bool isConstexprUnknown(const Pointer &P) { - if (!P.isBlockPointer() || P.isZero()) - return false; - return isConstexprUnknown(P.block()); -} - bool CheckBCPResult(InterpState &S, const Pointer &Ptr) { if (Ptr.isDummy()) return false; @@ -874,7 +864,9 @@ bool CheckGlobalLoad(InterpState &S, CodePtr OpPC, const Block *B) { if (!B->isAccessible()) { if (!CheckExtern(S, OpPC, B)) return false; - return CheckWeak(S, OpPC, B); + if (!CheckWeak(S, OpPC, B)) + return false; + return false; } if (!CheckConstant(S, OpPC, B->getDescriptor())) @@ -956,7 +948,9 @@ bool CheckLoad(InterpState &S, CodePtr OpPC, PtrView Ptr, AccessKinds AK) { } if (!CheckExtern(S, OpPC, Ptr.block())) return false; - return CheckWeak(S, OpPC, Ptr.block()); + if (!CheckWeak(S, OpPC, Ptr.block())) + return false; + return false; } if (!CheckConstant(S, OpPC, Ptr, AK)) @@ -977,8 +971,6 @@ bool CheckLoad(InterpState &S, CodePtr OpPC, PtrView Ptr, AccessKinds AK) { return false; if (!CheckVolatile(S, OpPC, Ptr, AK)) return false; - if (isConstexprUnknown(Ptr.block())) - return false; if (!Ptr.isArrayRoot()) { // According to GCC info page: @@ -1051,7 +1043,9 @@ bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { return false; if (!CheckExtern(S, OpPC, Ptr)) return false; - return CheckWeak(S, OpPC, Ptr.block()); + if (!CheckWeak(S, OpPC, Ptr.block())) + return false; + return false; } if (Ptr.isPastEnd()) @@ -1073,8 +1067,6 @@ bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { if (!CheckMutable(S, OpPC, Ptr.view())) return false; } - if (!S.inConstantContext() && isConstexprUnknown(Ptr)) - return false; return true; } @@ -1092,7 +1084,9 @@ bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr, if (!Ptr.block()->isAccessible()) { if (!CheckLive(S, OpPC, Ptr, AK)) return false; - return CheckExtern(S, OpPC, Ptr); + if (!CheckExtern(S, OpPC, Ptr)) + return false; + return false; } if (!WillBeActivated && !CheckLifetime(S, OpPC, Ptr, AK)) return false; @@ -1108,14 +1102,12 @@ bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr, return false; if (!CheckMutable(S, OpPC, Ptr.view(), AK)) return false; - if (isConstexprUnknown(Ptr)) - return false; return true; } static bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr, bool IsCtor, bool IsDtor) { - if (!Ptr.isDummy() && !isConstexprUnknown(Ptr)) { + if (!Ptr.isDummy() && !Ptr.isConstexprUnknown()) { if (!CheckLive(S, OpPC, Ptr, AK_MemberCall)) return false; if (!CheckRange(S, OpPC, Ptr, AK_MemberCall)) @@ -2881,8 +2873,6 @@ bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, const Expr *E, return false; if (!CheckConst(S, OpPC, Ptr)) return false; - if (!S.inConstantContext() && isConstexprUnknown(Ptr)) - return false; const auto *NewExpr = cast<CXXNewExpr>(E); const ASTContext &ASTCtx = S.getASTContext(); @@ -3066,7 +3056,7 @@ bool CheckBitCast(InterpState &S, CodePtr OpPC, bool HasIndeterminateBits, } bool handleReference(InterpState &S, CodePtr OpPC, Block *B) { - if (isConstexprUnknown(B)) { + if (B->isConstexprUnknown()) { S.Stk.push<Pointer>(B); return true; } diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h index 5c02dedcce920..b96b50fe9e69f 100644 --- a/clang/lib/AST/ByteCode/Interp.h +++ b/clang/lib/AST/ByteCode/Interp.h @@ -133,8 +133,6 @@ bool handleFixedPointOverflow(InterpState &S, CodePtr OpPC, const FixedPoint &FP); bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I); -bool isConstexprUnknown(const Pointer &P); -bool isConstexprUnknown(const Block *B); bool DynamicCast(InterpState &S, CodePtr OpPC, const Type *DestType, bool IsReferenceCast); bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth, @@ -886,11 +884,6 @@ bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr, bool CanOverflow, UnsignedOrNone BitWidth = std::nullopt) { assert(!Ptr.isDummy()); - if (!S.inConstantContext()) { - if (isConstexprUnknown(Ptr)) - return false; - } - if constexpr (std::is_same_v<T, Boolean>) { if (!S.getLangOpts().CPlusPlus14) return Invalid(S, OpPC); @@ -1321,7 +1314,7 @@ inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) { assert(!RHS.isZero()); if (!S.inConstantContext()) { - if (isConstexprUnknown(LHS) || isConstexprUnknown(RHS)) + if (LHS.isConstexprUnknown() || RHS.isConstexprUnknown()) return false; } @@ -2054,7 +2047,7 @@ inline bool GetRefGlobal(InterpState &S, CodePtr OpPC, uint32_t I) { return true; } - if (isConstexprUnknown(B)) { + if (B->isConstexprUnknown()) { S.Stk.push<Pointer>(B); return true; } diff --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h index 35f1339be6b40..3e923a9c1a4c9 100644 --- a/clang/lib/AST/ByteCode/Pointer.h +++ b/clang/lib/AST/ByteCode/Pointer.h @@ -1198,7 +1198,7 @@ class Pointer { if (isOpaquePointer()) return Opaque.isConstexprUnknown(); if (isBlockPointer()) - return getDeclDesc()->IsConstexprUnknown; + return block()->isConstexprUnknown(); return false; } diff --git a/clang/lib/AST/ByteCode/Program.cpp b/clang/lib/AST/ByteCode/Program.cpp index 4f7daf450b5ff..de4314b405283 100644 --- a/clang/lib/AST/ByteCode/Program.cpp +++ b/clang/lib/AST/ByteCode/Program.cpp @@ -10,7 +10,6 @@ #include "Context.h" #include "Function.h" #include "PrimType.h" -#include "Reflect.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclTemplate.h" @@ -80,11 +79,12 @@ UnsignedOrNone Program::getOrCreateGlobal(const ValueDecl *VD, } UnsignedOrNone Program::createGlobal(const ValueDecl *VD, const Expr *Init, - bool IsConstexprUnknown) { + bool IsConstexprUnknown, + bool CanBeExtern) { bool IsExtern; bool IsWeak = VD->isWeak(); if (const auto *Var = dyn_cast<VarDecl>(VD)) { - IsExtern = Var->hasExternalStorage(); + IsExtern = CanBeExtern && !Init && Var->hasExternalStorage(); } else { assert((isa<UnnamedGlobalConstantDecl, MSGuidDecl, TemplateParamObjectDecl>( VD))); @@ -163,12 +163,13 @@ UnsignedOrNone Program::createGlobal(DeclOrExpr D, QualType Ty, bool IsExtern, if (!Desc) return std::nullopt; - Desc->IsConstexprUnknown = IsConstexprUnknown; // Allocate a block for storage. unsigned I = Globals.size(); - BlockFlags Flags = BlockFlags().withExtern(IsExtern).withWeak(IsWeak); + BlockFlags Flags = + BlockFlags().withExtern(IsExtern).withWeak(IsWeak).withConstexprUnknown( + IsConstexprUnknown); auto *G = new (Allocator, Desc->getAllocSize() + Block::getMetadataSize(Block::Global)) Global(Ctx.getEvalID(), getCurrentDecl(), Desc, Block::Global, Flags); diff --git a/clang/lib/AST/ByteCode/Program.h b/clang/lib/AST/ByteCode/Program.h index 3cae337a6bc76..82f22579d45fe 100644 --- a/clang/lib/AST/ByteCode/Program.h +++ b/clang/lib/AST/ByteCode/Program.h @@ -84,7 +84,8 @@ class Program final { /// Creates a global and returns its index. UnsignedOrNone createGlobal(const ValueDecl *VD, const Expr *Init, - bool IsConstexprUnknown = false); + bool IsConstexprUnknown = false, + bool CanBeExtern = true); /// Creates a global from a lifetime-extended temporary. UnsignedOrNone createGlobal(const Expr *E, QualType ExprType); _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
