Timm =?utf-8?q?Bäder?= <[email protected]>,
Timm =?utf-8?q?Bäder?= <[email protected]>,
Timm =?utf-8?q?Bäder?= <[email protected]>,
Timm =?utf-8?q?Bäder?= <[email protected]>,
Timm =?utf-8?q?Bäder?= <[email protected]>
Message-ID:
In-Reply-To: <llvm.org/llvm/llvm-project/pull/[email protected]>


https://github.com/tbaederr updated 
https://github.com/llvm/llvm-project/pull/177738

>From 42ade200f59b30249cb160d10da80dcfe3a0f5ce Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <[email protected]>
Date: Fri, 23 Jan 2026 14:29:38 +0100
Subject: [PATCH 1/6] State

---
 clang/lib/AST/ByteCode/InterpState.cpp |   7 +-
 clang/lib/AST/ByteCode/InterpState.h   |  28 +-----
 clang/lib/AST/ByteCode/State.cpp       |  57 ++++++++++-
 clang/lib/AST/ByteCode/State.h         |  76 +++++++++++---
 clang/lib/AST/ExprConstant.cpp         | 133 ++-----------------------
 5 files changed, 133 insertions(+), 168 deletions(-)

diff --git a/clang/lib/AST/ByteCode/InterpState.cpp 
b/clang/lib/AST/ByteCode/InterpState.cpp
index a95916cd63981..510606c84af13 100644
--- a/clang/lib/AST/ByteCode/InterpState.cpp
+++ b/clang/lib/AST/ByteCode/InterpState.cpp
@@ -19,8 +19,8 @@ using namespace clang::interp;
 
 InterpState::InterpState(State &Parent, Program &P, InterpStack &Stk,
                          Context &Ctx, SourceMapper *M)
-    : Parent(Parent), M(M), P(P), Stk(Stk), Ctx(Ctx), BottomFrame(*this),
-      Current(&BottomFrame) {
+    : State(Ctx.getASTContext(), Parent.getEvalStatus()), M(M), P(P), Stk(Stk),
+      Ctx(Ctx), BottomFrame(*this), Current(&BottomFrame) {
   InConstantContext = Parent.InConstantContext;
   CheckingPotentialConstantExpression =
       Parent.CheckingPotentialConstantExpression;
@@ -30,7 +30,8 @@ InterpState::InterpState(State &Parent, Program &P, 
InterpStack &Stk,
 
 InterpState::InterpState(State &Parent, Program &P, InterpStack &Stk,
                          Context &Ctx, const Function *Func)
-    : Parent(Parent), M(nullptr), P(P), Stk(Stk), Ctx(Ctx),
+    : State(Ctx.getASTContext(), Parent.getEvalStatus()), M(nullptr), P(P),
+      Stk(Stk), Ctx(Ctx),
       BottomFrame(*this, Func, nullptr, CodePtr(), Func->getArgSize()),
       Current(&BottomFrame) {
   InConstantContext = Parent.InConstantContext;
diff --git a/clang/lib/AST/ByteCode/InterpState.h 
b/clang/lib/AST/ByteCode/InterpState.h
index e2e4d5c985f93..5c620c0b8a775 100644
--- a/clang/lib/AST/ByteCode/InterpState.h
+++ b/clang/lib/AST/ByteCode/InterpState.h
@@ -63,35 +63,13 @@ class InterpState final : public State, public SourceMapper 
{
   }
   const Frame *getBottomFrame() const override { return &BottomFrame; }
 
-  // Access objects from the walker context.
-  Expr::EvalStatus &getEvalStatus() const override {
-    return Parent.getEvalStatus();
-  }
-  ASTContext &getASTContext() const override { return Ctx.getASTContext(); }
   const LangOptions &getLangOpts() const {
     return Ctx.getASTContext().getLangOpts();
   }
+  ASTContext &getASTContext() { return Ctx.getASTContext(); }
 
-  // Forward status checks and updates to the walker.
-  bool keepEvaluatingAfterFailure() const override {
-    return Parent.keepEvaluatingAfterFailure();
-  }
-  bool keepEvaluatingAfterSideEffect() const override {
-    return Parent.keepEvaluatingAfterSideEffect();
-  }
-  bool noteUndefinedBehavior() override {
-    return Parent.noteUndefinedBehavior();
-  }
+  bool stepsLeft() const override { return true; }
   bool inConstantContext() const;
-  bool hasActiveDiagnostic() override { return Parent.hasActiveDiagnostic(); }
-  void setActiveDiagnostic(bool Flag) override {
-    Parent.setActiveDiagnostic(Flag);
-  }
-  void setFoldFailureDiagnostic(bool Flag) override {
-    Parent.setFoldFailureDiagnostic(Flag);
-  }
-  bool hasPriorDiagnostic() override { return Parent.hasPriorDiagnostic(); }
-  bool noteSideEffect() override { return Parent.noteSideEffect(); }
 
   /// Deallocates a pointer.
   void deallocate(Block *B);
@@ -156,8 +134,6 @@ class InterpState final : public State, public SourceMapper 
{
 private:
   friend class EvaluationResult;
   friend class InterpStateCCOverride;
-  /// AST Walker state.
-  State &Parent;
   /// Dead block chain.
   DeadBlock *DeadBlocks = nullptr;
   /// Reference to the offset-source mapping.
diff --git a/clang/lib/AST/ByteCode/State.cpp b/clang/lib/AST/ByteCode/State.cpp
index 323231fbf8236..8958aa547b90f 100644
--- a/clang/lib/AST/ByteCode/State.cpp
+++ b/clang/lib/AST/ByteCode/State.cpp
@@ -72,12 +72,12 @@ void State::addNotes(ArrayRef<PartialDiagnosticAt> Diags) {
 }
 
 DiagnosticBuilder State::report(SourceLocation Loc, diag::kind DiagId) {
-  return getASTContext().getDiagnostics().Report(Loc, DiagId);
+  return Ctx.getDiagnostics().Report(Loc, DiagId);
 }
 
 /// Add a diagnostic to the diagnostics list.
 PartialDiagnostic &State::addDiag(SourceLocation Loc, diag::kind DiagId) {
-  PartialDiagnostic PD(DiagId, getASTContext().getDiagAllocator());
+  PartialDiagnostic PD(DiagId, Ctx.getDiagAllocator());
   getEvalStatus().Diag->push_back(std::make_pair(Loc, PD));
   return getEvalStatus().Diag->back().second;
 }
@@ -91,8 +91,7 @@ OptionalDiagnostic State::diag(SourceLocation Loc, diag::kind 
DiagId,
     }
 
     unsigned CallStackNotes = getCallStackDepth() - 1;
-    unsigned Limit =
-        getASTContext().getDiagnostics().getConstexprBacktraceLimit();
+    unsigned Limit = Ctx.getDiagnostics().getConstexprBacktraceLimit();
     if (Limit)
       CallStackNotes = std::min(CallStackNotes, Limit + 1);
     if (checkingPotentialConstantExpression())
@@ -158,3 +157,53 @@ void State::addCallStack(unsigned Limit) {
           << Out.str() << CallRange;
   }
 }
+
+bool State::hasPriorDiagnostic() {
+  if (!getEvalStatus().Diag->empty()) {
+    switch (EvalMode) {
+    case EvaluationMode::ConstantFold:
+    case EvaluationMode::IgnoreSideEffects:
+      if (!HasFoldFailureDiagnostic)
+        break;
+      // We've already failed to fold something. Keep that diagnostic.
+      [[fallthrough]];
+    case EvaluationMode::ConstantExpression:
+    case EvaluationMode::ConstantExpressionUnevaluated:
+      setActiveDiagnostic(false);
+      return true;
+    }
+  }
+  return false;
+}
+
+bool State::keepEvaluatingAfterFailure() const {
+  uint64_t Limit = Ctx.getLangOpts().ConstexprStepLimit;
+  if (Limit != 0 && !stepsLeft())
+    return false;
+
+  switch (EvalMode) {
+  case EvaluationMode::ConstantExpression:
+  case EvaluationMode::ConstantExpressionUnevaluated:
+  case EvaluationMode::ConstantFold:
+  case EvaluationMode::IgnoreSideEffects:
+    return checkingPotentialConstantExpression() ||
+           checkingForUndefinedBehavior();
+  }
+  llvm_unreachable("Missed EvalMode case");
+}
+
+bool State::keepEvaluatingAfterSideEffect() const {
+  switch (EvalMode) {
+  case EvaluationMode::IgnoreSideEffects:
+    return true;
+
+  case EvaluationMode::ConstantExpression:
+  case EvaluationMode::ConstantExpressionUnevaluated:
+  case EvaluationMode::ConstantFold:
+    // By default, assume any side effect might be valid in some other
+    // evaluation of this expression from a different context.
+    return checkingPotentialConstantExpression() ||
+           checkingForUndefinedBehavior();
+  }
+  llvm_unreachable("Missed EvalMode case");
+}
diff --git a/clang/lib/AST/ByteCode/State.h b/clang/lib/AST/ByteCode/State.h
index 0695c61c07a05..b1f799dd13621 100644
--- a/clang/lib/AST/ByteCode/State.h
+++ b/clang/lib/AST/ByteCode/State.h
@@ -78,21 +78,51 @@ class SourceInfo;
 /// Interface for the VM to interact with the AST walker's context.
 class State {
 public:
+  State(ASTContext &ASTCtx, Expr::EvalStatus &EvalStatus)
+      : Ctx(ASTCtx), EvalStatus(EvalStatus) {}
   virtual ~State();
 
-  virtual bool noteUndefinedBehavior() = 0;
-  virtual bool keepEvaluatingAfterFailure() const = 0;
-  virtual bool keepEvaluatingAfterSideEffect() const = 0;
   virtual Frame *getCurrentFrame() = 0;
   virtual const Frame *getBottomFrame() const = 0;
-  virtual bool hasActiveDiagnostic() = 0;
-  virtual void setActiveDiagnostic(bool Flag) = 0;
-  virtual void setFoldFailureDiagnostic(bool Flag) = 0;
-  virtual Expr::EvalStatus &getEvalStatus() const = 0;
-  virtual ASTContext &getASTContext() const = 0;
-  virtual bool hasPriorDiagnostic() = 0;
   virtual unsigned getCallStackDepth() = 0;
-  virtual bool noteSideEffect() = 0;
+  virtual bool stepsLeft() const = 0;
+
+  Expr::EvalStatus &getEvalStatus() const { return EvalStatus; }
+
+  /// Note that we have had a side-effect, and determine whether we should
+  /// keep evaluating.
+  bool noteSideEffect() {
+    getEvalStatus().HasSideEffects = true;
+    return keepEvaluatingAfterSideEffect();
+  }
+
+  // If we have a prior diagnostic, it will be noting that the expression
+  // isn't a constant expression. This diagnostic is more important,
+  // unless we require this evaluation to produce a constant expression.
+  //
+  // FIXME: We might want to show both diagnostics to the user in
+  // EvaluationMode::ConstantFold mode.
+  bool hasPriorDiagnostic();
+
+  /// Should we continue evaluation as much as possible after encountering a
+  /// construct which can't be reduced to a value?
+  bool keepEvaluatingAfterFailure() const;
+  /// Should we continue evaluation after encountering a side-effect that we
+  /// couldn't model?
+  bool keepEvaluatingAfterSideEffect() const;
+
+  /// Note that we hit something that was technically undefined behavior, but
+  /// that we can evaluate past it (such as signed overflow or floating-point
+  /// division by zero.)
+  bool noteUndefinedBehavior() {
+    getEvalStatus().HasUndefinedBehavior = true;
+    return keepEvaluatingAfterUndefinedBehavior();
+  }
+
+  bool hasActiveDiagnostic() const { return HasActiveDiagnostic; }
+  void setActiveDiagnostic(bool Flag) { HasActiveDiagnostic = Flag; };
+
+  void setFoldFailureDiagnostic(bool Flag) { HasFoldFailureDiagnostic = Flag; 
};
 
   /// Are we checking whether the expression is a potential constant
   /// expression?
@@ -104,8 +134,6 @@ class State {
     return CheckingForUndefinedBehavior;
   }
 
-public:
-  State() = default;
   /// Diagnose that the evaluation could not be folded (FF => FoldFailure)
   OptionalDiagnostic
   FFDiag(SourceLocation Loc,
@@ -168,7 +196,17 @@ class State {
   /// is set; this is used when evaluating ICEs in C.
   bool CheckingForUndefinedBehavior = false;
 
+  /// HasActiveDiagnostic - Was the previous diagnostic stored? If so, further
+  /// notes attached to it will also be stored, otherwise they will not be.
+  bool HasActiveDiagnostic = false;
+
+  /// Have we emitted a diagnostic explaining why we couldn't constant
+  /// fold (not just why it's not strictly a constant expression)?
+  bool HasFoldFailureDiagnostic = false;
+
   EvaluationMode EvalMode;
+  ASTContext &Ctx;
+  Expr::EvalStatus &EvalStatus;
 
 private:
   void addCallStack(unsigned Limit);
@@ -177,6 +215,20 @@ class State {
 
   OptionalDiagnostic diag(SourceLocation Loc, diag::kind DiagId,
                           unsigned ExtraNotes, bool IsCCEDiag);
+
+  /// Should we continue evaluation after encountering undefined behavior?
+  bool keepEvaluatingAfterUndefinedBehavior() {
+    switch (EvalMode) {
+    case EvaluationMode::IgnoreSideEffects:
+    case EvaluationMode::ConstantFold:
+      return true;
+
+    case EvaluationMode::ConstantExpression:
+    case EvaluationMode::ConstantExpressionUnevaluated:
+      return checkingForUndefinedBehavior();
+    }
+    llvm_unreachable("Missed EvalMode case");
+  }
 };
 
 } // namespace interp
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 857688ed8039d..86f728fd9f4a0 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -794,13 +794,8 @@ namespace {
   /// rules.  For example, the RHS of (0 && foo()) is not evaluated.  We can
   /// evaluate the expression regardless of what the RHS is, but C only allows
   /// certain things in certain situations.
-  class EvalInfo : public interp::State {
+  class EvalInfo final : public interp::State {
   public:
-    ASTContext &Ctx;
-
-    /// EvalStatus - Contains information about the evaluation.
-    Expr::EvalStatus &EvalStatus;
-
     /// CurrentCall - The top of the constexpr call stack.
     CallStackFrame *CurrentCall;
 
@@ -919,16 +914,8 @@ namespace {
     /// initialization.
     uint64_t ArrayInitIndex = -1;
 
-    /// HasActiveDiagnostic - Was the previous diagnostic stored? If so, 
further
-    /// notes attached to it will also be stored, otherwise they will not be.
-    bool HasActiveDiagnostic;
-
-    /// Have we emitted a diagnostic explaining why we couldn't constant
-    /// fold (not just why it's not strictly a constant expression)?
-    bool HasFoldFailureDiagnostic;
-
     EvalInfo(const ASTContext &C, Expr::EvalStatus &S, EvaluationMode Mode)
-        : Ctx(const_cast<ASTContext &>(C)), EvalStatus(S), 
CurrentCall(nullptr),
+        : State(const_cast<ASTContext &>(C), S), CurrentCall(nullptr),
           CallStackDepth(0), NextCallIndex(1),
           StepsLeft(C.getLangOpts().ConstexprStepLimit),
           EnableNewConstInterp(C.getLangOpts().EnableNewConstInterp),
@@ -936,8 +923,7 @@ namespace {
                       /*This=*/nullptr,
                       /*CallExpr=*/nullptr, CallRef()),
           EvaluatingDecl((const ValueDecl *)nullptr),
-          EvaluatingDeclValue(nullptr), HasActiveDiagnostic(false),
-          HasFoldFailureDiagnostic(false) {
+          EvaluatingDeclValue(nullptr) {
       EvalMode = Mode;
     }
 
@@ -945,7 +931,6 @@ namespace {
       discardCleanups();
     }
 
-    ASTContext &getASTContext() const override { return Ctx; }
     const LangOptions &getLangOpts() const { return Ctx.getLangOpts(); }
 
     void setEvaluatingDecl(APValue::LValueBase Base, APValue &Value,
@@ -1104,107 +1089,10 @@ namespace {
     interp::Frame *getCurrentFrame() override { return CurrentCall; }
     const interp::Frame *getBottomFrame() const override { return 
&BottomFrame; }
 
-    bool hasActiveDiagnostic() override { return HasActiveDiagnostic; }
-    void setActiveDiagnostic(bool Flag) override { HasActiveDiagnostic = Flag; 
}
-
-    void setFoldFailureDiagnostic(bool Flag) override {
-      HasFoldFailureDiagnostic = Flag;
-    }
-
-    Expr::EvalStatus &getEvalStatus() const override { return EvalStatus; }
-
-    // If we have a prior diagnostic, it will be noting that the expression
-    // isn't a constant expression. This diagnostic is more important,
-    // unless we require this evaluation to produce a constant expression.
-    //
-    // FIXME: We might want to show both diagnostics to the user in
-    // EvaluationMode::ConstantFold mode.
-    bool hasPriorDiagnostic() override {
-      if (!EvalStatus.Diag->empty()) {
-        switch (EvalMode) {
-        case EvaluationMode::ConstantFold:
-        case EvaluationMode::IgnoreSideEffects:
-          if (!HasFoldFailureDiagnostic)
-            break;
-          // We've already failed to fold something. Keep that diagnostic.
-          [[fallthrough]];
-        case EvaluationMode::ConstantExpression:
-        case EvaluationMode::ConstantExpressionUnevaluated:
-          setActiveDiagnostic(false);
-          return true;
-        }
-      }
-      return false;
-    }
-
     unsigned getCallStackDepth() override { return CallStackDepth; }
+    bool stepsLeft() const override { return StepsLeft > 0; }
 
   public:
-    /// Should we continue evaluation after encountering a side-effect that we
-    /// couldn't model?
-    bool keepEvaluatingAfterSideEffect() const override {
-      switch (EvalMode) {
-      case EvaluationMode::IgnoreSideEffects:
-        return true;
-
-      case EvaluationMode::ConstantExpression:
-      case EvaluationMode::ConstantExpressionUnevaluated:
-      case EvaluationMode::ConstantFold:
-        // By default, assume any side effect might be valid in some other
-        // evaluation of this expression from a different context.
-        return checkingPotentialConstantExpression() ||
-               checkingForUndefinedBehavior();
-      }
-      llvm_unreachable("Missed EvalMode case");
-    }
-
-    /// Note that we have had a side-effect, and determine whether we should
-    /// keep evaluating.
-    bool noteSideEffect() override {
-      EvalStatus.HasSideEffects = true;
-      return keepEvaluatingAfterSideEffect();
-    }
-
-    /// Should we continue evaluation after encountering undefined behavior?
-    bool keepEvaluatingAfterUndefinedBehavior() {
-      switch (EvalMode) {
-      case EvaluationMode::IgnoreSideEffects:
-      case EvaluationMode::ConstantFold:
-        return true;
-
-      case EvaluationMode::ConstantExpression:
-      case EvaluationMode::ConstantExpressionUnevaluated:
-        return checkingForUndefinedBehavior();
-      }
-      llvm_unreachable("Missed EvalMode case");
-    }
-
-    /// Note that we hit something that was technically undefined behavior, but
-    /// that we can evaluate past it (such as signed overflow or floating-point
-    /// division by zero.)
-    bool noteUndefinedBehavior() override {
-      EvalStatus.HasUndefinedBehavior = true;
-      return keepEvaluatingAfterUndefinedBehavior();
-    }
-
-    /// Should we continue evaluation as much as possible after encountering a
-    /// construct which can't be reduced to a value?
-    bool keepEvaluatingAfterFailure() const override {
-      uint64_t Limit = Ctx.getLangOpts().ConstexprStepLimit;
-      if (Limit != 0 && !StepsLeft)
-        return false;
-
-      switch (EvalMode) {
-      case EvaluationMode::ConstantExpression:
-      case EvaluationMode::ConstantExpressionUnevaluated:
-      case EvaluationMode::ConstantFold:
-      case EvaluationMode::IgnoreSideEffects:
-        return checkingPotentialConstantExpression() ||
-               checkingForUndefinedBehavior();
-      }
-      llvm_unreachable("Missed EvalMode case");
-    }
-
     /// Notes that we failed to evaluate an expression that other expressions
     /// directly depend on, and determine if we should keep evaluating. This
     /// should only be called if we actually intend to keep evaluating.
@@ -2416,9 +2304,8 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, 
SourceLocation Loc,
 
       // In CUDA/HIP device compilation, only device side variables have
       // constant addresses.
-      if (Info.getASTContext().getLangOpts().CUDA &&
-          Info.getASTContext().getLangOpts().CUDAIsDevice &&
-          Info.getASTContext().CUDAConstantEvalCtx.NoWrongSidedVars) {
+      if (Info.Ctx.getLangOpts().CUDA && Info.Ctx.getLangOpts().CUDAIsDevice &&
+          Info.Ctx.CUDAConstantEvalCtx.NoWrongSidedVars) {
         if ((!Var->hasAttr<CUDADeviceAttr>() &&
              !Var->hasAttr<CUDAConstantAttr>() &&
              !Var->getType()->isCUDADeviceBuiltinSurfaceType() &&
@@ -6330,7 +6217,7 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, 
EvalInfo &Info,
         *Info.CurrentCall, hasSpecificAttr<MSConstexprAttr>(AS->getAttrs()) &&
                                isa<ReturnStmt>(SS));
 
-    auto LO = Info.getASTContext().getLangOpts();
+    auto LO = Info.Ctx.getLangOpts();
     if (LO.CXXAssumptions && !LO.MSVCCompat) {
       for (auto *Attr : AS->getAttrs()) {
         auto *AA = dyn_cast<CXXAssumeAttr>(Attr);
@@ -6341,7 +6228,7 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, 
EvalInfo &Info,
         if (Assumption->isValueDependent())
           return ESR_Failed;
 
-        if (Assumption->HasSideEffects(Info.getASTContext()))
+        if (Assumption->HasSideEffects(Info.Ctx))
           continue;
 
         bool Value;
@@ -9329,8 +9216,8 @@ class LValueExprEvaluator
   bool VisitCompoundLiteralExpr(const CompoundLiteralExpr *E);
   bool VisitMemberExpr(const MemberExpr *E);
   bool VisitStringLiteral(const StringLiteral *E) {
-    return Success(APValue::LValueBase(
-        E, 0, Info.getASTContext().getNextStringLiteralVersion()));
+    return Success(
+        APValue::LValueBase(E, 0, Info.Ctx.getNextStringLiteralVersion()));
   }
   bool VisitObjCEncodeExpr(const ObjCEncodeExpr *E) { return Success(E); }
   bool VisitCXXTypeidExpr(const CXXTypeidExpr *E);

>From 0ee1356a9a814387a77c0f3e4c13f8fad0483132 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <[email protected]>
Date: Tue, 27 Jan 2026 10:18:45 +0100
Subject: [PATCH 2/6] take const State&

---
 clang/lib/AST/ByteCode/InterpState.cpp | 4 ++--
 clang/lib/AST/ByteCode/InterpState.h   | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/clang/lib/AST/ByteCode/InterpState.cpp 
b/clang/lib/AST/ByteCode/InterpState.cpp
index 510606c84af13..952aec070768f 100644
--- a/clang/lib/AST/ByteCode/InterpState.cpp
+++ b/clang/lib/AST/ByteCode/InterpState.cpp
@@ -17,7 +17,7 @@
 using namespace clang;
 using namespace clang::interp;
 
-InterpState::InterpState(State &Parent, Program &P, InterpStack &Stk,
+InterpState::InterpState(const State &Parent, Program &P, InterpStack &Stk,
                          Context &Ctx, SourceMapper *M)
     : State(Ctx.getASTContext(), Parent.getEvalStatus()), M(M), P(P), Stk(Stk),
       Ctx(Ctx), BottomFrame(*this), Current(&BottomFrame) {
@@ -28,7 +28,7 @@ InterpState::InterpState(State &Parent, Program &P, 
InterpStack &Stk,
   EvalMode = Parent.EvalMode;
 }
 
-InterpState::InterpState(State &Parent, Program &P, InterpStack &Stk,
+InterpState::InterpState(const State &Parent, Program &P, InterpStack &Stk,
                          Context &Ctx, const Function *Func)
     : State(Ctx.getASTContext(), Parent.getEvalStatus()), M(nullptr), P(P),
       Stk(Stk), Ctx(Ctx),
diff --git a/clang/lib/AST/ByteCode/InterpState.h 
b/clang/lib/AST/ByteCode/InterpState.h
index 5c620c0b8a775..c8cdbc6693d81 100644
--- a/clang/lib/AST/ByteCode/InterpState.h
+++ b/clang/lib/AST/ByteCode/InterpState.h
@@ -42,9 +42,9 @@ struct StdAllocatorCaller {
 /// Interpreter context.
 class InterpState final : public State, public SourceMapper {
 public:
-  InterpState(State &Parent, Program &P, InterpStack &Stk, Context &Ctx,
+  InterpState(const State &Parent, Program &P, InterpStack &Stk, Context &Ctx,
               SourceMapper *M = nullptr);
-  InterpState(State &Parent, Program &P, InterpStack &Stk, Context &Ctx,
+  InterpState(const State &Parent, Program &P, InterpStack &Stk, Context &Ctx,
               const Function *Func);
 
   ~InterpState();

>From 879965d166b8a80a448c487796b630054156aa67 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <[email protected]>
Date: Tue, 27 Jan 2026 10:57:38 +0100
Subject: [PATCH 3/6] setFoldFailureDiagnostic can be private

---
 clang/lib/AST/ByteCode/State.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/lib/AST/ByteCode/State.h b/clang/lib/AST/ByteCode/State.h
index b1f799dd13621..781fdba9e0b27 100644
--- a/clang/lib/AST/ByteCode/State.h
+++ b/clang/lib/AST/ByteCode/State.h
@@ -122,8 +122,6 @@ class State {
   bool hasActiveDiagnostic() const { return HasActiveDiagnostic; }
   void setActiveDiagnostic(bool Flag) { HasActiveDiagnostic = Flag; };
 
-  void setFoldFailureDiagnostic(bool Flag) { HasFoldFailureDiagnostic = Flag; 
};
-
   /// Are we checking whether the expression is a potential constant
   /// expression?
   bool checkingPotentialConstantExpression() const {
@@ -229,6 +227,8 @@ class State {
     }
     llvm_unreachable("Missed EvalMode case");
   }
+
+  void setFoldFailureDiagnostic(bool Flag) { HasFoldFailureDiagnostic = Flag; 
};
 };
 
 } // namespace interp

>From fe3840eadc3a441e18a1423feedb3f7760861c84 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <[email protected]>
Date: Tue, 27 Jan 2026 10:59:32 +0100
Subject: [PATCH 4/6] setActiveDiagnostic can be private

---
 clang/lib/AST/ByteCode/State.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/AST/ByteCode/State.h b/clang/lib/AST/ByteCode/State.h
index 781fdba9e0b27..342cb98aefde2 100644
--- a/clang/lib/AST/ByteCode/State.h
+++ b/clang/lib/AST/ByteCode/State.h
@@ -120,7 +120,6 @@ class State {
   }
 
   bool hasActiveDiagnostic() const { return HasActiveDiagnostic; }
-  void setActiveDiagnostic(bool Flag) { HasActiveDiagnostic = Flag; };
 
   /// Are we checking whether the expression is a potential constant
   /// expression?
@@ -229,6 +228,7 @@ class State {
   }
 
   void setFoldFailureDiagnostic(bool Flag) { HasFoldFailureDiagnostic = Flag; 
};
+  void setActiveDiagnostic(bool Flag) { HasActiveDiagnostic = Flag; };
 };
 
 } // namespace interp

>From 22bfb40579e693c3a5dd0fec9ab53a2b2cba8373 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <[email protected]>
Date: Tue, 27 Jan 2026 11:08:16 +0100
Subject: [PATCH 5/6] Make a few bool fields private

---
 clang/lib/AST/ByteCode/State.cpp | 15 +++++++--------
 clang/lib/AST/ByteCode/State.h   | 33 ++++++++++++++++----------------
 2 files changed, 23 insertions(+), 25 deletions(-)

diff --git a/clang/lib/AST/ByteCode/State.cpp b/clang/lib/AST/ByteCode/State.cpp
index 8958aa547b90f..76c8738a91546 100644
--- a/clang/lib/AST/ByteCode/State.cpp
+++ b/clang/lib/AST/ByteCode/State.cpp
@@ -25,7 +25,7 @@ OptionalDiagnostic State::FFDiag(SourceLocation Loc, 
diag::kind DiagId,
 
 OptionalDiagnostic State::FFDiag(const Expr *E, diag::kind DiagId,
                                  unsigned ExtraNotes) {
-  if (getEvalStatus().Diag)
+  if (EvalStatus.Diag)
     return diag(E->getExprLoc(), DiagId, ExtraNotes, false);
   setActiveDiagnostic(false);
   return OptionalDiagnostic();
@@ -33,7 +33,7 @@ OptionalDiagnostic State::FFDiag(const Expr *E, diag::kind 
DiagId,
 
 OptionalDiagnostic State::FFDiag(const SourceInfo &SI, diag::kind DiagId,
                                  unsigned ExtraNotes) {
-  if (getEvalStatus().Diag)
+  if (EvalStatus.Diag)
     return diag(SI.getLoc(), DiagId, ExtraNotes, false);
   setActiveDiagnostic(false);
   return OptionalDiagnostic();
@@ -43,7 +43,7 @@ OptionalDiagnostic State::CCEDiag(SourceLocation Loc, 
diag::kind DiagId,
                                   unsigned ExtraNotes) {
   // Don't override a previous diagnostic. Don't bother collecting
   // diagnostics if we're evaluating for overflow.
-  if (!getEvalStatus().Diag || !getEvalStatus().Diag->empty()) {
+  if (!EvalStatus.Diag || !EvalStatus.Diag->empty()) {
     setActiveDiagnostic(false);
     return OptionalDiagnostic();
   }
@@ -68,7 +68,7 @@ OptionalDiagnostic State::Note(SourceLocation Loc, diag::kind 
DiagId) {
 
 void State::addNotes(ArrayRef<PartialDiagnosticAt> Diags) {
   if (hasActiveDiagnostic())
-    llvm::append_range(*getEvalStatus().Diag, Diags);
+    llvm::append_range(*EvalStatus.Diag, Diags);
 }
 
 DiagnosticBuilder State::report(SourceLocation Loc, diag::kind DiagId) {
@@ -78,13 +78,12 @@ DiagnosticBuilder State::report(SourceLocation Loc, 
diag::kind DiagId) {
 /// Add a diagnostic to the diagnostics list.
 PartialDiagnostic &State::addDiag(SourceLocation Loc, diag::kind DiagId) {
   PartialDiagnostic PD(DiagId, Ctx.getDiagAllocator());
-  getEvalStatus().Diag->push_back(std::make_pair(Loc, PD));
-  return getEvalStatus().Diag->back().second;
+  EvalStatus.Diag->push_back(std::make_pair(Loc, PD));
+  return EvalStatus.Diag->back().second;
 }
 
 OptionalDiagnostic State::diag(SourceLocation Loc, diag::kind DiagId,
                                unsigned ExtraNotes, bool IsCCEDiag) {
-  Expr::EvalStatus &EvalStatus = getEvalStatus();
   if (EvalStatus.Diag) {
     if (hasPriorDiagnostic()) {
       return OptionalDiagnostic();
@@ -159,7 +158,7 @@ void State::addCallStack(unsigned Limit) {
 }
 
 bool State::hasPriorDiagnostic() {
-  if (!getEvalStatus().Diag->empty()) {
+  if (!EvalStatus.Diag->empty()) {
     switch (EvalMode) {
     case EvaluationMode::ConstantFold:
     case EvaluationMode::IgnoreSideEffects:
diff --git a/clang/lib/AST/ByteCode/State.h b/clang/lib/AST/ByteCode/State.h
index 342cb98aefde2..d1aa3daf2aa29 100644
--- a/clang/lib/AST/ByteCode/State.h
+++ b/clang/lib/AST/ByteCode/State.h
@@ -92,18 +92,10 @@ class State {
   /// Note that we have had a side-effect, and determine whether we should
   /// keep evaluating.
   bool noteSideEffect() {
-    getEvalStatus().HasSideEffects = true;
+    EvalStatus.HasSideEffects = true;
     return keepEvaluatingAfterSideEffect();
   }
 
-  // If we have a prior diagnostic, it will be noting that the expression
-  // isn't a constant expression. This diagnostic is more important,
-  // unless we require this evaluation to produce a constant expression.
-  //
-  // FIXME: We might want to show both diagnostics to the user in
-  // EvaluationMode::ConstantFold mode.
-  bool hasPriorDiagnostic();
-
   /// Should we continue evaluation as much as possible after encountering a
   /// construct which can't be reduced to a value?
   bool keepEvaluatingAfterFailure() const;
@@ -115,12 +107,10 @@ class State {
   /// that we can evaluate past it (such as signed overflow or floating-point
   /// division by zero.)
   bool noteUndefinedBehavior() {
-    getEvalStatus().HasUndefinedBehavior = true;
+    EvalStatus.HasUndefinedBehavior = true;
     return keepEvaluatingAfterUndefinedBehavior();
   }
 
-  bool hasActiveDiagnostic() const { return HasActiveDiagnostic; }
-
   /// Are we checking whether the expression is a potential constant
   /// expression?
   bool checkingPotentialConstantExpression() const {
@@ -193,6 +183,11 @@ class State {
   /// is set; this is used when evaluating ICEs in C.
   bool CheckingForUndefinedBehavior = false;
 
+  EvaluationMode EvalMode;
+  ASTContext &Ctx;
+  Expr::EvalStatus &EvalStatus;
+
+private:
   /// HasActiveDiagnostic - Was the previous diagnostic stored? If so, further
   /// notes attached to it will also be stored, otherwise they will not be.
   bool HasActiveDiagnostic = false;
@@ -201,11 +196,6 @@ class State {
   /// fold (not just why it's not strictly a constant expression)?
   bool HasFoldFailureDiagnostic = false;
 
-  EvaluationMode EvalMode;
-  ASTContext &Ctx;
-  Expr::EvalStatus &EvalStatus;
-
-private:
   void addCallStack(unsigned Limit);
 
   PartialDiagnostic &addDiag(SourceLocation Loc, diag::kind DiagId);
@@ -227,8 +217,17 @@ class State {
     llvm_unreachable("Missed EvalMode case");
   }
 
+  // If we have a prior diagnostic, it will be noting that the expression
+  // isn't a constant expression. This diagnostic is more important,
+  // unless we require this evaluation to produce a constant expression.
+  //
+  // FIXME: We might want to show both diagnostics to the user in
+  // EvaluationMode::ConstantFold mode.
+  bool hasPriorDiagnostic();
+
   void setFoldFailureDiagnostic(bool Flag) { HasFoldFailureDiagnostic = Flag; 
};
   void setActiveDiagnostic(bool Flag) { HasActiveDiagnostic = Flag; };
+  bool hasActiveDiagnostic() const { return HasActiveDiagnostic; }
 };
 
 } // namespace interp

>From cf64be53369d13d5307e268fdff562753b0abb07 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <[email protected]>
Date: Tue, 27 Jan 2026 11:52:25 +0100
Subject: [PATCH 6/6] Copy SourceInfos

---
 clang/lib/AST/ByteCode/State.cpp | 4 ++--
 clang/lib/AST/ByteCode/State.h   | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/clang/lib/AST/ByteCode/State.cpp b/clang/lib/AST/ByteCode/State.cpp
index 76c8738a91546..f1192f1d07ebd 100644
--- a/clang/lib/AST/ByteCode/State.cpp
+++ b/clang/lib/AST/ByteCode/State.cpp
@@ -31,7 +31,7 @@ OptionalDiagnostic State::FFDiag(const Expr *E, diag::kind 
DiagId,
   return OptionalDiagnostic();
 }
 
-OptionalDiagnostic State::FFDiag(const SourceInfo &SI, diag::kind DiagId,
+OptionalDiagnostic State::FFDiag(SourceInfo SI, diag::kind DiagId,
                                  unsigned ExtraNotes) {
   if (EvalStatus.Diag)
     return diag(SI.getLoc(), DiagId, ExtraNotes, false);
@@ -55,7 +55,7 @@ OptionalDiagnostic State::CCEDiag(const Expr *E, diag::kind 
DiagId,
   return CCEDiag(E->getExprLoc(), DiagId, ExtraNotes);
 }
 
-OptionalDiagnostic State::CCEDiag(const SourceInfo &SI, diag::kind DiagId,
+OptionalDiagnostic State::CCEDiag(SourceInfo SI, diag::kind DiagId,
                                   unsigned ExtraNotes) {
   return CCEDiag(SI.getLoc(), DiagId, ExtraNotes);
 }
diff --git a/clang/lib/AST/ByteCode/State.h b/clang/lib/AST/ByteCode/State.h
index d1aa3daf2aa29..1b752549ba049 100644
--- a/clang/lib/AST/ByteCode/State.h
+++ b/clang/lib/AST/ByteCode/State.h
@@ -133,7 +133,7 @@ class State {
          unsigned ExtraNotes = 0);
 
   OptionalDiagnostic
-  FFDiag(const SourceInfo &SI,
+  FFDiag(SourceInfo SI,
          diag::kind DiagId = diag::note_invalid_subexpr_in_const_expr,
          unsigned ExtraNotes = 0);
 
@@ -153,7 +153,7 @@ class State {
           unsigned ExtraNotes = 0);
 
   OptionalDiagnostic
-  CCEDiag(const SourceInfo &SI,
+  CCEDiag(SourceInfo SI,
           diag::kind DiagId = diag::note_invalid_subexpr_in_const_expr,
           unsigned ExtraNotes = 0);
 

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to