https://github.com/tbaederr created 
https://github.com/llvm/llvm-project/pull/152909

This results in diagnostics that are closer to what the current interpreter 
produces.

>From 711115ab80b6957d09ac8dd7a4fac1a32f3b3744 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbae...@redhat.com>
Date: Sun, 10 Aug 2025 13:05:49 +0200
Subject: [PATCH] [clang][bytecode] Use Param decl as variable source if we can

This results in diagnostics that are closer to what the current
interpreter produces.
---
 clang/lib/AST/ByteCode/Compiler.cpp           | 40 +++++++++----------
 clang/lib/AST/ByteCode/Compiler.h             |  2 +-
 clang/test/AST/ByteCode/cxx23.cpp             |  5 +--
 clang/test/AST/ByteCode/lifetimes.cpp         |  9 ++---
 .../test/SemaCXX/cxx23-invalid-constexpr.cpp  |  1 +
 5 files changed, 28 insertions(+), 29 deletions(-)

diff --git a/clang/lib/AST/ByteCode/Compiler.cpp 
b/clang/lib/AST/ByteCode/Compiler.cpp
index f131ac17c11bb..5275b86a57a47 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -2062,12 +2062,16 @@ bool Compiler<Emitter>::visitArrayElemInit(unsigned 
ElemIndex, const Expr *Init,
 template <class Emitter>
 bool Compiler<Emitter>::visitCallArgs(ArrayRef<const Expr *> Args,
                                       const FunctionDecl *FuncDecl,
-                                      bool Activate) {
+                                      bool Activate, bool IsOperatorCall) {
   assert(VarScope->getKind() == ScopeKind::Call);
   llvm::BitVector NonNullArgs;
   if (FuncDecl && FuncDecl->hasAttr<NonNullAttr>())
     NonNullArgs = collectNonNullArgs(FuncDecl, Args);
 
+  bool ExplicitMemberFn = false;
+  if (const auto *MD = dyn_cast_if_present<CXXMethodDecl>(FuncDecl))
+    ExplicitMemberFn = MD->isExplicitObjectMemberFunction();
+
   unsigned ArgIndex = 0;
   for (const Expr *Arg : Args) {
     if (canClassify(Arg)) {
@@ -2075,8 +2079,19 @@ bool Compiler<Emitter>::visitCallArgs(ArrayRef<const 
Expr *> Args,
         return false;
     } else {
 
-      std::optional<unsigned> LocalIndex = allocateLocal(
-          Arg, Arg->getType(), /*ExtendingDecl=*/nullptr, ScopeKind::Call);
+      DeclTy Source = Arg;
+      if (FuncDecl) {
+        // Try to use the parameter declaration instead of the argument
+        // expression as a source.
+        unsigned DeclIndex = ArgIndex - IsOperatorCall + ExplicitMemberFn;
+        if (DeclIndex < FuncDecl->getNumParams())
+          Source = FuncDecl->getParamDecl(ArgIndex - IsOperatorCall +
+                                          ExplicitMemberFn);
+      }
+
+      std::optional<unsigned> LocalIndex =
+          allocateLocal(std::move(Source), Arg->getType(),
+                        /*ExtendingDecl=*/nullptr, ScopeKind::Call);
       if (!LocalIndex)
         return false;
 
@@ -4489,14 +4504,6 @@ template <class Emitter>
 unsigned Compiler<Emitter>::allocateLocalPrimitive(
     DeclTy &&Src, PrimType Ty, bool IsConst, const ValueDecl *ExtendingDecl,
     ScopeKind SC, bool IsConstexprUnknown) {
-  // Make sure we don't accidentally register the same decl twice.
-  if (const auto *VD =
-          dyn_cast_if_present<ValueDecl>(Src.dyn_cast<const Decl *>())) {
-    assert(!P.getGlobal(VD));
-    assert(!Locals.contains(VD));
-    (void)VD;
-  }
-
   // FIXME: There are cases where Src.is<Expr*>() is wrong, e.g.
   //   (int){12} in C. Consider using Expr::isTemporaryObject() instead
   //   or isa<MaterializeTemporaryExpr>().
@@ -4518,19 +4525,11 @@ std::optional<unsigned>
 Compiler<Emitter>::allocateLocal(DeclTy &&Src, QualType Ty,
                                  const ValueDecl *ExtendingDecl, ScopeKind SC,
                                  bool IsConstexprUnknown) {
-  // Make sure we don't accidentally register the same decl twice.
-  if ([[maybe_unused]] const auto *VD =
-          dyn_cast_if_present<ValueDecl>(Src.dyn_cast<const Decl *>())) {
-    assert(!P.getGlobal(VD));
-    assert(!Locals.contains(VD));
-  }
-
   const ValueDecl *Key = nullptr;
   const Expr *Init = nullptr;
   bool IsTemporary = false;
   if (auto *VD = dyn_cast_if_present<ValueDecl>(Src.dyn_cast<const Decl *>())) 
{
     Key = VD;
-    Ty = VD->getType();
 
     if (const auto *VarD = dyn_cast<VarDecl>(VD))
       Init = VarD->getInit();
@@ -5167,7 +5166,8 @@ bool Compiler<Emitter>::VisitCallExpr(const CallExpr *E) {
       return false;
   }
 
-  if (!this->visitCallArgs(Args, FuncDecl, IsAssignmentOperatorCall))
+  if (!this->visitCallArgs(Args, FuncDecl, IsAssignmentOperatorCall,
+                           isa<CXXOperatorCallExpr>(E)))
     return false;
 
   // Undo the argument reversal we did earlier.
diff --git a/clang/lib/AST/ByteCode/Compiler.h 
b/clang/lib/AST/ByteCode/Compiler.h
index d72ffa13f6b9d..901934e530ade 100644
--- a/clang/lib/AST/ByteCode/Compiler.h
+++ b/clang/lib/AST/ByteCode/Compiler.h
@@ -306,7 +306,7 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, 
bool>,
   bool visitArrayElemInit(unsigned ElemIndex, const Expr *Init,
                           OptPrimType InitT);
   bool visitCallArgs(ArrayRef<const Expr *> Args, const FunctionDecl *FuncDecl,
-                     bool Activate);
+                     bool Activate, bool IsOperatorCall);
 
   /// Creates a local primitive value.
   unsigned allocateLocalPrimitive(DeclTy &&Decl, PrimType Ty, bool IsConst,
diff --git a/clang/test/AST/ByteCode/cxx23.cpp 
b/clang/test/AST/ByteCode/cxx23.cpp
index 45dd4f528aefb..2182d7c4e4325 100644
--- a/clang/test/AST/ByteCode/cxx23.cpp
+++ b/clang/test/AST/ByteCode/cxx23.cpp
@@ -309,15 +309,14 @@ namespace NonLiteralDtorInParam {
     ~NonLiteral() {} // all23-note {{declared here}}
   };
   constexpr int F2(NonLiteral N) { // all20-error {{constexpr function's 1st 
parameter type 'NonLiteral' is not a literal type}} \
-                                   // ref23-note {{non-constexpr function 
'~NonLiteral' cannot be used in a constant expression}}
+                                   // all23-note {{non-constexpr function 
'~NonLiteral' cannot be used in a constant expression}}
     return 8;
   }
 
 
   void test() {
     NonLiteral L;
-    constexpr auto D = F2(L); // all23-error {{must be initialized by a 
constant expression}} \
-                              // expected23-note {{non-constexpr function 
'~NonLiteral' cannot be used in a constant expression}}
+    constexpr auto D = F2(L); // all23-error {{must be initialized by a 
constant expression}}
   }
 }
 
diff --git a/clang/test/AST/ByteCode/lifetimes.cpp 
b/clang/test/AST/ByteCode/lifetimes.cpp
index 5c8d56291f079..c8bf02c228481 100644
--- a/clang/test/AST/ByteCode/lifetimes.cpp
+++ b/clang/test/AST/ByteCode/lifetimes.cpp
@@ -94,14 +94,13 @@ namespace CallScope {
     int n = 0;
     constexpr int f() const { return 0; }
   };
-  constexpr Q *out_of_lifetime(Q q) { return &q; } // both-warning {{address 
of stack}}
+  constexpr Q *out_of_lifetime(Q q) { return &q; } // both-warning {{address 
of stack}} \
+                                                   // expected-note 
2{{declared here}}
   constexpr int k3 = out_of_lifetime({})->n; // both-error {{must be 
initialized by a constant expression}} \
-                                             // expected-note {{read of 
temporary whose lifetime has ended}} \
-                                             // expected-note {{temporary 
created here}} \
+                                             // expected-note {{read of 
variable whose lifetime has ended}} \
                                              // ref-note {{read of object 
outside its lifetime}}
 
   constexpr int k4 = out_of_lifetime({})->f(); // both-error {{must be 
initialized by a constant expression}} \
-                                               // expected-note {{member call 
on temporary whose lifetime has ended}} \
-                                               // expected-note {{temporary 
created here}} \
+                                               // expected-note {{member call 
on variable whose lifetime has ended}} \
                                                // ref-note {{member call on 
object outside its lifetime}}
 }
diff --git a/clang/test/SemaCXX/cxx23-invalid-constexpr.cpp 
b/clang/test/SemaCXX/cxx23-invalid-constexpr.cpp
index 3229a91fbcefb..1c832e51c2cbc 100644
--- a/clang/test/SemaCXX/cxx23-invalid-constexpr.cpp
+++ b/clang/test/SemaCXX/cxx23-invalid-constexpr.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -fsyntax-only -verify=expected -std=c++23 %s
+// RUN: %clang_cc1 -fsyntax-only -verify=expected -std=c++23 %s 
-fexperimental-new-constant-interpreter
 
 // This test covers modifications made by P2448R2.
 

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to