[clang] [clang] Reject constexpr-unknown values as constant expressions more consistently (PR #129952)
Eli Friedman via cfe-commits
cfe-commits at lists.llvm.org
Thu Mar 6 14:09:55 PST 2025
https://github.com/efriedma-quic updated https://github.com/llvm/llvm-project/pull/129952
>From 9ac636ee137248cafe38f4d2e016cfb885142dff Mon Sep 17 00:00:00 2001
From: Eli Friedman <efriedma at quicinc.com>
Date: Wed, 5 Mar 2025 14:20:21 -0800
Subject: [PATCH 1/2] [clang] Reject constexpr-unknown values as constant
expressions more consistently.
Perform the check for constexpr-unknown values in the same place we
perform checks for other values which don't count as constant
expressions.
While I'm here, also fix a rejects-valid with a reference that doesn't
have an initializer. This diagnostic was also covering up some of the
bugs here.
The existing behavior with -fexperimental-new-constant-interpreter seems
to be correct, but the diagnostics are slightly different; it would be
helpful if someone could check on that as a followup.
Followup to #128409.
Fixes #129844. Fixes #129845.
---
clang/lib/AST/ExprConstant.cpp | 25 +++++++++----------
clang/test/CodeGenCXX/cxx23-p2280r4.cpp | 12 +++++++++
.../SemaCXX/constant-expression-cxx11.cpp | 4 +--
.../SemaCXX/constant-expression-p2280r4.cpp | 25 ++++++++++++++++++-
4 files changed, 50 insertions(+), 16 deletions(-)
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index d9a1e5bb42343..216bc478bb28b 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -2419,6 +2419,16 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
LVal.getLValueCallIndex() == 0) &&
"have call index for global lvalue");
+ if (LVal.allowConstexprUnknown()) {
+ if (BaseVD) {
+ Info.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << BaseVD;
+ NoteLValueLocation(Info, Base);
+ } else {
+ Info.FFDiag(Loc);
+ }
+ return false;
+ }
+
if (Base.is<DynamicAllocLValue>()) {
Info.FFDiag(Loc, diag::note_constexpr_dynamic_alloc)
<< IsReferenceType << !Designator.Entries.empty();
@@ -3597,7 +3607,8 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
// expressions here; doing so would regress diagnostics for things like
// reading from a volatile constexpr variable.
if ((Info.getLangOpts().CPlusPlus && !VD->hasConstantInitialization() &&
- VD->mightBeUsableInConstantExpressions(Info.Ctx)) ||
+ VD->mightBeUsableInConstantExpressions(Info.Ctx) &&
+ !AllowConstexprUnknown) ||
((Info.getLangOpts().CPlusPlus || Info.getLangOpts().OpenCL) &&
!Info.getLangOpts().CPlusPlus11 && !VD->hasICEInitializer(Info.Ctx))) {
if (Init) {
@@ -16993,18 +17004,6 @@ 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/CodeGenCXX/cxx23-p2280r4.cpp b/clang/test/CodeGenCXX/cxx23-p2280r4.cpp
index d5409be451df0..c91457e5c20de 100644
--- a/clang/test/CodeGenCXX/cxx23-p2280r4.cpp
+++ b/clang/test/CodeGenCXX/cxx23-p2280r4.cpp
@@ -13,3 +13,15 @@ int& test() {
auto &i = s;
return i;
}
+
+// CHECK: @_Z1fv(
+// CHECK-NEXT: entry:
+// CHECK-NEXT: getelementptr inbounds nuw %struct.B
+// CHECK-NEXT: getelementptr inbounds nuw %struct.A
+// CHECK-NEXT: [[X:%.*]] = load ptr, ptr @x, align 8
+// CHECK-NEXT: store ptr [[X]]
+int &ff();
+int &x = ff();
+struct A { int& x; };
+struct B { A x[20]; };
+B f() { return {x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x}; }
diff --git a/clang/test/SemaCXX/constant-expression-cxx11.cpp b/clang/test/SemaCXX/constant-expression-cxx11.cpp
index 76e2f81947051..c35f3a5632a05 100644
--- a/clang/test/SemaCXX/constant-expression-cxx11.cpp
+++ b/clang/test/SemaCXX/constant-expression-cxx11.cpp
@@ -1472,8 +1472,8 @@ namespace ConvertedConstantExpr {
enum class E {
em = m,
en = n, // expected-error {{enumerator value is not a constant expression}} cxx11_20-note {{initializer of 'n' is unknown}}
- eo = (m + // pre-cxx23-error {{not a constant expression}}
- n // cxx11_20-note {{initializer of 'n' is unknown}} cxx23-error {{not a constant expression}}
+ eo = (m + // expected-error {{not a constant expression}}
+ n // cxx11_20-note {{initializer of 'n' is unknown}}
),
eq = reinterpret_cast<long>((int*)0) // expected-error {{not a constant expression}} expected-note {{reinterpret_cast}}
};
diff --git a/clang/test/SemaCXX/constant-expression-p2280r4.cpp b/clang/test/SemaCXX/constant-expression-p2280r4.cpp
index 65e5e6b34b48f..731b0e9b03046 100644
--- a/clang/test/SemaCXX/constant-expression-p2280r4.cpp
+++ b/clang/test/SemaCXX/constant-expression-p2280r4.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++23 -verify %s
+// RUN: %clang_cc1 -std=c++23 -verify=expected,nointerpreter %s
// RUN: %clang_cc1 -std=c++23 -verify %s -fexperimental-new-constant-interpreter
using size_t = decltype(sizeof(0));
@@ -154,3 +154,26 @@ int g() {
static_assert(f(arr) == 5);
}
}
+
+namespace GH128409 {
+ int &ff();
+ int &x = ff(); // nointerpreter-note {{declared here}}
+ constinit int &z = x; // expected-error {{variable does not have a constant initializer}}
+ // expected-note at -1 {{required by 'constinit' specifier here}}
+ // nointerpreter-note at -2 {{initializer of 'x' is not a constant expression}}
+}
+
+namespace GH129845 {
+ int &ff();
+ int &x = ff(); // nointerpreter-note {{declared here}}
+ struct A { int& x; };
+ constexpr A g = {x}; // expected-error {{constexpr variable 'g' must be initialized by a constant expression}}
+ // nointerpreter-note at -1 {{initializer of 'x' is not a constant expression}}
+ const A* gg = &g;
+}
+
+namespace extern_reference_used_as_unknown {
+ extern int &x;
+ int y;
+ constinit int& g = (x,y); // expected-warning {{left operand of comma operator has no effect}}
+}
>From 5ce2daf09edb42b78ea9fca2462a898171b12ce2 Mon Sep 17 00:00:00 2001
From: Eli Friedman <efriedma at quicinc.com>
Date: Thu, 6 Mar 2025 14:09:28 -0800
Subject: [PATCH 2/2] Fix regression test on Windows.
---
clang/test/CodeGenCXX/cxx23-p2280r4.cpp | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/clang/test/CodeGenCXX/cxx23-p2280r4.cpp b/clang/test/CodeGenCXX/cxx23-p2280r4.cpp
index c91457e5c20de..b62c68c66f0fa 100644
--- a/clang/test/CodeGenCXX/cxx23-p2280r4.cpp
+++ b/clang/test/CodeGenCXX/cxx23-p2280r4.cpp
@@ -4,7 +4,7 @@
extern int& s;
-// CHECK: @_Z4testv()
+// CHECK-LABEL: @_Z4testv()
// CHECK-NEXT: entry:
// CHECK-NEXT: [[I:%.*]] = alloca ptr, align {{.*}}
// CHECK-NEXT: [[X:%.*]] = load ptr, ptr @s, align {{.*}}
@@ -14,12 +14,13 @@ int& test() {
return i;
}
-// CHECK: @_Z1fv(
-// CHECK-NEXT: entry:
-// CHECK-NEXT: getelementptr inbounds nuw %struct.B
-// CHECK-NEXT: getelementptr inbounds nuw %struct.A
-// CHECK-NEXT: [[X:%.*]] = load ptr, ptr @x, align 8
-// CHECK-NEXT: store ptr [[X]]
+// CHECK-LABEL: @_Z1fv(
+// CHECK: [[X1:%.*]] = load ptr, ptr @x, align 8
+// CHECK-NEXT: store ptr [[X1]]
+// CHECK: [[X2:%.*]] = load ptr, ptr @x, align 8
+// CHECK-NEXT: store ptr [[X2]]
+// CHECK: [[X3:%.*]] = load ptr, ptr @x, align 8
+// CHECK-NEXT: store ptr [[X3]]
int &ff();
int &x = ff();
struct A { int& x; };
More information about the cfe-commits
mailing list