https://github.com/tbaederr updated https://github.com/llvm/llvm-project/pull/149462
>From 216f90bd097904c4f12f7a493b2b0eaeba6b9261 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbae...@redhat.com> Date: Fri, 18 Jul 2025 08:24:49 +0200 Subject: [PATCH] [clang][bytecode] Use bytecode interprete in isPotentialConstantExprUnevaluated Fake a function call to the given function and evaluate the given expression as if it was part of that function call. --- clang/lib/AST/ByteCode/Compiler.cpp | 5 +++++ clang/lib/AST/ByteCode/Context.cpp | 14 ++++++++++++++ clang/lib/AST/ByteCode/Context.h | 4 +++- clang/lib/AST/ByteCode/EvalEmitter.cpp | 13 +++++++++++++ clang/lib/AST/ByteCode/EvalEmitter.h | 3 +++ clang/lib/AST/ByteCode/Interp.cpp | 6 +++++- clang/lib/AST/ExprConstant.cpp | 5 +++++ clang/test/Sema/diagnose_if.c | 1 + clang/test/SemaCXX/diagnose_if-ext.cpp | 1 + clang/test/SemaCXX/diagnose_if.cpp | 1 + 10 files changed, 51 insertions(+), 2 deletions(-) diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index ea473730350b6..65ad7caf8913b 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -6670,6 +6670,11 @@ bool Compiler<Emitter>::visitDeclRef(const ValueDecl *D, const Expr *E) { } // Function parameters. if (const auto *PVD = dyn_cast<ParmVarDecl>(D)) { + if (Ctx.getLangOpts().CPlusPlus && !Ctx.getLangOpts().CPlusPlus11 && + !D->getType()->isIntegralOrEnumerationType()) { + return this->emitInvalidDeclRef(cast<DeclRefExpr>(E), + /*InitializerFailed=*/false, E); + } if (auto It = this->Params.find(PVD); It != this->Params.end()) { if (IsReference || !It->second.IsPtr) return this->emitGetParam(classifyPrim(E), It->second.Offset, E); diff --git a/clang/lib/AST/ByteCode/Context.cpp b/clang/lib/AST/ByteCode/Context.cpp index a629ff9569428..d8a3368c9d885 100644 --- a/clang/lib/AST/ByteCode/Context.cpp +++ b/clang/lib/AST/ByteCode/Context.cpp @@ -52,6 +52,20 @@ bool Context::isPotentialConstantExpr(State &Parent, const FunctionDecl *FD) { return Func->isValid(); } +bool Context::isPotentialConstantExprUnevaluated(State &Parent, const Expr *E, + const FunctionDecl *FD) { + assert(Stk.empty()); + ++EvalID; + size_t StackSizeBefore = Stk.size(); + Compiler<EvalEmitter> C(*this, *P, Parent, Stk); + + if (!C.interpretCall(FD, E)) { + C.cleanup(); + Stk.clearTo(StackSizeBefore); + } + return true; +} + bool Context::evaluateAsRValue(State &Parent, const Expr *E, APValue &Result) { ++EvalID; bool Recursing = !Stk.empty(); diff --git a/clang/lib/AST/ByteCode/Context.h b/clang/lib/AST/ByteCode/Context.h index 5898ab5e54599..6ab526cec0144 100644 --- a/clang/lib/AST/ByteCode/Context.h +++ b/clang/lib/AST/ByteCode/Context.h @@ -47,7 +47,9 @@ class Context final { ~Context(); /// Checks if a function is a potential constant expression. - bool isPotentialConstantExpr(State &Parent, const FunctionDecl *FnDecl); + bool isPotentialConstantExpr(State &Parent, const FunctionDecl *FD); + bool isPotentialConstantExprUnevaluated(State &Parent, const Expr *E, + const FunctionDecl *FD); /// Evaluates a toplevel expression as an rvalue. bool evaluateAsRValue(State &Parent, const Expr *E, APValue &Result); diff --git a/clang/lib/AST/ByteCode/EvalEmitter.cpp b/clang/lib/AST/ByteCode/EvalEmitter.cpp index 5498065657e0a..6e511bc7d2fab 100644 --- a/clang/lib/AST/ByteCode/EvalEmitter.cpp +++ b/clang/lib/AST/ByteCode/EvalEmitter.cpp @@ -90,6 +90,19 @@ EvaluationResult EvalEmitter::interpretAsPointer(const Expr *E, return std::move(this->EvalResult); } +bool EvalEmitter::interpretCall(const FunctionDecl *FD, const Expr *E) { + // Add parameters to the parameter map. The values in the ParamOffset don't + // matter in this case as reading from them can't ever work. + for (const ParmVarDecl *PD : FD->parameters()) { + this->Params.insert({PD, {0, false}}); + } + + if (!this->visit(E)) + return false; + PrimType T = Ctx.classify(E).value_or(PT_Ptr); + return this->emitPop(T, E); +} + void EvalEmitter::emitLabel(LabelTy Label) { CurrentLabel = Label; } EvalEmitter::LabelTy EvalEmitter::getLabel() { return NextLabel++; } diff --git a/clang/lib/AST/ByteCode/EvalEmitter.h b/clang/lib/AST/ByteCode/EvalEmitter.h index 7303adba22af7..2fe7da608c739 100644 --- a/clang/lib/AST/ByteCode/EvalEmitter.h +++ b/clang/lib/AST/ByteCode/EvalEmitter.h @@ -40,6 +40,9 @@ class EvalEmitter : public SourceMapper { EvaluationResult interpretDecl(const VarDecl *VD, bool CheckFullyInitialized); /// Interpret the given Expr to a Pointer. EvaluationResult interpretAsPointer(const Expr *E, PtrCallback PtrCB); + /// Interpret the given expression as if it was in the body of the given + /// function, i.e. the parameters of the function are available for use. + bool interpretCall(const FunctionDecl *FD, const Expr *E); /// Clean up all resources. void cleanup(); diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp index e8b519478c026..fe27ecd33d98b 100644 --- a/clang/lib/AST/ByteCode/Interp.cpp +++ b/clang/lib/AST/ByteCode/Interp.cpp @@ -142,8 +142,12 @@ static bool diagnoseUnknownDecl(InterpState &S, CodePtr OpPC, return false; if (isa<ParmVarDecl>(D)) { - if (D->getType()->isReferenceType()) + if (D->getType()->isReferenceType()) { + if (S.inConstantContext() && S.getLangOpts().CPlusPlus && + !S.getLangOpts().CPlusPlus11) + diagnoseNonConstVariable(S, OpPC, D); return false; + } const SourceInfo &Loc = S.Current->getSource(OpPC); if (S.getLangOpts().CPlusPlus11) { diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 767cc4c3b19eb..6a5dc7a81f4a8 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -18015,6 +18015,11 @@ bool Expr::isPotentialConstantExprUnevaluated(Expr *E, Info.InConstantContext = true; Info.CheckingPotentialConstantExpression = true; + if (Info.EnableNewConstInterp) { + Info.Ctx.getInterpContext().isPotentialConstantExprUnevaluated(Info, E, FD); + return Diags.empty(); + } + // Fabricate a call stack frame to give the arguments a plausible cover story. CallStackFrame Frame(Info, SourceLocation(), FD, /*This=*/nullptr, /*CallExpr=*/nullptr, CallRef()); diff --git a/clang/test/Sema/diagnose_if.c b/clang/test/Sema/diagnose_if.c index e9b8497d5ca4e..a4cf43e9c869f 100644 --- a/clang/test/Sema/diagnose_if.c +++ b/clang/test/Sema/diagnose_if.c @@ -1,4 +1,5 @@ // RUN: %clang_cc1 %s -verify -fno-builtin +// RUN: %clang_cc1 %s -verify -fno-builtin -fexperimental-new-constant-interpreter #define _diagnose_if(...) __attribute__((diagnose_if(__VA_ARGS__))) diff --git a/clang/test/SemaCXX/diagnose_if-ext.cpp b/clang/test/SemaCXX/diagnose_if-ext.cpp index d5625b501322e..e0f73976eea3a 100644 --- a/clang/test/SemaCXX/diagnose_if-ext.cpp +++ b/clang/test/SemaCXX/diagnose_if-ext.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -Wpedantic -fsyntax-only %s -verify +// RUN: %clang_cc1 -Wpedantic -fsyntax-only %s -verify -fexperimental-new-constant-interpreter void foo() __attribute__((diagnose_if(1, "", "error"))); // expected-warning{{'diagnose_if' is a clang extension}} void foo(int a) __attribute__((diagnose_if(a, "", "error"))); // expected-warning{{'diagnose_if' is a clang extension}} diff --git a/clang/test/SemaCXX/diagnose_if.cpp b/clang/test/SemaCXX/diagnose_if.cpp index 21897c5184b73..1b9e660c4e224 100644 --- a/clang/test/SemaCXX/diagnose_if.cpp +++ b/clang/test/SemaCXX/diagnose_if.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 %s -verify -fno-builtin -std=c++14 +// RUN: %clang_cc1 %s -verify -fno-builtin -std=c++14 -fexperimental-new-constant-interpreter #define _diagnose_if(...) __attribute__((diagnose_if(__VA_ARGS__))) _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits