Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 12 additions & 13 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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,
Expand Down
12 changes: 12 additions & 0 deletions clang/test/CodeGenCXX/cxx23-p2280r4.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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}; }
4 changes: 2 additions & 2 deletions clang/test/SemaCXX/constant-expression-cxx11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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}}
};
Expand Down
25 changes: 24 additions & 1 deletion clang/test/SemaCXX/constant-expression-p2280r4.cpp
Original file line number Diff line number Diff line change
@@ -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));
Expand Down Expand Up @@ -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}}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you end the comments in \, you don't need to add the @-2 stuff.

// expected-note@-1 {{required by 'constinit' specifier here}}
// nointerpreter-note@-2 {{initializer of 'x' is not a constant expression}}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't want to block on this, but the diagnostic here is a little off... Even if the initializer of x was a constant expression, the declaration of z would still not be valid because x is not const (or constexpr).

In other words, if I saw this error in practice, I'd try to fix x's initializer, just to be greeted by another diagnostic.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is pre-existing though

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both clang and gcc accept the following:

int y;
int &r1 = y;
constinit int &r2 = r1;

I think that's right, looking at the rules for "potentially-constant" variables?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://godbolt.org/z/81M8aYGPn
Yeah, not a fan of any of this. But this patch LGTM.

}

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@-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}}
}
Loading