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

Reply via email to