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?= <[email protected]>
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;
+  }
+}

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to