[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 | +} |