Skip to content

Commit a024a0c

Browse files
authored
[clang][bytecode] Override InConstantContext flag for immediate calls (#109967)
And fix the diagnostics for __builtin_is_constant_evaluated(). We can be in a non-constant context, but calling an immediate function always makes the context constant for the duration of that call.
1 parent 3be8e3a commit a024a0c

File tree

5 files changed

+47
-8
lines changed

5 files changed

+47
-8
lines changed

clang/lib/AST/ByteCode/Interp.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1136,6 +1136,7 @@ bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
11361136
InterpFrame *FrameBefore = S.Current;
11371137
S.Current = NewFrame.get();
11381138

1139+
InterpStateCCOverride CCOverride(S, Func->getDecl()->isImmediateFunction());
11391140
APValue CallResult;
11401141
// Note that we cannot assert(CallResult.hasValue()) here since
11411142
// Ret() above only sets the APValue if the curent frame doesn't

clang/lib/AST/ByteCode/InterpBuiltin.cpp

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -136,16 +136,17 @@ static bool retPrimValue(InterpState &S, CodePtr OpPC, APValue &Result,
136136
static bool interp__builtin_is_constant_evaluated(InterpState &S, CodePtr OpPC,
137137
const InterpFrame *Frame,
138138
const CallExpr *Call) {
139+
unsigned Depth = S.Current->getDepth();
140+
auto isStdCall = [](const FunctionDecl *F) -> bool {
141+
return F && F->isInStdNamespace() && F->getIdentifier() &&
142+
F->getIdentifier()->isStr("is_constant_evaluated");
143+
};
144+
const InterpFrame *Caller = Frame->Caller;
139145
// The current frame is the one for __builtin_is_constant_evaluated.
140146
// The one above that, potentially the one for std::is_constant_evaluated().
141147
if (S.inConstantContext() && !S.checkingPotentialConstantExpression() &&
142-
Frame->Caller && S.getEvalStatus().Diag) {
143-
auto isStdCall = [](const FunctionDecl *F) -> bool {
144-
return F && F->isInStdNamespace() && F->getIdentifier() &&
145-
F->getIdentifier()->isStr("is_constant_evaluated");
146-
};
147-
const InterpFrame *Caller = Frame->Caller;
148-
148+
S.getEvalStatus().Diag &&
149+
(Depth == 1 || (Depth == 2 && isStdCall(Caller->getCallee())))) {
149150
if (Caller->Caller && isStdCall(Caller->getCallee())) {
150151
const Expr *E = Caller->Caller->getExpr(Caller->getRetPC());
151152
S.report(E->getExprLoc(),

clang/lib/AST/ByteCode/InterpState.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,13 @@ InterpState::InterpState(State &Parent, Program &P, InterpStack &Stk,
1919
Context &Ctx, SourceMapper *M)
2020
: Parent(Parent), M(M), P(P), Stk(Stk), Ctx(Ctx), Current(nullptr) {}
2121

22+
bool InterpState::inConstantContext() const {
23+
if (ConstantContextOverride)
24+
return *ConstantContextOverride;
25+
26+
return Parent.InConstantContext;
27+
}
28+
2229
InterpState::~InterpState() {
2330
while (Current) {
2431
InterpFrame *Next = Current->Caller;

clang/lib/AST/ByteCode/InterpState.h

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ class InterpState final : public State, public SourceMapper {
7777
bool noteUndefinedBehavior() override {
7878
return Parent.noteUndefinedBehavior();
7979
}
80-
bool inConstantContext() const { return Parent.InConstantContext; }
80+
bool inConstantContext() const;
8181
bool hasActiveDiagnostic() override { return Parent.hasActiveDiagnostic(); }
8282
void setActiveDiagnostic(bool Flag) override {
8383
Parent.setActiveDiagnostic(Flag);
@@ -116,6 +116,7 @@ class InterpState final : public State, public SourceMapper {
116116

117117
private:
118118
friend class EvaluationResult;
119+
friend class InterpStateCCOverride;
119120
/// AST Walker state.
120121
State &Parent;
121122
/// Dead block chain.
@@ -124,6 +125,7 @@ class InterpState final : public State, public SourceMapper {
124125
SourceMapper *M;
125126
/// Allocator used for dynamic allocations performed via the program.
126127
DynamicAllocator Alloc;
128+
std::optional<bool> ConstantContextOverride;
127129

128130
public:
129131
/// Reference to the module containing all bytecode.
@@ -144,6 +146,26 @@ class InterpState final : public State, public SourceMapper {
144146
SeenGlobalTemporaries;
145147
};
146148

149+
class InterpStateCCOverride final {
150+
public:
151+
InterpStateCCOverride(InterpState &Ctx, bool Value)
152+
: Ctx(Ctx), OldCC(Ctx.ConstantContextOverride) {
153+
// We only override this if the new value is true.
154+
Enabled = Value;
155+
if (Enabled)
156+
Ctx.ConstantContextOverride = Value;
157+
}
158+
~InterpStateCCOverride() {
159+
if (Enabled)
160+
Ctx.ConstantContextOverride = OldCC;
161+
}
162+
163+
private:
164+
bool Enabled;
165+
InterpState &Ctx;
166+
std::optional<bool> OldCC;
167+
};
168+
147169
} // namespace interp
148170
} // namespace clang
149171

clang/test/CodeGenCXX/cxx2a-consteval.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,14 @@
66
// RUN: %clang_cc1 -emit-llvm %s -Dconsteval="" -std=c++2a -triple x86_64-unknown-linux-gnu -o %t.ll
77
// RUN: FileCheck -check-prefix=EXPR -input-file=%t.ll %s
88

9+
// RUN: %clang_cc1 -emit-llvm %s -std=c++2a -triple x86_64-unknown-linux-gnu -o %t.ll -fexperimental-new-constant-interpreter
10+
// RUN: FileCheck -check-prefix=EVAL -input-file=%t.ll %s
11+
// RUN: FileCheck -check-prefix=EVAL-STATIC -input-file=%t.ll %s
12+
// RUN: FileCheck -check-prefix=EVAL-FN -input-file=%t.ll %s
13+
//
14+
// RUN: %clang_cc1 -emit-llvm %s -Dconsteval="" -std=c++2a -triple x86_64-unknown-linux-gnu -o %t.ll -fexperimental-new-constant-interpreter
15+
// RUN: FileCheck -check-prefix=EXPR -input-file=%t.ll %s
16+
917
// there is two version of symbol checks to ensure
1018
// that the symbol we are looking for are correct
1119
// EVAL-NOT: @__cxx_global_var_init()

0 commit comments

Comments
 (0)