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
