diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index ba91f9481fe98..44a5d5740dabe 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -287,6 +287,9 @@ Bug Fixes to C++ Support a non-template inner-class between the function and the class template. (`#65810 `_) +- Fix a crash when calling a non-constant immediate function + in the initializer of a static data member. + (`#65985 _`). - Clang now properly converts static lambda call operator to function pointers on win32. (`#62594 `_) diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 5fe9abb1fdcab..5a6b5efbf6c12 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -3232,13 +3232,21 @@ ExprResult Parser::ParseCXXMemberInitializer(Decl *D, bool IsFunction, assert(Tok.isOneOf(tok::equal, tok::l_brace) && "Data member initializer not starting with '=' or '{'"); + bool IsFieldInitialization = isa_and_present(D); + EnterExpressionEvaluationContext Context( Actions, - isa_and_present(D) + IsFieldInitialization ? Sema::ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed : Sema::ExpressionEvaluationContext::PotentiallyEvaluated, D); - Actions.ExprEvalContexts.back().InImmediateEscalatingFunctionContext = true; + + // CWG2760 + // Default member initializers used to initialize a base or member subobject + // [...] are considered to be part of the function body + Actions.ExprEvalContexts.back().InImmediateEscalatingFunctionContext = + IsFieldInitialization; + if (TryConsumeToken(tok::equal, EqualLoc)) { if (Tok.is(tok::kw_delete)) { // In principle, an initializer of '= delete p;' is legal, but it will diff --git a/clang/test/SemaCXX/cxx2a-consteval.cpp b/clang/test/SemaCXX/cxx2a-consteval.cpp index d98ec8048c324..a091fadfa3094 100644 --- a/clang/test/SemaCXX/cxx2a-consteval.cpp +++ b/clang/test/SemaCXX/cxx2a-consteval.cpp @@ -1126,4 +1126,53 @@ int test2() { return h{nullptr}; } // expected-note@-2 {{subobject 'g' is not initialized}} +} + +namespace GH65985 { + +int consteval operator""_foo(unsigned long long V) { + return 0; +} +int consteval operator""_bar(unsigned long long V); // expected-note 3{{here}} + +int consteval f() { + return 0; +} + +int consteval g(); // expected-note {{here}} + + +struct C { + static const int a = 1_foo; + static constexpr int b = 1_foo; + static const int c = 1_bar; // expected-error {{call to consteval function 'GH65985::operator""_bar' is not a constant expression}} \ + // expected-note {{undefined function 'operator""_bar' cannot be used in a constant expression}} \ + // expected-error {{in-class initializer for static data member is not a constant expression}} + + // FIXME: remove duplicate diagnostics + static constexpr int d = 1_bar; // expected-error {{call to consteval function 'GH65985::operator""_bar' is not a constant expression}} \ + // expected-note {{undefined function 'operator""_bar' cannot be used in a constant expression}} \ + // expected-error {{constexpr variable 'd' must be initialized by a constant expression}} \ + // expected-note {{undefined function 'operator""_bar' cannot be used in a constant expression}} + + static const int e = f(); + static const int f = g(); // expected-error {{call to consteval function 'GH65985::g' is not a constant expression}} \ + // expected-error {{in-class initializer for static data member is not a constant expression}} \ + // expected-note {{undefined function 'g' cannot be used in a constant expression}} +}; + +} + +namespace GH66562 { + +namespace ns +{ + consteval int foo(int x) { return 1; } // expected-note {{declared here}} +} + +template +struct T { + static constexpr auto xx = ns::foo(A{}); // expected-error {{cannot take address of consteval function 'foo' outside of an immediate invocation}} +}; + } diff --git a/clang/test/SemaCXX/cxx2b-consteval-propagate.cpp b/clang/test/SemaCXX/cxx2b-consteval-propagate.cpp index c0adbbdf9be63..531a626228733 100644 --- a/clang/test/SemaCXX/cxx2b-consteval-propagate.cpp +++ b/clang/test/SemaCXX/cxx2b-consteval-propagate.cpp @@ -331,6 +331,21 @@ S s(0); // expected-note {{in the default initializer of 'j'}} } +namespace GH65985 { +consteval int invalid(); // expected-note 2{{declared here}} +constexpr int escalating(auto) { + return invalid(); + // expected-note@-1 {{'escalating' is an immediate function because its body contains a call to a consteval function 'invalid' and that call is not a constant expression}} + // expected-note@-2 2{{undefined function 'invalid' cannot be used in a constant expression}} +} +struct S { + static constexpr int a = escalating(0); // expected-note 2{{in call to}} + // expected-error@-1 {{call to immediate function 'GH65985::escalating' is not a constant expression}} + // expected-error@-2 {{constexpr variable 'a' must be initialized by a constant expression}} +}; + +} + namespace GH66324 { consteval int allocate(); // expected-note 2{{declared here}}