[clang] [clang][bytecode] Add `EvalSettings` struct and replace parent `State` (PR #226175)
Timm Baeder via cfe-commits
cfe-commits at lists.llvm.org
Fri Sep 25 04:54:05 PDT 2026
https://github.com/tbaederr updated https://github.com/llvm/llvm-project/pull/226175
>From 559df2a1acc409983680ca904c50bf817f442258 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Thu, 24 Sep 2026 16:08:13 +0200
Subject: [PATCH] [clang][bytecode] Use EvalSettings struct
---
clang/lib/AST/ByteCode/Context.cpp | 114 ++++++++++++-------
clang/lib/AST/ByteCode/Context.h | 41 ++++---
clang/lib/AST/ByteCode/EvalEmitter.cpp | 6 +
clang/lib/AST/ByteCode/EvalEmitter.h | 2 +
clang/lib/AST/ByteCode/EvalSettings.h | 35 ++++++
clang/lib/AST/ByteCode/InterpState.cpp | 30 +++--
clang/lib/AST/ByteCode/InterpState.h | 6 +-
clang/lib/AST/ExprConstant.cpp | 146 +++++++++++++++----------
8 files changed, 258 insertions(+), 122 deletions(-)
create mode 100644 clang/lib/AST/ByteCode/EvalSettings.h
diff --git a/clang/lib/AST/ByteCode/Context.cpp b/clang/lib/AST/ByteCode/Context.cpp
index 9cdb2725a92040..76d875bdceba01 100644
--- a/clang/lib/AST/ByteCode/Context.cpp
+++ b/clang/lib/AST/ByteCode/Context.cpp
@@ -12,6 +12,7 @@
#include "Char.h"
#include "Compiler.h"
#include "EvalEmitter.h"
+#include "EvalSettings.h"
#include "Integral.h"
#include "InterpFrame.h"
#include "InterpHelpers.h"
@@ -37,7 +38,8 @@ Context::Context(ASTContext &Ctx) : Ctx(Ctx), P(new Program(*this)) {
Context::~Context() = default;
-bool Context::isPotentialConstantExpr(State &Parent, const FunctionDecl *FD) {
+bool Context::isPotentialConstantExpr(const EvalSettings &Settings,
+ const FunctionDecl *FD) {
assert(Stk.empty());
// Get a function handle.
@@ -54,15 +56,16 @@ bool Context::isPotentialConstantExpr(State &Parent, const FunctionDecl *FD) {
++EvalID;
// And run it.
- return Run(Parent, Func);
+ return Run(Settings, Func);
}
-void Context::isPotentialConstantExprUnevaluated(State &Parent, const Expr *E,
+void Context::isPotentialConstantExprUnevaluated(const EvalSettings &Settings,
+ const Expr *E,
const FunctionDecl *FD) {
assert(Stk.empty());
++EvalID;
size_t StackSizeBefore = Stk.size();
- Compiler<EvalEmitter> C(*this, *P, Parent, Stk, FrameAlloc);
+ Compiler<EvalEmitter> C(*this, *P, Settings, Stk, FrameAlloc);
if (!C.interpretCall(FD, E)) {
C.cleanup();
@@ -99,12 +102,42 @@ bool Context::evaluateAsRValue(State &Parent, const Expr *E, APValue &Result) {
return true;
}
-bool Context::evaluate(State &Parent, const Expr *E, APValue &Result,
- ConstantExprKind Kind) {
+bool Context::evaluateAsRValue(const EvalSettings &Settings, const Expr *E,
+ APValue &Result) {
++EvalID;
bool Recursing = !Stk.empty();
size_t StackSizeBefore = Stk.size();
- Compiler<EvalEmitter> C(*this, *P, Parent, Stk, FrameAlloc, Kind);
+ Compiler<EvalEmitter> C(*this, *P, Settings, Stk, FrameAlloc);
+
+ auto Res = C.interpretExpr(E);
+
+ if (Res.isInvalid()) {
+ C.cleanup();
+ Stk.clearTo(StackSizeBefore);
+ return false;
+ }
+
+ if (!Recursing) {
+ // We *can* actually get here with a non-empty stack, since
+ // things like InterpState::noteSideEffect() exist.
+ C.cleanup();
+#ifndef NDEBUG
+ // Make sure we don't rely on some value being still alive in
+ // InterpStack memory.
+ Stk.clearTo(StackSizeBefore);
+#endif
+ }
+
+ Result = Res.stealAPValue();
+ return true;
+}
+
+bool Context::evaluate(const EvalSettings &Settings, const Expr *E,
+ APValue &Result) {
+ ++EvalID;
+ bool Recursing = !Stk.empty();
+ size_t StackSizeBefore = Stk.size();
+ Compiler<EvalEmitter> C(*this, *P, Settings, Stk, FrameAlloc);
auto Res = C.interpretExpr(E, /*ConvertResultToRValue=*/false,
/*DestroyToplevelScope=*/true);
@@ -128,12 +161,13 @@ bool Context::evaluate(State &Parent, const Expr *E, APValue &Result,
return true;
}
-bool Context::evaluateAsInitializer(State &Parent, const VarDecl *VD,
- const Expr *Init, APValue &Result) {
+bool Context::evaluateAsInitializer(const EvalSettings &Settings,
+ const VarDecl *VD, const Expr *Init,
+ APValue &Result) {
++EvalID;
bool Recursing = !Stk.empty();
size_t StackSizeBefore = Stk.size();
- Compiler<EvalEmitter> C(*this, *P, Parent, Stk, FrameAlloc);
+ Compiler<EvalEmitter> C(*this, *P, Settings, Stk, FrameAlloc);
bool CheckGlobalInitialized =
(VD->getType()->isRecordType() || VD->getType()->isArrayType());
@@ -160,10 +194,10 @@ bool Context::evaluateAsInitializer(State &Parent, const VarDecl *VD,
return true;
}
-bool Context::evaluateDestruction(State &Parent, const VarDecl *VD,
- APValue Value) {
+bool Context::evaluateDestruction(const EvalSettings &Settings,
+ const VarDecl *VD, APValue Value) {
assert(Stk.empty());
- Compiler<EvalEmitter> C(*this, *P, Parent, Stk, FrameAlloc);
+ Compiler<EvalEmitter> C(*this, *P, Settings, Stk, FrameAlloc);
auto Res = C.interpretDestructor(VD, Value);
@@ -186,14 +220,15 @@ void Context::registerRedecl(const VarDecl *VD, const APValue &V) {
}
template <typename ResultT>
-bool Context::evaluateStringRepr(State &Parent, const Expr *SizeExpr,
- const Expr *PtrExpr, ResultT &Result) {
+bool Context::evaluateStringRepr(const EvalSettings &Settings,
+ const Expr *SizeExpr, const Expr *PtrExpr,
+ ResultT &Result) {
assert(Stk.empty());
- Compiler<EvalEmitter> C(*this, *P, Parent, Stk, FrameAlloc);
+ Compiler<EvalEmitter> C(*this, *P, Settings, Stk, FrameAlloc);
// Evaluate size value.
APValue SizeValue;
- if (!evaluateAsRValue(Parent, SizeExpr, SizeValue))
+ if (!evaluateAsRValue(Settings, SizeExpr, SizeValue))
return false;
if (!SizeValue.isInt())
@@ -269,26 +304,28 @@ bool Context::evaluateStringRepr(State &Parent, const Expr *SizeExpr,
return true;
}
-bool Context::evaluateCharRange(State &Parent, const Expr *SizeExpr,
- const Expr *PtrExpr, APValue &Result) {
+bool Context::evaluateCharRange(const EvalSettings &Settings,
+ const Expr *SizeExpr, const Expr *PtrExpr,
+ APValue &Result) {
assert(SizeExpr);
assert(PtrExpr);
- return evaluateStringRepr(Parent, SizeExpr, PtrExpr, Result);
+ return evaluateStringRepr(Settings, SizeExpr, PtrExpr, Result);
}
-bool Context::evaluateCharRange(State &Parent, const Expr *SizeExpr,
- const Expr *PtrExpr, std::string &Result) {
+bool Context::evaluateCharRange(const EvalSettings &Settings,
+ const Expr *SizeExpr, const Expr *PtrExpr,
+ std::string &Result) {
assert(SizeExpr);
assert(PtrExpr);
- return evaluateStringRepr(Parent, SizeExpr, PtrExpr, Result);
+ return evaluateStringRepr(Settings, SizeExpr, PtrExpr, Result);
}
-bool Context::evaluateString(State &Parent, const Expr *E,
+bool Context::evaluateString(const EvalSettings &Settings, const Expr *E,
std::string &Result) {
assert(Stk.empty());
- Compiler<EvalEmitter> C(*this, *P, Parent, Stk, FrameAlloc);
+ Compiler<EvalEmitter> C(*this, *P, Settings, Stk, FrameAlloc);
auto PtrRes = C.interpretAsPointer(E, [&](InterpState &S, CodePtr OpPC,
const Pointer &Ptr) {
@@ -350,9 +387,10 @@ bool Context::evaluateString(State &Parent, const Expr *E,
return true;
}
-std::optional<uint64_t> Context::evaluateStrlen(State &Parent, const Expr *E) {
+std::optional<uint64_t> Context::evaluateStrlen(const EvalSettings &Settings,
+ const Expr *E) {
assert(Stk.empty());
- Compiler<EvalEmitter> C(*this, *P, Parent, Stk, FrameAlloc);
+ Compiler<EvalEmitter> C(*this, *P, Settings, Stk, FrameAlloc);
std::optional<uint64_t> Result;
auto PtrRes = C.interpretAsPointer(E, [&](InterpState &S, CodePtr OpPC,
@@ -416,12 +454,11 @@ std::optional<uint64_t> Context::evaluateStrlen(State &Parent, const Expr *E) {
return Result;
}
-std::optional<uint64_t> Context::tryEvaluateObjectSize(State &Parent,
- const Expr *E,
- unsigned Kind,
- bool IsDynamic) {
+std::optional<uint64_t>
+Context::tryEvaluateObjectSize(const EvalSettings &Settings, const Expr *E,
+ unsigned Kind, bool IsDynamic) {
assert(Stk.empty());
- Compiler<EvalEmitter> C(*this, *P, Parent, Stk, FrameAlloc);
+ Compiler<EvalEmitter> C(*this, *P, Settings, Stk, FrameAlloc);
std::optional<uint64_t> Result;
auto PtrRes = C.interpretAsLValuePointer(E, [&](InterpState &S, CodePtr OpPC,
@@ -448,17 +485,16 @@ std::optional<uint64_t> Context::tryEvaluateObjectSize(State &Parent,
return Result;
}
-std::optional<bool>
-Context::evaluateWithSubstitution(State &Parent, const FunctionDecl *Callee,
- ArrayRef<const Expr *> Args, const Expr *This,
- const Expr *Condition) {
+std::optional<bool> Context::evaluateWithSubstitution(
+ const EvalSettings &Settings, const FunctionDecl *Callee,
+ ArrayRef<const Expr *> Args, const Expr *This, const Expr *Condition) {
if (OptPrimType ConditionT = classify(Condition);
!ConditionT || ConditionT != PT_Bool) {
return std::nullopt;
}
assert(Stk.empty());
- Compiler<EvalEmitter> C(*this, *P, Parent, Stk, FrameAlloc);
+ Compiler<EvalEmitter> C(*this, *P, Settings, Stk, FrameAlloc);
std::optional<bool> Result =
C.interpretWithSubstitutions(Callee, Args, This, Condition);
@@ -599,9 +635,9 @@ const llvm::fltSemantics &Context::getFloatSemantics(QualType T) const {
return Ctx.getFloatTypeSemantics(T);
}
-bool Context::Run(State &Parent, const Function *Func) {
+bool Context::Run(const EvalSettings &Settings, const Function *Func) {
auto Memory = std::make_unique<char[]>(InterpFrame::allocSize(Func));
- InterpState State(Parent, *P, Stk, FrameAlloc, *this, Func);
+ InterpState State(Settings, *P, Stk, FrameAlloc, *this, Func);
InterpFrame *Frame = new (Memory.get()) InterpFrame(
State, Func, /*Caller=*/nullptr, CodePtr(), Func->getArgSize());
State.Current = Frame;
diff --git a/clang/lib/AST/ByteCode/Context.h b/clang/lib/AST/ByteCode/Context.h
index 1390bc280602e4..baeb08c39200e5 100644
--- a/clang/lib/AST/ByteCode/Context.h
+++ b/clang/lib/AST/ByteCode/Context.h
@@ -32,6 +32,7 @@ class Function;
class Program;
class State;
enum PrimType : uint8_t;
+struct EvalSettings;
struct ParamOffset {
unsigned Offset;
@@ -54,37 +55,44 @@ class Context final {
~Context();
/// Checks if a function is a potential constant expression.
- bool isPotentialConstantExpr(State &Parent, const FunctionDecl *FD);
- void isPotentialConstantExprUnevaluated(State &Parent, const Expr *E,
+ bool isPotentialConstantExpr(const EvalSettings &Settings,
+ const FunctionDecl *FD);
+ void isPotentialConstantExprUnevaluated(const EvalSettings &Settings,
+ const Expr *E,
const FunctionDecl *FD);
/// Evaluates a toplevel expression as an rvalue.
+ // FIXME: Get rid of the version using a parent State.
bool evaluateAsRValue(State &Parent, const Expr *E, APValue &Result);
+ bool evaluateAsRValue(const EvalSettings &Settings, const Expr *E,
+ APValue &Result);
/// Like evaluateAsRvalue(), but does no implicit lvalue-to-rvalue conversion.
- bool evaluate(State &Parent, const Expr *E, APValue &Result,
- ConstantExprKind Kind);
+ bool evaluate(const EvalSettings &Settings, const Expr *E, APValue &Result);
/// Evaluates a toplevel initializer.
- bool evaluateAsInitializer(State &Parent, const VarDecl *VD, const Expr *Init,
- APValue &Result);
+ bool evaluateAsInitializer(const EvalSettings &Settings, const VarDecl *VD,
+ const Expr *Init, APValue &Result);
void registerRedecl(const VarDecl *VD, const APValue &V);
/// Evaluates the destruction of a variable.
- bool evaluateDestruction(State &Parent, const VarDecl *VD, APValue Value);
+ bool evaluateDestruction(const EvalSettings &Settings, const VarDecl *VD,
+ APValue Value);
- bool evaluateCharRange(State &Parent, const Expr *SizeExpr,
+ bool evaluateCharRange(const EvalSettings &Settings, const Expr *SizeExpr,
const Expr *PtrExpr, APValue &Result);
- bool evaluateCharRange(State &Parent, const Expr *SizeExpr,
+ bool evaluateCharRange(const EvalSettings &Settings, const Expr *SizeExpr,
const Expr *PtrExpr, std::string &Result);
/// Evaluate \param E and if it can be evaluated to a null-terminated string,
/// copy the result into \param Result.
- bool evaluateString(State &Parent, const Expr *E, std::string &Result);
+ bool evaluateString(const EvalSettings &Settings, const Expr *E,
+ std::string &Result);
/// Evalute \param E and if it can be evaluated to a string literal,
/// run strlen() on it.
- std::optional<uint64_t> evaluateStrlen(State &Parent, const Expr *E);
+ std::optional<uint64_t> evaluateStrlen(const EvalSettings &Settings,
+ const Expr *E);
/// If \param E evaluates to a pointer the number of accessible bytes
/// past the pointer is estimated in \param Result as if evaluated by
@@ -96,10 +104,11 @@ class Context final {
/// as the one referred to by E are considered, when Kind & 1 == 0
/// bytes belonging to the same storage (stack, heap allocation,
/// global variable) are considered.
- std::optional<uint64_t> tryEvaluateObjectSize(State &Parent, const Expr *E,
- unsigned Kind, bool IsDynamic);
+ std::optional<uint64_t> tryEvaluateObjectSize(const EvalSettings &Settings,
+ const Expr *E, unsigned Kind,
+ bool IsDynamic);
- std::optional<bool> evaluateWithSubstitution(State &Parent,
+ std::optional<bool> evaluateWithSubstitution(const EvalSettings &Settings,
const FunctionDecl *Callee,
ArrayRef<const Expr *> Args,
const Expr *This,
@@ -192,10 +201,10 @@ class Context final {
private:
friend class EvalIDScope;
/// Runs a function.
- bool Run(State &Parent, const Function *Func);
+ bool Run(const EvalSettings &Settings, const Function *Func);
template <typename ResultT>
- bool evaluateStringRepr(State &Parent, const Expr *SizeExpr,
+ bool evaluateStringRepr(const EvalSettings &Settings, const Expr *SizeExpr,
const Expr *PtrExpr, ResultT &Result);
/// Current compilation context.
diff --git a/clang/lib/AST/ByteCode/EvalEmitter.cpp b/clang/lib/AST/ByteCode/EvalEmitter.cpp
index ec7550eb4cc17a..b0b34621314369 100644
--- a/clang/lib/AST/ByteCode/EvalEmitter.cpp
+++ b/clang/lib/AST/ByteCode/EvalEmitter.cpp
@@ -8,6 +8,7 @@
#include "EvalEmitter.h"
#include "Context.h"
+#include "EvalSettings.h"
#include "IntegralAP.h"
#include "Interp.h"
#include "clang/AST/DeclCXX.h"
@@ -23,6 +24,11 @@ EvalEmitter::EvalEmitter(Context &Ctx, Program &P, State &Parent,
: Ctx(Ctx), P(P), S(Parent, P, Stk, FA, Ctx, this), EvalResult(Ctx),
ConstexprKind(ConstexprKind) {}
+EvalEmitter::EvalEmitter(Context &Ctx, Program &P, const EvalSettings &Settings,
+ InterpStack &Stk, FrameAllocator &FA)
+ : Ctx(Ctx), P(P), S(Settings, P, Stk, FA, Ctx, this), EvalResult(Ctx),
+ ConstexprKind(Settings.ConstexprKind) {}
+
EvalEmitter::EvalEmitter(Context &Ctx, Program &P, Expr::EvalStatus &Status,
InterpStack &Stk, FrameAllocator &FA)
: Ctx(Ctx), P(P), S(Status, P, Stk, FA, Ctx, this), EvalResult(Ctx) {}
diff --git a/clang/lib/AST/ByteCode/EvalEmitter.h b/clang/lib/AST/ByteCode/EvalEmitter.h
index 70ad775e84f81c..2faa48a5077372 100644
--- a/clang/lib/AST/ByteCode/EvalEmitter.h
+++ b/clang/lib/AST/ByteCode/EvalEmitter.h
@@ -74,6 +74,8 @@ class EvalEmitter : public SourceMapper {
EvalEmitter(Context &Ctx, Program &P, State &Parent, InterpStack &Stk,
FrameAllocator &FrameAlloc,
ConstantExprKind ConstexprKind = ConstantExprKind::Normal);
+ EvalEmitter(Context &Ctx, Program &P, const EvalSettings &Settings,
+ InterpStack &Stk, FrameAllocator &FrameAlloc);
EvalEmitter(Context &Ctx, Program &P, Expr::EvalStatus &Status,
InterpStack &Stk, FrameAllocator &FrameAlloc);
diff --git a/clang/lib/AST/ByteCode/EvalSettings.h b/clang/lib/AST/ByteCode/EvalSettings.h
new file mode 100644
index 00000000000000..df4dcda515ded2
--- /dev/null
+++ b/clang/lib/AST/ByteCode/EvalSettings.h
@@ -0,0 +1,35 @@
+//===--------------------------- EvalSettings.h -----------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_EVALSETTINGS_H
+#define LLVM_CLANG_AST_INTERP_EVALSETTINGS_H
+
+#include "State.h"
+
+namespace clang {
+namespace interp {
+
+struct EvalSettings {
+ Expr::EvalStatus &EvalStatus;
+ const EvaluationMode EvalMode;
+ const ConstantExprKind ConstexprKind;
+
+ bool InConstantContext = false;
+ bool CheckingPotentialConstantExpression = false;
+ bool CheckingForUndefinedBehavior = false;
+
+ EvalSettings(EvaluationMode EvalMode, Expr::EvalStatus &EvalStatus,
+ ConstantExprKind ConstexprKind = ConstantExprKind::Normal)
+ : EvalStatus(EvalStatus), EvalMode(EvalMode),
+ ConstexprKind(ConstexprKind) {}
+};
+
+} // namespace interp
+} // namespace clang
+
+#endif
diff --git a/clang/lib/AST/ByteCode/InterpState.cpp b/clang/lib/AST/ByteCode/InterpState.cpp
index 7d0364fa7d10d8..e69880d9e1a87e 100644
--- a/clang/lib/AST/ByteCode/InterpState.cpp
+++ b/clang/lib/AST/ByteCode/InterpState.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "InterpState.h"
+#include "EvalSettings.h"
#include "InterpFrame.h"
#include "InterpStack.h"
#include "Program.h"
@@ -30,19 +31,32 @@ InterpState::InterpState(const State &Parent, Program &P, InterpStack &Stk,
CheckingForUndefinedBehavior = Parent.CheckingForUndefinedBehavior;
EvalMode = Parent.EvalMode;
}
+InterpState::InterpState(const EvalSettings &Settings, Program &P,
+ InterpStack &Stk, FrameAllocator &FrameAlloc,
+ Context &Ctx, SourceMapper *M)
+ : State(Ctx.getASTContext(), Settings.EvalStatus), M(M),
+ FrameAlloc(FrameAlloc), P(P), Stk(Stk), Ctx(Ctx), BottomFrame(*this),
+ Current(&BottomFrame), StepsLeft(Ctx.getLangOpts().ConstexprStepLimit),
+ InfiniteSteps(StepsLeft == 0), EvalID(Ctx.getEvalID()) {
+ InConstantContext = Settings.InConstantContext;
+ CheckingPotentialConstantExpression =
+ Settings.CheckingPotentialConstantExpression;
+ CheckingForUndefinedBehavior = Settings.CheckingForUndefinedBehavior;
+ EvalMode = Settings.EvalMode;
+}
-InterpState::InterpState(const State &Parent, Program &P, InterpStack &Stk,
- FrameAllocator &FrameAlloc, Context &Ctx,
- const Function *Func)
- : State(Ctx.getASTContext(), Parent.getEvalStatus()), M(nullptr),
+InterpState::InterpState(const EvalSettings &Settings, Program &P,
+ InterpStack &Stk, FrameAllocator &FrameAlloc,
+ Context &Ctx, const Function *Func)
+ : State(Ctx.getASTContext(), Settings.EvalStatus), M(nullptr),
FrameAlloc(FrameAlloc), P(P), Stk(Stk), Ctx(Ctx), BottomFrame(*this),
Current(&BottomFrame), StepsLeft(Ctx.getLangOpts().ConstexprStepLimit),
InfiniteSteps(StepsLeft == 0), EvalID(Ctx.getEvalID()) {
- InConstantContext = Parent.InConstantContext;
+ InConstantContext = Settings.InConstantContext;
CheckingPotentialConstantExpression =
- Parent.CheckingPotentialConstantExpression;
- CheckingForUndefinedBehavior = Parent.CheckingForUndefinedBehavior;
- EvalMode = Parent.EvalMode;
+ Settings.CheckingPotentialConstantExpression;
+ CheckingForUndefinedBehavior = Settings.CheckingForUndefinedBehavior;
+ EvalMode = Settings.EvalMode;
}
InterpState::InterpState(Expr::EvalStatus &Status, Program &P, InterpStack &Stk,
diff --git a/clang/lib/AST/ByteCode/InterpState.h b/clang/lib/AST/ByteCode/InterpState.h
index b4f89e9583d972..eeb010ed216496 100644
--- a/clang/lib/AST/ByteCode/InterpState.h
+++ b/clang/lib/AST/ByteCode/InterpState.h
@@ -27,6 +27,7 @@ namespace clang {
namespace interp {
class Context;
class SourceMapper;
+struct EvalSettings;
struct StdAllocatorCaller {
@@ -48,8 +49,11 @@ class InterpState final : public State {
InterpState(const State &Parent, Program &P, InterpStack &Stk,
FrameAllocator &FrameAlloc, Context &Ctx,
SourceMapper *M = nullptr);
+ InterpState(const EvalSettings &Settings, Program &P, InterpStack &Stk,
+ FrameAllocator &FrameAlloc, Context &Ctx,
+ SourceMapper *M = nullptr);
- InterpState(const State &Parent, Program &P, InterpStack &Stk,
+ InterpState(const EvalSettings &Settings, Program &P, InterpStack &Stk,
FrameAllocator &FA, Context &Ctx, const Function *Func);
InterpState(Expr::EvalStatus &Status, Program &P, InterpStack &Stk,
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index dea859382918b0..f5e8fd40348d05 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -33,6 +33,7 @@
//===----------------------------------------------------------------------===//
#include "ByteCode/Context.h"
+#include "ByteCode/EvalSettings.h"
#include "ByteCode/Frame.h"
#include "ByteCode/State.h"
#include "ExprConstShared.h"
@@ -22001,16 +22002,18 @@ bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx,
"Expression evaluator can't be called on a dependent expression.");
ExprTimeTraceScope TimeScope(this, Ctx, "EvaluateAsLValue");
+
+ if (Ctx.getLangOpts().EnableNewConstInterp) {
+ interp::EvalSettings Settings(EvaluationMode::ConstantFold, Result);
+ Settings.InConstantContext = InConstantContext;
+ return Ctx.getInterpContext().evaluate(Settings, this, Result.Val);
+ }
+
EvalInfo Info(Ctx, Result, EvaluationMode::ConstantFold);
Info.InConstantContext = InConstantContext;
LValue LV;
CheckedTemporaries CheckedTemps;
- if (Info.EnableNewConstInterp) {
- return Info.Ctx.getInterpContext().evaluate(Info, this, Result.Val,
- ConstantExprKind::Normal);
- }
-
if (!EvaluateLValue(this, LV, Info) || !Info.discardCleanups() ||
Result.HasSideEffects ||
!CheckLValueConstantExpression(Info, getExprLoc(),
@@ -22056,13 +22059,17 @@ bool Expr::EvaluateAsConstantExpr(EvalResult &Result, const ASTContext &Ctx,
return true;
ExprTimeTraceScope TimeScope(this, Ctx, "EvaluateAsConstantExpr");
+ if (Ctx.getLangOpts().EnableNewConstInterp) {
+ interp::EvalSettings Settings(EvaluationMode::ConstantExpression, Result,
+ Kind);
+ Settings.InConstantContext = true;
+ return Ctx.getInterpContext().evaluate(Settings, this, Result.Val);
+ }
+
EvaluationMode EM = EvaluationMode::ConstantExpression;
EvalInfo Info(Ctx, Result, EM);
Info.InConstantContext = true;
- if (Info.EnableNewConstInterp)
- return Info.Ctx.getInterpContext().evaluate(Info, this, Result.Val, Kind);
-
// The type of the object we're initializing is 'const T' for a class NTTP.
QualType T = getType();
if (Kind == ConstantExprKind::ClassTemplateArgument)
@@ -22122,21 +22129,25 @@ bool Expr::EvaluateAsInitializer(const ASTContext &Ctx, const VarDecl *VD,
return Name;
});
- EvalInfo Info(Ctx, EStatus,
- (IsConstantInitialization &&
- (Ctx.getLangOpts().CPlusPlus || Ctx.getLangOpts().C23))
- ? EvaluationMode::ConstantExpression
- : EvaluationMode::ConstantFold);
- Info.setEvaluatingDecl(VD, EStatus.Val);
- Info.InConstantContext = IsConstantInitialization;
+ EvaluationMode EvalMode =
+ (IsConstantInitialization &&
+ (Ctx.getLangOpts().CPlusPlus || Ctx.getLangOpts().C23))
+ ? EvaluationMode::ConstantExpression
+ : EvaluationMode::ConstantFold;
+
+ if (Ctx.getLangOpts().EnableNewConstInterp) {
+ interp::EvalSettings Settings(EvalMode, EStatus);
+ Settings.InConstantContext = IsConstantInitialization;
+ return Ctx.getInterpContext().evaluateAsInitializer(Settings, VD, this,
+ EStatus.Val);
+ }
SourceLocation DeclLoc = VD->getLocation();
QualType DeclTy = VD->getType();
- if (Info.EnableNewConstInterp) {
- auto &InterpCtx = Ctx.getInterpContext();
- return InterpCtx.evaluateAsInitializer(Info, VD, this, EStatus.Val);
- }
+ EvalInfo Info(Ctx, EStatus, EvalMode);
+ Info.setEvaluatingDecl(VD, EStatus.Val);
+ Info.InConstantContext = IsConstantInitialization;
LValue LVal;
LVal.set(VD);
@@ -22202,11 +22213,12 @@ bool VarDecl::evaluateDestruction(
return false;
if (Ctx.getLangOpts().EnableNewConstInterp) {
- EvalInfo Info(Ctx, EStatus,
- IsConstantDestruction ? EvaluationMode::ConstantExpression
- : EvaluationMode::ConstantFold);
- Info.InConstantContext = IsConstantDestruction;
- if (!Ctx.getInterpContext().evaluateDestruction(Info, this,
+ interp::EvalSettings Settings(IsConstantDestruction
+ ? EvaluationMode::ConstantExpression
+ : EvaluationMode::ConstantFold,
+ EStatus);
+ Settings.InConstantContext = IsConstantDestruction;
+ if (!Ctx.getInterpContext().evaluateDestruction(Settings, this,
std::move(DestroyedValue)))
return false;
ensureEvaluatedStmt()->HasConstantDestruction = true;
@@ -22905,19 +22917,23 @@ bool Expr::EvaluateWithSubstitution(APValue &Value, ASTContext &Ctx,
});
Expr::EvalStatus Status;
- EvalInfo Info(Ctx, Status, EvaluationMode::ConstantExpressionUnevaluated);
- Info.InConstantContext = true;
- if (Info.EnableNewConstInterp) {
+ if (Ctx.getLangOpts().EnableNewConstInterp) {
+ interp::EvalSettings Settings(EvaluationMode::ConstantExpressionUnevaluated,
+ Status);
+ Settings.InConstantContext = true;
if (std::optional<bool> BoolResult =
- Info.Ctx.getInterpContext().evaluateWithSubstitution(
- Info, Callee, Args, This, this)) {
+ Ctx.getInterpContext().evaluateWithSubstitution(Settings, Callee,
+ Args, This, this)) {
Value = APValue(APSInt(APInt(1, static_cast<uint64_t>(*BoolResult))));
return true;
}
return false;
}
+ EvalInfo Info(Ctx, Status, EvaluationMode::ConstantExpressionUnevaluated);
+ Info.InConstantContext = true;
+
LValue ThisVal;
const LValue *ThisPtr = nullptr;
if (This) {
@@ -22988,20 +23004,23 @@ bool Expr::isPotentialConstantExpr(const FunctionDecl *FD,
return Name;
});
+ const ASTContext &Ctx = FD->getASTContext();
Expr::EvalStatus Status;
Status.Diag = &Diags;
- EvalInfo Info(FD->getASTContext(), Status,
- EvaluationMode::ConstantExpression);
- Info.InConstantContext = true;
- Info.CheckingPotentialConstantExpression = true;
-
// The constexpr VM attempts to compile all methods to bytecode here.
- if (Info.EnableNewConstInterp) {
- Info.Ctx.getInterpContext().isPotentialConstantExpr(Info, FD);
+ if (Ctx.getLangOpts().EnableNewConstInterp) {
+ interp::EvalSettings Settings(EvaluationMode::ConstantExpression, Status);
+ Settings.InConstantContext = true;
+ Settings.CheckingPotentialConstantExpression = true;
+ Ctx.getInterpContext().isPotentialConstantExpr(Settings, FD);
return Diags.empty();
}
+ EvalInfo Info(Ctx, Status, EvaluationMode::ConstantExpression);
+ Info.InConstantContext = true;
+ Info.CheckingPotentialConstantExpression = true;
+
const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD);
const CXXRecordDecl *RD = MD ? MD->getParent()->getCanonicalDecl() : nullptr;
@@ -23038,19 +23057,23 @@ bool Expr::isPotentialConstantExprUnevaluated(Expr *E,
assert(!E->isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");
+ const ASTContext &Ctx = FD->getASTContext();
Expr::EvalStatus Status;
Status.Diag = &Diags;
- EvalInfo Info(FD->getASTContext(), Status,
- EvaluationMode::ConstantExpressionUnevaluated);
- Info.InConstantContext = true;
- Info.CheckingPotentialConstantExpression = true;
-
- if (Info.EnableNewConstInterp) {
- Info.Ctx.getInterpContext().isPotentialConstantExprUnevaluated(Info, E, FD);
+ if (Ctx.getLangOpts().EnableNewConstInterp) {
+ interp::EvalSettings Settings(EvaluationMode::ConstantExpressionUnevaluated,
+ Status);
+ Settings.InConstantContext = true;
+ Settings.CheckingPotentialConstantExpression = true;
+ Ctx.getInterpContext().isPotentialConstantExprUnevaluated(Settings, E, FD);
return Diags.empty();
}
+ EvalInfo Info(Ctx, Status, EvaluationMode::ConstantExpressionUnevaluated);
+ Info.InConstantContext = true;
+ Info.CheckingPotentialConstantExpression = true;
+
// Fabricate a call stack frame to give the arguments a plausible cover story.
CallStackFrame Frame(Info, SourceLocation(), FD, /*This=*/nullptr,
/*CallExpr=*/nullptr, CallRef());
@@ -23066,12 +23089,13 @@ std::optional<uint64_t> Expr::tryEvaluateObjectSize(const ASTContext &Ctx,
return std::nullopt;
Expr::EvalStatus Status;
- EvalInfo Info(Ctx, Status, EvaluationMode::ConstantFold);
- if (Info.EnableNewConstInterp)
- return Info.Ctx.getInterpContext().tryEvaluateObjectSize(
- Info, this, Type,
- /*IsDynamic=*/false);
+ if (Ctx.getLangOpts().EnableNewConstInterp) {
+ interp::EvalSettings Settings(EvaluationMode::ConstantFold, Status);
+ return Ctx.getInterpContext().tryEvaluateObjectSize(Settings, this, Type,
+ /*IsDynamic=*/false);
+ }
+ EvalInfo Info(Ctx, Status, EvaluationMode::ConstantFold);
return tryEvaluateBuiltinObjectSize(this, Type, Info);
}
@@ -23122,15 +23146,16 @@ EvaluateBuiltinStrLen(const Expr *E, EvalInfo &Info,
std::optional<std::string> Expr::tryEvaluateString(ASTContext &Ctx) const {
Expr::EvalStatus Status;
- EvalInfo Info(Ctx, Status, EvaluationMode::ConstantFold);
std::string StringResult;
- if (Info.EnableNewConstInterp) {
- if (!Info.Ctx.getInterpContext().evaluateString(Info, this, StringResult))
+ if (Ctx.getLangOpts().EnableNewConstInterp) {
+ interp::EvalSettings Settings(EvaluationMode::ConstantFold, Status);
+ if (!Ctx.getInterpContext().evaluateString(Settings, this, StringResult))
return std::nullopt;
return StringResult;
}
+ EvalInfo Info(Ctx, Status, EvaluationMode::ConstantFold);
if (EvaluateBuiltinStrLen(this, Info, &StringResult))
return StringResult;
return std::nullopt;
@@ -23142,13 +23167,16 @@ static bool EvaluateCharRangeAsStringImpl(const Expr *, T &Result,
const Expr *PtrExpression,
ASTContext &Ctx,
Expr::EvalResult &Status) {
+ if (Ctx.getLangOpts().EnableNewConstInterp) {
+ interp::EvalSettings Settings(EvaluationMode::ConstantExpression, Status);
+ Settings.InConstantContext = true;
+ return Ctx.getInterpContext().evaluateCharRange(Settings, SizeExpression,
+ PtrExpression, Result);
+ }
+
EvalInfo Info(Ctx, Status, EvaluationMode::ConstantExpression);
Info.InConstantContext = true;
- if (Info.EnableNewConstInterp)
- return Info.Ctx.getInterpContext().evaluateCharRange(Info, SizeExpression,
- PtrExpression, Result);
-
LValue String;
FullExpressionRAII Scope(Info);
APSInt SizeValue;
@@ -23210,10 +23238,12 @@ bool Expr::EvaluateCharRangeAsString(APValue &Result,
std::optional<uint64_t> Expr::tryEvaluateStrLen(const ASTContext &Ctx) const {
Expr::EvalStatus Status;
- EvalInfo Info(Ctx, Status, EvaluationMode::ConstantFold);
- if (Info.EnableNewConstInterp)
- return Info.Ctx.getInterpContext().evaluateStrlen(Info, this);
+ if (Ctx.getLangOpts().EnableNewConstInterp) {
+ interp::EvalSettings Settings(EvaluationMode::ConstantFold, Status);
+ return Ctx.getInterpContext().evaluateStrlen(Settings, this);
+ }
+ EvalInfo Info(Ctx, Status, EvaluationMode::ConstantFold);
return EvaluateBuiltinStrLen(this, Info);
}
More information about the cfe-commits
mailing list