[clang] 0677d7c - [Clang] Static member initializers are not immediate escalating context. (#66021)

via cfe-commits cfe-commits at lists.llvm.org
Tue Sep 19 14:41:55 PDT 2023


Author: cor3ntin
Date: 2023-09-19T23:41:51+02:00
New Revision: 0677d7cd8c1549b04ae02e0a878faabf17f8999f

URL: https://github.com/llvm/llvm-project/commit/0677d7cd8c1549b04ae02e0a878faabf17f8999f
DIFF: https://github.com/llvm/llvm-project/commit/0677d7cd8c1549b04ae02e0a878faabf17f8999f.diff

LOG: [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

Added: 
    

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/lib/Parse/ParseDeclCXX.cpp
    clang/test/SemaCXX/cxx2a-consteval.cpp
    clang/test/SemaCXX/cxx2b-consteval-propagate.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index ba91f9481fe988a..44a5d5740dabef1 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 <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>_`).
 - Clang now properly converts static lambda call operator to function
   pointers on win32.
   (`#62594 <https://github.com/llvm/llvm-project/issues/62594>`_)

diff  --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 5fe9abb1fdcab30..5a6b5efbf6c1223 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<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

diff  --git a/clang/test/SemaCXX/cxx2a-consteval.cpp b/clang/test/SemaCXX/cxx2a-consteval.cpp
index d98ec8048c32466..a091fadfa3094bd 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 at -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}}
+};
+
 }

diff  --git a/clang/test/SemaCXX/cxx2b-consteval-propagate.cpp b/clang/test/SemaCXX/cxx2b-consteval-propagate.cpp
index c0adbbdf9be6353..531a62622873357 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 at -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}}
+    // expected-note at -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 at -1 {{call to immediate function 'GH65985::escalating<int>' is not a constant expression}}
+    // expected-error at -2 {{constexpr variable 'a' must be initialized by a constant expression}}
+};
+
+}
+
 namespace GH66324 {
 
 consteval int allocate();  // expected-note  2{{declared here}}


        


More information about the cfe-commits mailing list