[clang] [clang][bytecode] Fix a diagnostic discrepancy (PR #177384)
Timm Baeder via cfe-commits
cfe-commits at lists.llvm.org
Thu Jan 22 21:51:58 PST 2026
Timm =?utf-8?q?Bäder?= <tbaeder at redhat.com>
Message-ID:
In-Reply-To: <llvm.org/llvm/llvm-project/pull/177384 at github.com>
https://github.com/tbaederr updated https://github.com/llvm/llvm-project/pull/177384
>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 1/2] 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;
+ }
+}
>From 5aa7e88038d3901763bea81a0b063f5092ffdeda Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Fri, 23 Jan 2026 06:51:31 +0100
Subject: [PATCH 2/2] Emit CtorCheck op also for non-CompundStmt bodies
---
clang/lib/AST/ByteCode/Compiler.cpp | 14 ++++++++++----
clang/test/AST/ByteCode/cxx23.cpp | 15 +++++++++++++++
2 files changed, 25 insertions(+), 4 deletions(-)
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index 5b276fedfeeaf..236f79c002301 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -6468,11 +6468,17 @@ 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 Stmt *Body = Ctor->getBody()) {
+ // Only emit the CtorCheck op for non-empty CompoundStmt bodies.
+ // For non-CompoundStmts, always assume they are non-empty and emit it.
+ if (const auto *CS = dyn_cast<CompoundStmt>(Body)) {
+ if (!CS->body_empty() && !this->emitCtorCheck(SourceInfo{}))
+ return false;
+ } else {
+ if (!this->emitCtorCheck(SourceInfo{}))
+ return false;
+ }
if (!visitStmt(Body))
return false;
diff --git a/clang/test/AST/ByteCode/cxx23.cpp b/clang/test/AST/ByteCode/cxx23.cpp
index 8139451400cae..e3be7887c357e 100644
--- a/clang/test/AST/ByteCode/cxx23.cpp
+++ b/clang/test/AST/ByteCode/cxx23.cpp
@@ -579,3 +579,18 @@ namespace UnknownParams {
return 1;
}
}
+
+namespace NonCompoundStmtBody {
+ /// The body of the constructor is NOT a CompoundStmt.
+ struct S {
+ constexpr S() try { x = 20; } catch(...) {}
+
+ int x = 0;
+ };
+
+ constexpr bool testS() {
+ S s;
+ return s.x == 20;
+ }
+ static_assert(testS());
+}
More information about the cfe-commits
mailing list