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

Reply via email to