Skip to content

Commit 42d49a7

Browse files
[clang] Reject constexpr-unknown values as constant expressions more consistently (#129952)
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.
1 parent d111e64 commit 42d49a7

File tree

4 files changed

+54
-19
lines changed

4 files changed

+54
-19
lines changed

clang/lib/AST/ExprConstant.cpp

+12-13
Original file line numberDiff line numberDiff line change
@@ -2419,6 +2419,16 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
24192419
LVal.getLValueCallIndex() == 0) &&
24202420
"have call index for global lvalue");
24212421

2422+
if (LVal.allowConstexprUnknown()) {
2423+
if (BaseVD) {
2424+
Info.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << BaseVD;
2425+
NoteLValueLocation(Info, Base);
2426+
} else {
2427+
Info.FFDiag(Loc);
2428+
}
2429+
return false;
2430+
}
2431+
24222432
if (Base.is<DynamicAllocLValue>()) {
24232433
Info.FFDiag(Loc, diag::note_constexpr_dynamic_alloc)
24242434
<< IsReferenceType << !Designator.Entries.empty();
@@ -3597,7 +3607,8 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
35973607
// expressions here; doing so would regress diagnostics for things like
35983608
// reading from a volatile constexpr variable.
35993609
if ((Info.getLangOpts().CPlusPlus && !VD->hasConstantInitialization() &&
3600-
VD->mightBeUsableInConstantExpressions(Info.Ctx)) ||
3610+
VD->mightBeUsableInConstantExpressions(Info.Ctx) &&
3611+
!AllowConstexprUnknown) ||
36013612
((Info.getLangOpts().CPlusPlus || Info.getLangOpts().OpenCL) &&
36023613
!Info.getLangOpts().CPlusPlus11 && !VD->hasICEInitializer(Info.Ctx))) {
36033614
if (Init) {
@@ -16993,18 +17004,6 @@ bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx,
1699317004

1699417005
if (!Info.discardCleanups())
1699517006
llvm_unreachable("Unhandled cleanup; missing full expression marker?");
16996-
16997-
if (Value.allowConstexprUnknown()) {
16998-
assert(Value.isLValue() && "Expected an lvalue");
16999-
auto Base = Value.getLValueBase();
17000-
const auto *NewVD = Base.dyn_cast<const ValueDecl *>();
17001-
if (!NewVD)
17002-
NewVD = VD;
17003-
Info.FFDiag(getExprLoc(), diag::note_constexpr_var_init_non_constant, 1)
17004-
<< NewVD;
17005-
NoteLValueLocation(Info, Base);
17006-
return false;
17007-
}
1700817007
}
1700917008

1701017009
return CheckConstantExpression(Info, DeclLoc, DeclTy, Value,

clang/test/CodeGenCXX/cxx23-p2280r4.cpp

+14-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
extern int& s;
66

7-
// CHECK: @_Z4testv()
7+
// CHECK-LABEL: @_Z4testv()
88
// CHECK-NEXT: entry:
99
// CHECK-NEXT: [[I:%.*]] = alloca ptr, align {{.*}}
1010
// CHECK-NEXT: [[X:%.*]] = load ptr, ptr @s, align {{.*}}
@@ -13,3 +13,16 @@ int& test() {
1313
auto &i = s;
1414
return i;
1515
}
16+
17+
// CHECK-LABEL: @_Z1fv(
18+
// CHECK: [[X1:%.*]] = load ptr, ptr @x, align 8
19+
// CHECK-NEXT: store ptr [[X1]]
20+
// CHECK: [[X2:%.*]] = load ptr, ptr @x, align 8
21+
// CHECK-NEXT: store ptr [[X2]]
22+
// CHECK: [[X3:%.*]] = load ptr, ptr @x, align 8
23+
// CHECK-NEXT: store ptr [[X3]]
24+
int &ff();
25+
int &x = ff();
26+
struct A { int& x; };
27+
struct B { A x[20]; };
28+
B f() { return {x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x}; }

clang/test/SemaCXX/constant-expression-cxx11.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -1472,8 +1472,8 @@ namespace ConvertedConstantExpr {
14721472
enum class E {
14731473
em = m,
14741474
en = n, // expected-error {{enumerator value is not a constant expression}} cxx11_20-note {{initializer of 'n' is unknown}}
1475-
eo = (m + // pre-cxx23-error {{not a constant expression}}
1476-
n // cxx11_20-note {{initializer of 'n' is unknown}} cxx23-error {{not a constant expression}}
1475+
eo = (m + // expected-error {{not a constant expression}}
1476+
n // cxx11_20-note {{initializer of 'n' is unknown}}
14771477
),
14781478
eq = reinterpret_cast<long>((int*)0) // expected-error {{not a constant expression}} expected-note {{reinterpret_cast}}
14791479
};

clang/test/SemaCXX/constant-expression-p2280r4.cpp

+26-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %clang_cc1 -std=c++23 -verify %s
1+
// RUN: %clang_cc1 -std=c++23 -verify=expected,nointerpreter %s
22
// RUN: %clang_cc1 -std=c++23 -verify %s -fexperimental-new-constant-interpreter
33

44
using size_t = decltype(sizeof(0));
@@ -39,8 +39,8 @@ void splash(Swim& swam) {
3939
static_assert(swam.phelps() == 28); // ok
4040
static_assert((&swam)->phelps() == 28); // ok
4141
Swim* pswam = &swam; // expected-note {{declared here}}
42-
static_assert(pswam->phelps() == 28); // expected-error {{static assertion expression is not an integral constant expression}}
43-
// expected-note@-1 {{read of non-constexpr variable 'pswam' is not allowed in a constant expression}}
42+
static_assert(pswam->phelps() == 28); // expected-error {{static assertion expression is not an integral constant expression}} \
43+
// expected-note {{read of non-constexpr variable 'pswam' is not allowed in a constant expression}}
4444
static_assert(how_many(swam) == 28); // ok
4545
static_assert(Swim().lochte() == 12); // ok
4646
static_assert(swam.lochte() == 12); // expected-error {{static assertion expression is not an integral constant expression}}
@@ -154,3 +154,26 @@ int g() {
154154
static_assert(f(arr) == 5);
155155
}
156156
}
157+
158+
namespace GH128409 {
159+
int &ff();
160+
int &x = ff(); // nointerpreter-note {{declared here}}
161+
constinit int &z = x; // expected-error {{variable does not have a constant initializer}} \
162+
// expected-note {{required by 'constinit' specifier here}} \
163+
// nointerpreter-note {{initializer of 'x' is not a constant expression}}
164+
}
165+
166+
namespace GH129845 {
167+
int &ff();
168+
int &x = ff(); // nointerpreter-note {{declared here}}
169+
struct A { int& x; };
170+
constexpr A g = {x}; // expected-error {{constexpr variable 'g' must be initialized by a constant expression}} \
171+
// nointerpreter-note {{initializer of 'x' is not a constant expression}}
172+
const A* gg = &g;
173+
}
174+
175+
namespace extern_reference_used_as_unknown {
176+
extern int &x;
177+
int y;
178+
constinit int& g = (x,y); // expected-warning {{left operand of comma operator has no effect}}
179+
}

0 commit comments

Comments
 (0)