Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Clang] Static member initializers are not immediate escalating context. #66021

Merged
merged 8 commits into from
Sep 19, 2023
4 changes: 4 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,10 @@ Bug Fixes to C++ Support
a non-template inner-class between the function and the class template.
(`#65810 <https://github.com/llvm/llvm-project/issues/65810>`_)

- Fix a crash when calling a non-constant immediate function
in the initializer of a static data member.
(`#65985 <https://github.com/llvm/llvm-project/issues/65985>_`).

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed an import failure of recursive friend class template.
Expand Down
12 changes: 10 additions & 2 deletions clang/lib/Parse/ParseDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3230,13 +3230,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<FieldDecl>(D);

EnterExpressionEvaluationContext Context(
Actions,
isa_and_present<FieldDecl>(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
Expand Down
57 changes: 53 additions & 4 deletions clang/test/SemaCXX/cxx2a-consteval.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ consteval int f1(int i) {
return i;
}

consteval constexpr int f2(int i) {
consteval constexpr int f2(int i) {
//expected-error@-1 {{cannot combine}}
return i;
}
Expand Down Expand Up @@ -195,7 +195,7 @@ auto ptr = ret1(0);
struct A {
consteval int f(int) {
// expected-note@-1+ {{declared here}}
return 0;
return 0;
}
};

Expand Down Expand Up @@ -239,7 +239,7 @@ constexpr int f_c(int i) {
int t = f(i);
// expected-error@-1 {{is not a constant expression}}
// expected-note@-2 {{function parameter}}
return f(0);
return f(0);
}

consteval int f_eval(int i) {
Expand Down Expand Up @@ -675,7 +675,7 @@ Bar<derp> a; // expected-note {{in instantiation of member function 'issue_55601

struct constantDerp {
// Can be used in a constant expression.
consteval constantDerp(int) {}
consteval constantDerp(int) {}
consteval operator int() const { return 5; }
};
Bar<constantDerp> b;
Expand Down Expand Up @@ -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 <class A>
struct T {
static constexpr auto xx = ns::foo(A{}); // expected-error {{cannot take address of consteval function 'foo' outside of an immediate invocation}}
};

}