Skip to content

[clang][bytecode] Enter a non-constant context when revisiting #136104

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions clang/lib/AST/ByteCode/Compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6466,8 +6466,13 @@ bool Compiler<Emitter>::visitDeclRef(const ValueDecl *D, const Expr *E) {

// In case we need to re-visit a declaration.
auto revisit = [&](const VarDecl *VD) -> bool {
if (!this->emitPushCC(VD->hasConstantInitialization(), E))
return false;
auto VarState = this->visitDecl(VD, /*IsConstexprUnknown=*/true);

if (!this->emitPopCC(E))
return false;

if (VarState.notCreated())
return true;
if (!VarState)
Expand Down
9 changes: 9 additions & 0 deletions clang/lib/AST/ByteCode/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -2848,6 +2848,15 @@ inline bool EndSpeculation(InterpState &S, CodePtr OpPC) {
return true;
}

inline bool PushCC(InterpState &S, CodePtr OpPC, bool Value) {
S.ConstantContextOverride = Value;
return true;
}
inline bool PopCC(InterpState &S, CodePtr OpPC) {
S.ConstantContextOverride = std::nullopt;
return true;
}

/// Do nothing and just abort execution.
inline bool Error(InterpState &S, CodePtr OpPC) { return false; }

Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/ByteCode/InterpState.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,6 @@ class InterpState final : public State, public SourceMapper {
SourceMapper *M;
/// Allocator used for dynamic allocations performed via the program.
DynamicAllocator Alloc;
std::optional<bool> ConstantContextOverride;

public:
/// Reference to the module containing all bytecode.
Expand All @@ -147,6 +146,7 @@ class InterpState final : public State, public SourceMapper {
/// Things needed to do speculative execution.
SmallVectorImpl<PartialDiagnosticAt> *PrevDiags = nullptr;
unsigned SpeculationDepth = 0;
std::optional<bool> ConstantContextOverride;

llvm::SmallVector<
std::pair<const Expr *, const LifetimeExtendedTemporaryDecl *>>
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/AST/ByteCode/Opcodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -872,3 +872,6 @@ def GetTypeidPtr : Opcode { let Args = [ArgTypePtr]; }
def DiagTypeid : Opcode;

def CheckDestruction : Opcode;

def PushCC : Opcode { let Args = [ArgBool]; }
def PopCC : Opcode;
8 changes: 8 additions & 0 deletions clang/test/AST/ByteCode/builtin-constant-p.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,11 @@ constexpr int mutate6(bool mutate) {
static_assert(mutate6(false) == 11);
static_assert(mutate6(true) == 21); // ref-error {{static assertion failed}} \
// ref-note {{evaluates to '10 == 21'}}

#define fold(x) (__builtin_constant_p(x) ? (x) : (x))
void g() {
/// f will be revisited when evaluating the static_assert, since it's
/// a local variable. But it should be visited in a non-constant context.
const float f = __builtin_is_constant_evaluated();
static_assert(fold(f == 0.0f));
}
Loading