[clang] Reject constexpr-unknown values as constant expressions more … · llvm/llvm-project@fbb2a7e (original) (raw)

4 files changed

lines changed

Original file line number Diff line number Diff line change
@@ -2419,6 +2419,16 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
2419 2419 LVal.getLValueCallIndex() == 0) &&
2420 2420 "have call index for global lvalue");
2421 2421
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 +
2422 2432 if (Base.is()) {
2423 2433 Info.FFDiag(Loc, diag::note_constexpr_dynamic_alloc)
2424 2434 << IsReferenceType << !Designator.Entries.empty();
@@ -3597,7 +3607,8 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
3597 3607 // expressions here; doing so would regress diagnostics for things like
3598 3608 // reading from a volatile constexpr variable.
3599 3609 if ((Info.getLangOpts().CPlusPlus && !VD->hasConstantInitialization() &&
3600 - VD->mightBeUsableInConstantExpressions(Info.Ctx)) |
3610 + VD->mightBeUsableInConstantExpressions(Info.Ctx) &&
3611 + !AllowConstexprUnknown) |
3601 3612 ((Info.getLangOpts().CPlusPlus |
3602 3613 !Info.getLangOpts().CPlusPlus11 && !VD->hasICEInitializer(Info.Ctx))) {
3603 3614 if (Init) {
@@ -16998,18 +17009,6 @@ bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx,
16998 17009
16999 17010 if (!Info.discardCleanups())
17000 17011 llvm_unreachable("Unhandled cleanup; missing full expression marker?");
17001 -
17002 - if (Value.allowConstexprUnknown()) {
17003 - assert(Value.isLValue() && "Expected an lvalue");
17004 - auto Base = Value.getLValueBase();
17005 - const auto *NewVD = Base.dyn_cast<const ValueDecl *>();
17006 - if (!NewVD)
17007 - NewVD = VD;
17008 - Info.FFDiag(getExprLoc(), diag::note_constexpr_var_init_non_constant, 1)
17009 - << NewVD;
17010 - NoteLValueLocation(Info, Base);
17011 - return false;
17012 - }
17013 17012 }
17014 17013
17015 17014 return CheckConstantExpression(Info, DeclLoc, DeclTy, Value,
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@
4 4
5 5 extern int& s;
6 6
7 -// CHECK: @_Z4testv()
7 +// CHECK-LABEL: @_Z4testv()
8 8 // CHECK-NEXT: entry:
9 9 // CHECK-NEXT: [[I:%.*]] = alloca ptr, align {{.*}}
10 10 // CHECK-NEXT: [[X:%.*]] = load ptr, ptr @s, align {{.*}}
@@ -13,3 +13,16 @@ int& test() {
13 13 auto &i = s;
14 14 return i;
15 15 }
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}; }
Original file line number Diff line number Diff line change
@@ -1472,8 +1472,8 @@ namespace ConvertedConstantExpr {
1472 1472 enum class E {
1473 1473 em = m,
1474 1474 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}}
1477 1477 ),
1478 1478 eq = reinterpret_cast<long>((int*)0) // expected-error {{not a constant expression}} expected-note {{reinterpret_cast}}
1479 1479 };
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
1 -// RUN: %clang_cc1 -std=c++23 -verify %s
1 +// RUN: %clang_cc1 -std=c++23 -verify=expected,nointerpreter %s
2 +// (Run line removed for backport to 20.x, so we don't need to backport
3 +// fexperimental-new-constant-interpreter changes)
4 +// UN: %clang_cc1 -std=c++23 -verify %s -fexperimental-new-constant-interpreter
2 5
3 6 using size_t = decltype(sizeof(0));
4 7
@@ -38,8 +41,8 @@ void splash(Swim& swam) {
38 41 static_assert(swam.phelps() == 28); // ok
39 42 static_assert((&swam)->phelps() == 28); // ok
40 43 Swim* pswam = &swam; // expected-note {{declared here}}
41 -static_assert(pswam->phelps() == 28); // expected-error {{static assertion expression is not an integral constant expression}}
42 -// expected-note@-1 {{read of non-constexpr variable 'pswam' is not allowed in a constant expression}}
44 +static_assert(pswam->phelps() == 28); // expected-error {{static assertion expression is not an integral constant expression}} \
45 + // expected-note {{read of non-constexpr variable 'pswam' is not allowed in a constant expression}}
43 46 static_assert(how_many(swam) == 28); // ok
44 47 static_assert(Swim().lochte() == 12); // ok
45 48 static_assert(swam.lochte() == 12); // expected-error {{static assertion expression is not an integral constant expression}}
@@ -153,3 +156,26 @@ int g() {
153 156 static_assert(f(arr) == 5);
154 157 }
155 158 }
159 +
160 +namespace GH128409 {
161 +int &ff();
162 +int &x = ff(); // nointerpreter-note {{declared here}}
163 +constinit int &z = x; // expected-error {{variable does not have a constant initializer}} \
164 + // expected-note {{required by 'constinit' specifier here}} \
165 + // nointerpreter-note {{initializer of 'x' is not a constant expression}}
166 +}
167 +
168 +namespace GH129845 {
169 +int &ff();
170 +int &x = ff(); // nointerpreter-note {{declared here}}
171 +struct A { int& x; };
172 +constexpr A g = {x}; // expected-error {{constexpr variable 'g' must be initialized by a constant expression}} \
173 + // nointerpreter-note {{initializer of 'x' is not a constant expression}}
174 +const A* gg = &g;
175 +}
176 +
177 +namespace extern_reference_used_as_unknown {
178 +extern int &x;
179 +int y;
180 +constinit int& g = (x,y); // expected-warning {{left operand of comma operator has no effect}}
181 +}