[clang] [clang][bytecode] Fix a diagnostic discrepancy (PR #177384)
Timm Baeder via cfe-commits
cfe-commits at lists.llvm.org
Thu Jan 22 07:52:55 PST 2026
https://github.com/tbaederr created https://github.com/llvm/llvm-project/pull/177384
The current interpreter does _not_ evaluate function calls when checking for a potential constant expression.
However, it _does_ evaluate the initializers of constructors. In the bytecode interpreter, this is harder because we compile the initializers and the body of a constructor all in the same function.
Add a special opcode that we emit after the constructor initializers and that aborts when we're checking for a potential constant expression.
>From 9d581a96fcc747d4df738967da9a6240efc04571 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Thu, 22 Jan 2026 16:40:06 +0100
Subject: [PATCH] asdfasdf
---
clang/lib/AST/ByteCode/Compiler.cpp | 7 ++++++-
clang/lib/AST/ByteCode/Interp.cpp | 11 +++++------
clang/lib/AST/ByteCode/Interp.h | 10 ++++++++++
clang/lib/AST/ByteCode/Opcodes.td | 2 ++
clang/test/AST/ByteCode/functions.cpp | 24 ++++++++++++++++++++++++
5 files changed, 47 insertions(+), 7 deletions(-)
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index bbc0f5058e6f9..5b276fedfeeaf 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -6468,10 +6468,15 @@ bool Compiler<Emitter>::compileConstructor(const CXXConstructorDecl *Ctor) {
if (!Scope.destroyLocals())
return false;
}
+ if (const auto *Body = cast_if_present<CompoundStmt>(Ctor->getBody());
+ Body && !Body->body_empty()) {
+
+ if (!this->emitCtorCheck(SourceInfo{}))
+ return false;
- if (const auto *Body = Ctor->getBody())
if (!visitStmt(Body))
return false;
+ }
return this->emitRetVoid(SourceInfo{});
}
diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp
index 4a98de1e75ecc..49c23e59cb0e0 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -1671,12 +1671,11 @@ bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
if (!CheckCallable(S, OpPC, Func))
return cleanup();
- // FIXME: The isConstructor() check here is not always right. The current
- // constant evaluator is somewhat inconsistent in when it allows a function
- // call when checking for a constant expression.
- if (Func->hasThisPointer() && S.checkingPotentialConstantExpression() &&
- !Func->isConstructor())
- return cleanup();
+ // Do not evaluate any function calls in checkingPotentialConstantExpression
+ // mode. Constructors will be aborted later when their initializers are
+ // evaluated.
+ if (S.checkingPotentialConstantExpression() && !Func->isConstructor())
+ return false;
if (!CheckCallDepth(S, OpPC))
return cleanup();
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index 2d8cccb8095a4..92e8266aa172b 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -3297,6 +3297,16 @@ inline bool SideEffect(InterpState &S, CodePtr OpPC) {
return S.noteSideEffect();
}
+/// Abort without a diagnostic if we're checking for a potential constant
+/// expression and this is not the bottom frame. This is used in constructors to
+/// allow evaluating their initializers but abort if we encounter anything in
+/// their body.
+inline bool CtorCheck(InterpState &S, CodePtr OpPC) {
+ if (S.checkingPotentialConstantExpression() && !S.Current->isBottomFrame())
+ return false;
+ return true;
+}
+
inline bool CheckBitCast(InterpState &S, CodePtr OpPC, const Type *TargetType,
bool SrcIsVoidPtr) {
const auto &Ptr = S.Stk.peek<Pointer>();
diff --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td
index 6e768793fcfcf..c3123410d06fe 100644
--- a/clang/lib/AST/ByteCode/Opcodes.td
+++ b/clang/lib/AST/ByteCode/Opcodes.td
@@ -923,5 +923,7 @@ def DiagTypeid : Opcode;
def CheckDestruction : Opcode;
+def CtorCheck : Opcode;
+
def PushCC : Opcode { let Args = [ArgBool]; }
def PopCC : Opcode;
diff --git a/clang/test/AST/ByteCode/functions.cpp b/clang/test/AST/ByteCode/functions.cpp
index 21d3ddaafaee3..6d3c03cc1e348 100644
--- a/clang/test/AST/ByteCode/functions.cpp
+++ b/clang/test/AST/ByteCode/functions.cpp
@@ -735,3 +735,27 @@ namespace PtrPtrCast {
void foo() { ; }
void bar(int *a) { a = (int *)(void *)(foo); }
}
+
+namespace NestedDiags {
+ constexpr int foo() { // both-error {{never produces a constant expression}}
+ throw; // both-note {{not valid in a constant expression}} \
+ // both-error {{cannot use 'throw' with exceptions disabled}}
+ return 0;
+ }
+ constexpr int bar() {
+ foo();
+ return 0;
+ }
+
+
+ struct S {
+ constexpr S() { // both-error {{never produces a constant expression}}
+ throw; // both-note {{not valid in a constant expression}} \
+ // both-error {{cannot use 'throw' with exceptions disabled}}
+ }
+ };
+ constexpr bool callS() {
+ S s;
+ return true;
+ }
+}
More information about the cfe-commits
mailing list