Author: Timm Baeder Date: 2026-02-25T07:46:12+01:00 New Revision: fc1cba892ffa22e27b1d49204781e84354d0e8bf
URL: https://github.com/llvm/llvm-project/commit/fc1cba892ffa22e27b1d49204781e84354d0e8bf DIFF: https://github.com/llvm/llvm-project/commit/fc1cba892ffa22e27b1d49204781e84354d0e8bf.diff LOG: [clang][bytecode] Copy EvalID into InterpState (#182913) So the EvalID there is independent of changes to the one in the Context. This is currently an NFC change but will make future commits easier. Added: Modified: clang/lib/AST/ByteCode/Compiler.cpp clang/lib/AST/ByteCode/Context.h clang/lib/AST/ByteCode/Interp.cpp clang/lib/AST/ByteCode/Interp.h clang/lib/AST/ByteCode/InterpState.cpp clang/lib/AST/ByteCode/InterpState.h Removed: ################################################################################ diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index 15e65a4d96581..9727d95c00119 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -7332,9 +7332,12 @@ bool Compiler<Emitter>::visitDeclRef(const ValueDecl *D, const Expr *E) { // evaluate the initializer. if (VD->isLocalVarDecl() && typeShouldBeVisited(VD->getType()) && VD->getInit() && !VD->getInit()->isValueDependent()) { - - if (VD->evaluateValue()) + if (VD->evaluateValue()) { + // Revisit the variable declaration, but make sure it's associated with a + // diff erent evaluation, so e.g. mutable reads don't work on it. + EvalIDScope _(Ctx); return revisit(VD); + } if (!IsReference) return this->emitDummyPtr(D, E); diff --git a/clang/lib/AST/ByteCode/Context.h b/clang/lib/AST/ByteCode/Context.h index 53afafdb49c0d..1b8c25732a262 100644 --- a/clang/lib/AST/ByteCode/Context.h +++ b/clang/lib/AST/ByteCode/Context.h @@ -37,6 +37,7 @@ struct ParamOffset { bool IsPtr; }; +class EvalIDScope; /// Holds all information required to evaluate constexpr code in a module. class Context final { public: @@ -167,6 +168,7 @@ class Context final { static bool isUnevaluatedBuiltin(unsigned ID); private: + friend class EvalIDScope; /// Runs a function. bool Run(State &Parent, const Function *Func); @@ -189,6 +191,16 @@ class Context final { unsigned LongLongWidth; }; +class EvalIDScope { +public: + EvalIDScope(Context &Ctx) : Ctx(Ctx), OldID(Ctx.EvalID) { ++Ctx.EvalID; } + ~EvalIDScope() { Ctx.EvalID = OldID; } + +private: + Context &Ctx; + const unsigned OldID; +}; + } // namespace interp } // namespace clang diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp index bb259822c3dfe..ebc7220aa5671 100644 --- a/clang/lib/AST/ByteCode/Interp.cpp +++ b/clang/lib/AST/ByteCode/Interp.cpp @@ -230,7 +230,7 @@ static bool CheckTemporary(InterpState &S, CodePtr OpPC, const Block *B, // 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 (B->getEvalID() != S.Ctx.getEvalID() && + if (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; @@ -626,16 +626,8 @@ bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { // In C++14 onwards, it is permitted to read a mutable member whose // lifetime began within the evaluation. - if (S.getLangOpts().CPlusPlus14 && - Ptr.block()->getEvalID() == S.Ctx.getEvalID()) { - // FIXME: This check is necessary because (of the way) we revisit - // variables in Compiler.cpp:visitDeclRef. Revisiting a so far - // unknown variable will get the same EvalID and we end up allowing - // reads from mutable members of it. - if (!S.inConstantContext() && isConstexprUnknown(Ptr)) - return false; + if (S.getLangOpts().CPlusPlus14 && Ptr.block()->getEvalID() == S.EvalID) return true; - } const SourceInfo &Loc = S.Current->getSource(OpPC); const FieldDecl *Field = Ptr.getField(); diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h index db9514486aa6b..7f30def20cc36 100644 --- a/clang/lib/AST/ByteCode/Interp.h +++ b/clang/lib/AST/ByteCode/Interp.h @@ -3486,8 +3486,8 @@ inline bool Alloc(InterpState &S, CodePtr OpPC, const Descriptor *Desc) { return false; DynamicAllocator &Allocator = S.getAllocator(); - Block *B = Allocator.allocate(Desc, S.Ctx.getEvalID(), - DynamicAllocator::Form::NonArray); + Block *B = + Allocator.allocate(Desc, S.EvalID, DynamicAllocator::Form::NonArray); assert(B); S.Stk.push<Pointer>(B); return true; @@ -3522,9 +3522,8 @@ inline bool AllocN(InterpState &S, CodePtr OpPC, PrimType T, const Expr *Source, return false; DynamicAllocator &Allocator = S.getAllocator(); - Block *B = - Allocator.allocate(Source, T, static_cast<size_t>(NumElements), - S.Ctx.getEvalID(), DynamicAllocator::Form::Array); + Block *B = Allocator.allocate(Source, T, static_cast<size_t>(NumElements), + S.EvalID, DynamicAllocator::Form::Array); assert(B); if (NumElements.isZero()) S.Stk.push<Pointer>(B); @@ -3558,9 +3557,8 @@ inline bool AllocCN(InterpState &S, CodePtr OpPC, const Descriptor *ElementDesc, return false; DynamicAllocator &Allocator = S.getAllocator(); - Block *B = - Allocator.allocate(ElementDesc, static_cast<size_t>(NumElements), - S.Ctx.getEvalID(), DynamicAllocator::Form::Array); + Block *B = Allocator.allocate(ElementDesc, static_cast<size_t>(NumElements), + S.EvalID, DynamicAllocator::Form::Array); assert(B); if (NumElements.isZero()) S.Stk.push<Pointer>(B); diff --git a/clang/lib/AST/ByteCode/InterpState.cpp b/clang/lib/AST/ByteCode/InterpState.cpp index df507bd5507c3..fd69559af5917 100644 --- a/clang/lib/AST/ByteCode/InterpState.cpp +++ b/clang/lib/AST/ByteCode/InterpState.cpp @@ -22,7 +22,7 @@ InterpState::InterpState(const State &Parent, Program &P, InterpStack &Stk, : State(Ctx.getASTContext(), Parent.getEvalStatus()), M(M), P(P), Stk(Stk), Ctx(Ctx), BottomFrame(*this), Current(&BottomFrame), StepsLeft(Ctx.getLangOpts().ConstexprStepLimit), - InfiniteSteps(StepsLeft == 0) { + InfiniteSteps(StepsLeft == 0), EvalID(Ctx.getEvalID()) { InConstantContext = Parent.InConstantContext; CheckingPotentialConstantExpression = Parent.CheckingPotentialConstantExpression; @@ -36,7 +36,7 @@ InterpState::InterpState(const State &Parent, Program &P, InterpStack &Stk, Stk(Stk), Ctx(Ctx), BottomFrame(*this, Func, nullptr, CodePtr(), Func->getArgSize()), Current(&BottomFrame), StepsLeft(Ctx.getLangOpts().ConstexprStepLimit), - InfiniteSteps(StepsLeft == 0) { + InfiniteSteps(StepsLeft == 0), EvalID(Ctx.getEvalID()) { InConstantContext = Parent.InConstantContext; CheckingPotentialConstantExpression = Parent.CheckingPotentialConstantExpression; diff --git a/clang/lib/AST/ByteCode/InterpState.h b/clang/lib/AST/ByteCode/InterpState.h index 4306f8194647d..8ed92432f1c7e 100644 --- a/clang/lib/AST/ByteCode/InterpState.h +++ b/clang/lib/AST/ByteCode/InterpState.h @@ -159,6 +159,8 @@ class InterpState final : public State, public SourceMapper { /// Whether infinite evaluation steps have been requested. If this is false, /// we use the StepsLeft value above. const bool InfiniteSteps = false; + /// ID identifying this evaluation. + const unsigned EvalID; /// Things needed to do speculative execution. SmallVectorImpl<PartialDiagnosticAt> *PrevDiags = nullptr; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
