[clang] [Clang] Treat constexpr-unknown value as invalid in `evaluateValue` (PR #128409)

Yingwei Zheng via cfe-commits cfe-commits at lists.llvm.org
Wed Feb 26 08:08:02 PST 2025


https://github.com/dtcxzyw updated https://github.com/llvm/llvm-project/pull/128409

>From 83248eb164ff53442ad6d0c9d1be20027519bac1 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Tue, 18 Feb 2025 01:26:26 +0800
Subject: [PATCH 1/5] [Clang][CodeGen] Bail out on constexpr unknown values in
 ConstantEmitter

---
 clang/lib/CodeGen/CGExprConstant.cpp    |  6 ++++--
 clang/test/CodeGenCXX/cxx23-p2280r4.cpp | 13 +++++++++++++
 2 files changed, 17 insertions(+), 2 deletions(-)
 create mode 100644 clang/test/CodeGenCXX/cxx23-p2280r4.cpp

diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp
index ee5874b26f534..075f3f435ad74 100644
--- a/clang/lib/CodeGen/CGExprConstant.cpp
+++ b/clang/lib/CodeGen/CGExprConstant.cpp
@@ -1883,8 +1883,10 @@ llvm::Constant *ConstantEmitter::tryEmitPrivateForVarInit(const VarDecl &D) {
 
   // Try to emit the initializer.  Note that this can allow some things that
   // are not allowed by tryEmitPrivateForMemory alone.
-  if (APValue *value = D.evaluateValue())
-    return tryEmitPrivateForMemory(*value, destType);
+  if (APValue *value = D.evaluateValue()) {
+    if (!value->allowConstexprUnknown())
+      return tryEmitPrivateForMemory(*value, destType);
+  }
 
   return nullptr;
 }
diff --git a/clang/test/CodeGenCXX/cxx23-p2280r4.cpp b/clang/test/CodeGenCXX/cxx23-p2280r4.cpp
new file mode 100644
index 0000000000000..bb9a90ba18ece
--- /dev/null
+++ b/clang/test/CodeGenCXX/cxx23-p2280r4.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++23 %s -emit-llvm -o - | FileCheck %s
+
+extern int& s;
+
+// CHECK: @_Z4testv()
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[I:%.*]] = alloca ptr, align {{.*}}
+// CHECK-NEXT: [[X:%.*]] = load ptr, ptr @s, align {{.*}}
+// CHECK-NEXT: store ptr [[X]], ptr [[I]], align {{.*}}
+int& test() {
+  auto &i = s;
+  return i;
+}

>From ac2bd210ffed3d882be2569a415d7c4bbcbba3e9 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Tue, 18 Feb 2025 19:20:39 +0800
Subject: [PATCH 2/5] Address review comments. NFC.

---
 clang/test/CodeGenCXX/cxx23-p2280r4.cpp | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/clang/test/CodeGenCXX/cxx23-p2280r4.cpp b/clang/test/CodeGenCXX/cxx23-p2280r4.cpp
index bb9a90ba18ece..d5409be451df0 100644
--- a/clang/test/CodeGenCXX/cxx23-p2280r4.cpp
+++ b/clang/test/CodeGenCXX/cxx23-p2280r4.cpp
@@ -1,4 +1,6 @@
 // RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++23 %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++17 %s -emit-llvm -o - | FileCheck %s
 
 extern int& s;
 

>From 1cea7d422c31b5065c76d9fb4a251955b2bea8e6 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Fri, 21 Feb 2025 12:15:29 +0800
Subject: [PATCH 3/5] [Clang][CodeGen] Address review comments. NFC.

---
 clang/lib/CodeGen/CGExprConstant.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp
index 075f3f435ad74..7d44a9f583eca 100644
--- a/clang/lib/CodeGen/CGExprConstant.cpp
+++ b/clang/lib/CodeGen/CGExprConstant.cpp
@@ -1883,10 +1883,10 @@ llvm::Constant *ConstantEmitter::tryEmitPrivateForVarInit(const VarDecl &D) {
 
   // Try to emit the initializer.  Note that this can allow some things that
   // are not allowed by tryEmitPrivateForMemory alone.
-  if (APValue *value = D.evaluateValue()) {
-    if (!value->allowConstexprUnknown())
-      return tryEmitPrivateForMemory(*value, destType);
-  }
+  // Bail out on constexpr-unknown values since they are invalid in CodeGen.
+  if (APValue *value = D.evaluateValue();
+      value && !value->allowConstexprUnknown())
+    return tryEmitPrivateForMemory(*value, destType);
 
   return nullptr;
 }

>From bc24bde52b664ca4b3bcbbbdd48a5a14be37a278 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sun, 23 Feb 2025 17:04:03 +0800
Subject: [PATCH 4/5] [Clang] Treat constexpr-unknown value as invalid in
 `evaluateValue`

---
 clang/lib/AST/Decl.cpp                           | 3 +++
 clang/lib/AST/ExprConstant.cpp                   | 2 --
 clang/lib/CodeGen/CGExprConstant.cpp             | 6 ++++--
 clang/test/SemaCXX/constant-expression-cxx11.cpp | 4 ++--
 4 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 5a3be1690f335..f6cf75ed96aca 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -2587,6 +2587,9 @@ APValue *VarDecl::evaluateValueImpl(SmallVectorImpl<PartialDiagnosticAt> &Notes,
       !Notes.empty())
     Result = false;
 
+  if (Eval->Evaluated.allowConstexprUnknown())
+    Result = false;
+
   // Ensure the computed APValue is cleaned up later if evaluation succeeded,
   // or that it's empty (so that there's nothing to clean up) if evaluation
   // failed.
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 6ccb6e23f8d2f..5e69b44c20e9c 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -3628,8 +3628,6 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
   if (AllowConstexprUnknown) {
     if (!Result)
       Result = &Info.CurrentCall->createConstexprUnknownAPValues(VD, Base);
-    else
-      Result->setConstexprUnknown();
   }
   return true;
 }
diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp
index 7d44a9f583eca..0295f703b9061 100644
--- a/clang/lib/CodeGen/CGExprConstant.cpp
+++ b/clang/lib/CodeGen/CGExprConstant.cpp
@@ -1884,9 +1884,11 @@ llvm::Constant *ConstantEmitter::tryEmitPrivateForVarInit(const VarDecl &D) {
   // Try to emit the initializer.  Note that this can allow some things that
   // are not allowed by tryEmitPrivateForMemory alone.
   // Bail out on constexpr-unknown values since they are invalid in CodeGen.
-  if (APValue *value = D.evaluateValue();
-      value && !value->allowConstexprUnknown())
+  if (APValue *value = D.evaluateValue()) {
+    assert(!value->allowConstexprUnknown() &&
+           "Constexpr unknown values are not allowed in CodeGen");
     return tryEmitPrivateForMemory(*value, destType);
+  }
 
   return nullptr;
 }
diff --git a/clang/test/SemaCXX/constant-expression-cxx11.cpp b/clang/test/SemaCXX/constant-expression-cxx11.cpp
index 76e2f81947051..0702673144bd5 100644
--- a/clang/test/SemaCXX/constant-expression-cxx11.cpp
+++ b/clang/test/SemaCXX/constant-expression-cxx11.cpp
@@ -122,9 +122,9 @@ namespace CaseStatements {
 }
 
 extern int &Recurse1;
-int &Recurse2 = Recurse1; // expected-note {{declared here}}
+int &Recurse2 = Recurse1; // pre-cxx23-note {{declared here}}
 int &Recurse1 = Recurse2;
-constexpr int &Recurse3 = Recurse2; // expected-error {{must be initialized by a constant expression}} expected-note {{initializer of 'Recurse2' is not a constant expression}}
+constexpr int &Recurse3 = Recurse2; // expected-error {{must be initialized by a constant expression}} pre-cxx23-note {{initializer of 'Recurse2' is not a constant expression}}
 
 extern const int RecurseA;
 const int RecurseB = RecurseA; // expected-note {{declared here}}

>From 52c81598da38532c119db9c06fcc3d7f9c332a8e Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Thu, 27 Feb 2025 00:07:22 +0800
Subject: [PATCH 5/5] [Clang][AST] Fix diag regression

---
 clang/lib/AST/Decl.cpp                           |  3 ---
 clang/lib/AST/ExprConstant.cpp                   | 12 ++++++++++++
 clang/test/SemaCXX/constant-expression-cxx11.cpp |  4 ++--
 3 files changed, 14 insertions(+), 5 deletions(-)

diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index f6cf75ed96aca..5a3be1690f335 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -2587,9 +2587,6 @@ APValue *VarDecl::evaluateValueImpl(SmallVectorImpl<PartialDiagnosticAt> &Notes,
       !Notes.empty())
     Result = false;
 
-  if (Eval->Evaluated.allowConstexprUnknown())
-    Result = false;
-
   // Ensure the computed APValue is cleaned up later if evaluation succeeded,
   // or that it's empty (so that there's nothing to clean up) if evaluation
   // failed.
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 5e69b44c20e9c..42801dc4e18fa 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -16998,6 +16998,18 @@ bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx,
 
     if (!Info.discardCleanups())
       llvm_unreachable("Unhandled cleanup; missing full expression marker?");
+
+    if (Value.allowConstexprUnknown()) {
+      assert(Value.isLValue() && "Expected an lvalue");
+      auto Base = Value.getLValueBase();
+      const auto *NewVD = Base.dyn_cast<const ValueDecl *>();
+      if (!NewVD)
+        NewVD = VD;
+      Info.FFDiag(getExprLoc(), diag::note_constexpr_var_init_non_constant, 1)
+          << NewVD;
+      NoteLValueLocation(Info, Base);
+      return false;
+    }
   }
 
   return CheckConstantExpression(Info, DeclLoc, DeclTy, Value,
diff --git a/clang/test/SemaCXX/constant-expression-cxx11.cpp b/clang/test/SemaCXX/constant-expression-cxx11.cpp
index 0702673144bd5..76e2f81947051 100644
--- a/clang/test/SemaCXX/constant-expression-cxx11.cpp
+++ b/clang/test/SemaCXX/constant-expression-cxx11.cpp
@@ -122,9 +122,9 @@ namespace CaseStatements {
 }
 
 extern int &Recurse1;
-int &Recurse2 = Recurse1; // pre-cxx23-note {{declared here}}
+int &Recurse2 = Recurse1; // expected-note {{declared here}}
 int &Recurse1 = Recurse2;
-constexpr int &Recurse3 = Recurse2; // expected-error {{must be initialized by a constant expression}} pre-cxx23-note {{initializer of 'Recurse2' is not a constant expression}}
+constexpr int &Recurse3 = Recurse2; // expected-error {{must be initialized by a constant expression}} expected-note {{initializer of 'Recurse2' is not a constant expression}}
 
 extern const int RecurseA;
 const int RecurseB = RecurseA; // expected-note {{declared here}}



More information about the cfe-commits mailing list