Skip to content

Commit 0677d7c

Browse files
authored
[Clang] Static member initializers are not immediate escalating context. (#66021)
Per CWG2760, default members initializers should be consider part the body of constructors, which mean they are evaluated in an immediate escalating context. However, this does not apply to static members. This patch produces some extraneous diagnostics, unfortunately we do not have a good way to report an error back to the initializer and this is a pre existing issue Fixes #65985 Fixes #66562
1 parent d8873df commit 0677d7c

File tree

4 files changed

+77
-2
lines changed

4 files changed

+77
-2
lines changed

clang/docs/ReleaseNotes.rst

+3
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,9 @@ Bug Fixes to C++ Support
287287
a non-template inner-class between the function and the class template.
288288
(`#65810 <https://github.com/llvm/llvm-project/issues/65810>`_)
289289

290+
- Fix a crash when calling a non-constant immediate function
291+
in the initializer of a static data member.
292+
(`#65985 <https://github.com/llvm/llvm-project/issues/65985>_`).
290293
- Clang now properly converts static lambda call operator to function
291294
pointers on win32.
292295
(`#62594 <https://github.com/llvm/llvm-project/issues/62594>`_)

clang/lib/Parse/ParseDeclCXX.cpp

+10-2
Original file line numberDiff line numberDiff line change
@@ -3232,13 +3232,21 @@ ExprResult Parser::ParseCXXMemberInitializer(Decl *D, bool IsFunction,
32323232
assert(Tok.isOneOf(tok::equal, tok::l_brace) &&
32333233
"Data member initializer not starting with '=' or '{'");
32343234

3235+
bool IsFieldInitialization = isa_and_present<FieldDecl>(D);
3236+
32353237
EnterExpressionEvaluationContext Context(
32363238
Actions,
3237-
isa_and_present<FieldDecl>(D)
3239+
IsFieldInitialization
32383240
? Sema::ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed
32393241
: Sema::ExpressionEvaluationContext::PotentiallyEvaluated,
32403242
D);
3241-
Actions.ExprEvalContexts.back().InImmediateEscalatingFunctionContext = true;
3243+
3244+
// CWG2760
3245+
// Default member initializers used to initialize a base or member subobject
3246+
// [...] are considered to be part of the function body
3247+
Actions.ExprEvalContexts.back().InImmediateEscalatingFunctionContext =
3248+
IsFieldInitialization;
3249+
32423250
if (TryConsumeToken(tok::equal, EqualLoc)) {
32433251
if (Tok.is(tok::kw_delete)) {
32443252
// In principle, an initializer of '= delete p;' is legal, but it will

clang/test/SemaCXX/cxx2a-consteval.cpp

+49
Original file line numberDiff line numberDiff line change
@@ -1126,4 +1126,53 @@ int test2() { return h{nullptr}; }
11261126
// expected-note@-2 {{subobject 'g' is not initialized}}
11271127

11281128

1129+
}
1130+
1131+
namespace GH65985 {
1132+
1133+
int consteval operator""_foo(unsigned long long V) {
1134+
return 0;
1135+
}
1136+
int consteval operator""_bar(unsigned long long V); // expected-note 3{{here}}
1137+
1138+
int consteval f() {
1139+
return 0;
1140+
}
1141+
1142+
int consteval g(); // expected-note {{here}}
1143+
1144+
1145+
struct C {
1146+
static const int a = 1_foo;
1147+
static constexpr int b = 1_foo;
1148+
static const int c = 1_bar; // expected-error {{call to consteval function 'GH65985::operator""_bar' is not a constant expression}} \
1149+
// expected-note {{undefined function 'operator""_bar' cannot be used in a constant expression}} \
1150+
// expected-error {{in-class initializer for static data member is not a constant expression}}
1151+
1152+
// FIXME: remove duplicate diagnostics
1153+
static constexpr int d = 1_bar; // expected-error {{call to consteval function 'GH65985::operator""_bar' is not a constant expression}} \
1154+
// expected-note {{undefined function 'operator""_bar' cannot be used in a constant expression}} \
1155+
// expected-error {{constexpr variable 'd' must be initialized by a constant expression}} \
1156+
// expected-note {{undefined function 'operator""_bar' cannot be used in a constant expression}}
1157+
1158+
static const int e = f();
1159+
static const int f = g(); // expected-error {{call to consteval function 'GH65985::g' is not a constant expression}} \
1160+
// expected-error {{in-class initializer for static data member is not a constant expression}} \
1161+
// expected-note {{undefined function 'g' cannot be used in a constant expression}}
1162+
};
1163+
1164+
}
1165+
1166+
namespace GH66562 {
1167+
1168+
namespace ns
1169+
{
1170+
consteval int foo(int x) { return 1; } // expected-note {{declared here}}
1171+
}
1172+
1173+
template <class A>
1174+
struct T {
1175+
static constexpr auto xx = ns::foo(A{}); // expected-error {{cannot take address of consteval function 'foo' outside of an immediate invocation}}
1176+
};
1177+
11291178
}

clang/test/SemaCXX/cxx2b-consteval-propagate.cpp

+15
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,21 @@ S s(0); // expected-note {{in the default initializer of 'j'}}
331331

332332
}
333333

334+
namespace GH65985 {
335+
consteval int invalid(); // expected-note 2{{declared here}}
336+
constexpr int escalating(auto) {
337+
return invalid();
338+
// expected-note@-1 {{'escalating<int>' is an immediate function because its body contains a call to a consteval function 'invalid' and that call is not a constant expression}}
339+
// expected-note@-2 2{{undefined function 'invalid' cannot be used in a constant expression}}
340+
}
341+
struct S {
342+
static constexpr int a = escalating(0); // expected-note 2{{in call to}}
343+
// expected-error@-1 {{call to immediate function 'GH65985::escalating<int>' is not a constant expression}}
344+
// expected-error@-2 {{constexpr variable 'a' must be initialized by a constant expression}}
345+
};
346+
347+
}
348+
334349
namespace GH66324 {
335350

336351
consteval int allocate(); // expected-note 2{{declared here}}

0 commit comments

Comments
 (0)