On Thu, Nov 17, 2022 at 07:42:40PM +0100, Jakub Jelinek via Gcc-patches wrote:
> I thought for older C++ this is to catch
> void
> foo ()
> {
>   constexpr int a = ({ static constexpr int b = 2; b; });
> }
> and for C++23 the only 3 spots that diagnose those.
> But perhaps for C++20 or older we can check if the var has a context
> of a constexpr function (then assume cp_finish_decl errored or pedwarned
> already) and only error or pedwarn otherwise.

So, here is an updated patch, which in constexpr.cc will accept
DECL_EXPR of decl_*constant_var_p static/thread_local non-extern vars
for C++23 or if they are not declared in constexpr/consteval function.
So, the statement expression case will remain hard error for C++ <= 20 rather 
than
pedwarn, because due to the ctx->quiet vs. !ctx->quiet case I don't see
what else we could do, either something is a constant expression, or
it is not, but whether it is or is not shouldn't depend on
-Wpedantic/-Wno-pedantic/-Werror=pedantic.

2022-11-17  Jakub Jelinek  <ja...@redhat.com>

gcc/c-family/
        * c-cppbuiltin.cc (c_cpp_builtins): Bump __cpp_constexpr
        value from 202207L to 202211L.
gcc/cp/
        * constexpr.cc (cxx_eval_constant_expression): Implement C++23
        P2647R1 - Permitting static constexpr variables in constexpr functions.
        Allow decl_constant_var_p static or thread_local vars for
        C++23 and later or if they are declared inside of constexpr or
        consteval function.
        (potential_constant_expression_1): Similarly, except use
        decl_maybe_constant_var_p instead of decl_constant_var_p if
        processing_template_decl.
        * decl.cc (diagnose_static_in_constexpr): New function.
        (start_decl): Remove diagnostics of static or thread_local
        vars in constexpr or consteval functions.
        (cp_finish_decl): Call diagnose_static_in_constexpr.
gcc/testsuite/
        * g++.dg/cpp23/constexpr-nonlit17.C: New test.
        * g++.dg/cpp23/constexpr-nonlit18.C: New test.
        * g++.dg/cpp23/constexpr-nonlit19.C: New test.
        * g++.dg/cpp23/constexpr-nonlit20.C: New test.
        * g++.dg/cpp23/feat-cxx2b.C: Adjust expected __cpp_constexpr
        value.
        * g++.dg/ext/stmtexpr19.C: Don't expect an error for C++20 or later. 

--- gcc/c-family/c-cppbuiltin.cc.jj     2022-11-17 09:00:42.106249011 +0100
+++ gcc/c-family/c-cppbuiltin.cc        2022-11-17 09:01:49.286320527 +0100
@@ -1074,7 +1074,7 @@ c_cpp_builtins (cpp_reader *pfile)
          /* Set feature test macros for C++23.  */
          cpp_define (pfile, "__cpp_size_t_suffix=202011L");
          cpp_define (pfile, "__cpp_if_consteval=202106L");
-         cpp_define (pfile, "__cpp_constexpr=202207L");
+         cpp_define (pfile, "__cpp_constexpr=202211L");
          cpp_define (pfile, "__cpp_multidimensional_subscript=202211L");
          cpp_define (pfile, "__cpp_named_character_escapes=202207L");
          cpp_define (pfile, "__cpp_static_call_operator=202207L");
--- gcc/cp/constexpr.cc.jj      2022-11-17 08:48:30.530357181 +0100
+++ gcc/cp/constexpr.cc 2022-11-17 20:53:15.432408015 +0100
@@ -7100,17 +7100,35 @@ cxx_eval_constant_expression (const cons
            /* Allow __FUNCTION__ etc.  */
            && !DECL_ARTIFICIAL (r))
          {
-           if (!ctx->quiet)
+           bool ok = decl_constant_var_p (r);
+           /* Since P2647R1 control can pass through definitions of static
+              or thread_local vars usable in constant expressions.
+              In C++20 or older, if such vars are declared inside of
+              constexpr or consteval function, diagnose_static_in_constexpr
+              should have already pedwarned on those.  Otherwise they could
+              be e.g. in a statement expression, reject those before
+              C++23.  */
+           if (ok && cxx_dialect < cxx23)
              {
-               if (CP_DECL_THREAD_LOCAL_P (r))
-                 error_at (loc, "control passes through definition of %qD "
-                                "with thread storage duration", r);
-               else
-                 error_at (loc, "control passes through definition of %qD "
-                                "with static storage duration", r);
+               tree fnctx = decl_function_context (r);
+               if (fnctx == NULL_TREE
+                   || !DECL_DECLARED_CONSTEXPR_P (fnctx))
+                 ok = false;
+             }
+           if (!ok)
+             {
+               if (!ctx->quiet)
+                 {
+                   if (CP_DECL_THREAD_LOCAL_P (r))
+                     error_at (loc, "control passes through definition of "
+                                    "%qD with thread storage duration", r);
+                   else
+                     error_at (loc, "control passes through definition of "
+                                    "%qD with static storage duration", r);
+                 }
+               *non_constant_p = true;
+               break;
              }
-           *non_constant_p = true;
-           break;
          }
 
        if (AGGREGATE_TYPE_P (TREE_TYPE (r))
@@ -9588,21 +9606,41 @@ potential_constant_expression_1 (tree t,
       tmp = DECL_EXPR_DECL (t);
       if (VAR_P (tmp) && !DECL_ARTIFICIAL (tmp))
        {
-         if (CP_DECL_THREAD_LOCAL_P (tmp) && !DECL_REALLY_EXTERN (tmp))
-           {
-             if (flags & tf_error)
-               constexpr_error (DECL_SOURCE_LOCATION (tmp), fundef_p,
-                                "%qD defined %<thread_local%> in "
-                                "%<constexpr%> context", tmp);
-             return false;
-           }
-         else if (TREE_STATIC (tmp))
+         if (TREE_STATIC (tmp)
+             || (CP_DECL_THREAD_LOCAL_P (tmp) && !DECL_REALLY_EXTERN (tmp)))
            {
-             if (flags & tf_error)
-               constexpr_error (DECL_SOURCE_LOCATION (tmp), fundef_p,
-                                "%qD defined %<static%> in %<constexpr%> "
-                                "context", tmp);
-             return false;
+             bool ok = (processing_template_decl
+                        ? decl_maybe_constant_var_p (tmp)
+                        : decl_constant_var_p (tmp));
+             /* Since P2647R1 control can pass through definitions of static
+                or thread_local vars usable in constant expressions.
+                In C++20 or older, if such vars are declared inside of
+                constexpr or consteval function, diagnose_static_in_constexpr
+                should have already pedwarned on those.  Otherwise they could
+                be e.g. in a statement expression, reject those before
+                C++23.  */
+             if (ok && cxx_dialect < cxx23)
+               {
+                 tree fnctx = decl_function_context (tmp);
+                 if (fnctx == NULL_TREE
+                     || !DECL_DECLARED_CONSTEXPR_P (fnctx))
+                   ok = false;
+               }
+             if (!ok)
+               {
+                 if (flags & tf_error)
+                   {
+                     if (CP_DECL_THREAD_LOCAL_P (tmp))
+                       constexpr_error (DECL_SOURCE_LOCATION (tmp), fundef_p,
+                                        "%qD defined %<thread_local%> in "
+                                        "%<constexpr%> context", tmp);
+                     else
+                       constexpr_error (DECL_SOURCE_LOCATION (tmp), fundef_p,
+                                        "%qD defined %<static%> in "
+                                        "%<constexpr%> context", tmp);
+                   }
+                 return false;
+               }
            }
          else if (!check_for_uninitialized_const_var
                   (tmp, /*constexpr_context_p=*/true, flags))
--- gcc/cp/decl.cc.jj   2022-11-16 14:44:43.692339668 +0100
+++ gcc/cp/decl.cc      2022-11-17 20:53:44.102011594 +0100
@@ -5600,6 +5600,57 @@ groktypename (cp_decl_specifier_seq *typ
   return type;
 }
 
+/* For C++17 and older diagnose static or thread_local decls in constexpr
+   or consteval functions.  For C++20 similarly, except if they are
+   usable in constant expressions.  */
+
+static void
+diagnose_static_in_constexpr (tree decl)
+{
+  if (cxx_dialect >= cxx23)
+    return;
+  if (current_function_decl
+      && VAR_P (decl)
+      && DECL_DECLARED_CONSTEXPR_P (current_function_decl))
+    {
+      bool ok = false;
+      if (processing_template_decl
+         ? decl_maybe_constant_var_p (decl)
+         : decl_constant_var_p (decl))
+       {
+         if (CP_DECL_THREAD_LOCAL_P (decl) && !DECL_REALLY_EXTERN (decl))
+           pedwarn (DECL_SOURCE_LOCATION (decl), OPT_Wpedantic,
+                    "%qD defined %<thread_local%> in %qs function only "
+                    "available with %<-std=c++2b%> or %<-std=gnu++2b%>", decl,
+                    DECL_IMMEDIATE_FUNCTION_P (current_function_decl)
+                    ? "consteval" : "constexpr");
+         else if (TREE_STATIC (decl))
+           pedwarn (DECL_SOURCE_LOCATION (decl), OPT_Wpedantic,
+                    "%qD defined %<static%> in %qs function only available "
+                    "with %<-std=c++2b%> or %<-std=gnu++2b%>", decl,
+                    DECL_IMMEDIATE_FUNCTION_P (current_function_decl)
+                    ? "consteval" : "constexpr");
+         ok = true;
+       }
+      else if (CP_DECL_THREAD_LOCAL_P (decl) && !DECL_REALLY_EXTERN (decl))
+       error_at (DECL_SOURCE_LOCATION (decl),
+                 "%qD defined %<thread_local%> in %qs function only "
+                 "available with %<-std=c++2b%> or %<-std=gnu++2b%>", decl,
+                 DECL_IMMEDIATE_FUNCTION_P (current_function_decl)
+                 ? "consteval" : "constexpr");
+      else if (TREE_STATIC (decl))
+       error_at (DECL_SOURCE_LOCATION (decl),
+                 "%qD defined %<static%> in %qs function only available "
+                 "with %<-std=c++2b%> or %<-std=gnu++2b%>", decl,
+                 DECL_IMMEDIATE_FUNCTION_P (current_function_decl)
+                 ? "consteval" : "constexpr");
+      else
+       ok = true;
+      if (!ok)
+       cp_function_chain->invalid_constexpr = true;
+    }
+}
+
 /* Process a DECLARATOR for a function-scope or namespace-scope
    variable or function declaration.
    (Function definitions go through start_function; class member
@@ -5860,29 +5911,6 @@ start_decl (const cp_declarator *declara
       DECL_THIS_STATIC (decl) = 1;
     }
 
-  if (current_function_decl && VAR_P (decl)
-      && DECL_DECLARED_CONSTEXPR_P (current_function_decl)
-      && cxx_dialect < cxx23)
-    {
-      bool ok = false;
-      if (CP_DECL_THREAD_LOCAL_P (decl) && !DECL_REALLY_EXTERN (decl))
-       error_at (DECL_SOURCE_LOCATION (decl),
-                 "%qD defined %<thread_local%> in %qs function only "
-                 "available with %<-std=c++2b%> or %<-std=gnu++2b%>", decl,
-                 DECL_IMMEDIATE_FUNCTION_P (current_function_decl)
-                 ? "consteval" : "constexpr");
-      else if (TREE_STATIC (decl))
-       error_at (DECL_SOURCE_LOCATION (decl),
-                 "%qD defined %<static%> in %qs function only available "
-                 "with %<-std=c++2b%> or %<-std=gnu++2b%>", decl,
-                 DECL_IMMEDIATE_FUNCTION_P (current_function_decl)
-                 ? "consteval" : "constexpr");
-      else
-       ok = true;
-      if (!ok)
-       cp_function_chain->invalid_constexpr = true;
-    }
-
   if (!processing_template_decl && VAR_P (decl))
     start_decl_1 (decl, initialized);
 
@@ -8424,6 +8452,9 @@ cp_finish_decl (tree decl, tree init, bo
          set_user_assembler_name (decl, asmspec);
          DECL_HARD_REGISTER (decl) = 1;
        }
+
+      diagnose_static_in_constexpr (decl);
+
       return;
     }
 
@@ -8749,6 +8780,8 @@ cp_finish_decl (tree decl, tree init, bo
       && !DECL_HARD_REGISTER (decl))
     targetm.lower_local_decl_alignment (decl);
 
+  diagnose_static_in_constexpr (decl);
+
   invoke_plugin_callbacks (PLUGIN_FINISH_DECL, decl);
 }
 
--- gcc/testsuite/g++.dg/cpp23/constexpr-nonlit17.C.jj  2022-11-17 
09:00:42.108248984 +0100
+++ gcc/testsuite/g++.dg/cpp23/constexpr-nonlit17.C     2022-11-17 
20:55:33.550498209 +0100
@@ -0,0 +1,12 @@
+// P2647R1 - Permitting static constexpr variables in constexpr functions
+// { dg-do compile { target c++23 } }
+
+constexpr char
+test ()
+{
+  static const int x = 5;
+  static constexpr char c[] = "Hello World";
+  return *(c + x);
+}
+
+static_assert (test () == ' ');
--- gcc/testsuite/g++.dg/cpp23/constexpr-nonlit18.C.jj  2022-11-17 
09:29:45.776136195 +0100
+++ gcc/testsuite/g++.dg/cpp23/constexpr-nonlit18.C     2022-11-17 
21:02:20.852865509 +0100
@@ -0,0 +1,49 @@
+// P2647R1 - Permitting static constexpr variables in constexpr functions
+// { dg-do compile { target c++14 } }
+
+constexpr int
+f1 (int x)
+{
+  if (x)
+    throw 1;
+  return 0;
+}
+
+constexpr int
+f2 ()
+{
+  static const int a = f1 (1);         // { dg-error "'a' defined 'static' in 
'constexpr' function only available with" "" { target c++20_down } }
+  return 0;
+}
+
+constexpr int
+f3 ()
+{
+  static const int a = 5;              // { dg-error "'a' defined 'static' in 
'constexpr' function only available with" "" { target c++20_down } }
+  return 0;
+}
+
+constexpr int
+f4 ()                                  // { dg-message "declared here" "" { 
target c++20_down } }
+{                                      // { dg-message "is not usable as a 
'constexpr' function because:" "" { target c++23 } .-1 }
+  static const int a = f1 (1);         // { dg-error "'a' defined 'static' in 
'constexpr' function only available with" "" { target c++20_down } }
+  return 0;                            // { dg-error "'a' defined 'static' in 
'constexpr' context" "" { target c++23 } .-1 }
+}
+
+constexpr int a4 = f4 ();              // { dg-error "called in a constant 
expression" }
+
+constexpr int
+f5 ()
+{
+  static const int a = f1 (0);         // { dg-error "'a' defined 'static' in 
'constexpr' function only available with" "" { target c++20_down } }
+  return 0;
+}
+
+constexpr int
+f6 ()
+{
+  static const int a = f1 (0);         // { dg-error "'a' defined 'static' in 
'constexpr' function only available with" "" { target c++20_down } }
+  return 0;
+}
+
+constexpr int a6 = f6 ();
--- gcc/testsuite/g++.dg/cpp23/constexpr-nonlit19.C.jj  2022-11-17 
20:56:07.887023431 +0100
+++ gcc/testsuite/g++.dg/cpp23/constexpr-nonlit19.C     2022-11-17 
21:04:12.618319027 +0100
@@ -0,0 +1,50 @@
+// P2647R1 - Permitting static constexpr variables in constexpr functions
+// { dg-do compile { target c++14 } }
+// { dg-options "-pedantic" }
+
+constexpr int
+f1 (int x)
+{
+  if (x)
+    throw 1;
+  return 0;
+}
+
+constexpr int
+f2 ()
+{
+  static const int a = f1 (1);         // { dg-error "'a' defined 'static' in 
'constexpr' function only available with" "" { target c++20_down } }
+  return 0;
+}
+
+constexpr int
+f3 ()
+{
+  static const int a = 5;              // { dg-warning "'a' defined 'static' 
in 'constexpr' function only available with" "" { target c++20_down } }
+  return 0;
+}
+
+constexpr int
+f4 ()                                  // { dg-message "declared here" "" { 
target c++20_down } }
+{                                      // { dg-message "is not usable as a 
'constexpr' function because:" "" { target c++23 } .-1 }
+  static const int a = f1 (1);         // { dg-error "'a' defined 'static' in 
'constexpr' function only available with" "" { target c++20_down } }
+  return 0;                            // { dg-error "'a' defined 'static' in 
'constexpr' context" "" { target c++23 } .-1 }
+}
+
+constexpr int a4 = f4 ();              // { dg-error "called in a constant 
expression" }
+
+constexpr int
+f5 ()
+{
+  static const int a = f1 (0);         // { dg-warning "'a' defined 'static' 
in 'constexpr' function only available with" "" { target c++20_down } }
+  return 0;
+}
+
+constexpr int
+f6 ()
+{
+  static const int a = f1 (0);         // { dg-warning "'a' defined 'static' 
in 'constexpr' function only available with" "" { target c++20_down } }
+  return 0;
+}
+
+constexpr int a6 = f6 ();
--- gcc/testsuite/g++.dg/cpp23/constexpr-nonlit20.C.jj  2022-11-17 
20:56:28.527738024 +0100
+++ gcc/testsuite/g++.dg/cpp23/constexpr-nonlit20.C     2022-11-17 
21:31:25.209729268 +0100
@@ -0,0 +1,50 @@
+// P2647R1 - Permitting static constexpr variables in constexpr functions
+// { dg-do compile { target c++14 } }
+// { dg-options "-Wno-pedantic" }
+
+constexpr int
+f1 (int x)
+{
+  if (x)
+    throw 1;
+  return 0;
+}
+
+constexpr int
+f2 ()
+{
+  static const int a = f1 (1);         // { dg-error "'a' defined 'static' in 
'constexpr' function only available with" "" { target c++20_down } }
+  return 0;
+}
+
+constexpr int
+f3 ()
+{
+  static const int a = 5;
+  return 0;
+}
+
+constexpr int
+f4 ()                                  // { dg-message "declared here" "" { 
target c++20_down } }
+{                                      // { dg-message "is not usable as a 
'constexpr' function because:" "" { target c++23 } .-1 }
+  static const int a = f1 (1);         // { dg-error "'a' defined 'static' in 
'constexpr' function only available with" "" { target c++20_down } }
+  return 0;                            // { dg-error "'a' defined 'static' in 
'constexpr' context" "" { target c++23 } .-1 }
+}
+
+constexpr int a4 = f4 ();              // { dg-error "called in a constant 
expression" }
+
+constexpr int
+f5 ()
+{
+  static const int a = f1 (0);
+  return 0;
+}
+
+constexpr int
+f6 ()
+{
+  static const int a = f1 (0);
+  return 0;
+}
+
+constexpr int a6 = f6 ();
--- gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C.jj  2022-11-17 08:48:30.561356753 
+0100
+++ gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C     2022-11-17 09:00:42.108248984 
+0100
@@ -134,8 +134,8 @@
 
 #ifndef __cpp_constexpr
 #  error "__cpp_constexpr"
-#elif __cpp_constexpr != 202207
-#  error "__cpp_constexpr != 202207"
+#elif __cpp_constexpr != 202211
+#  error "__cpp_constexpr != 202211"
 #endif
 
 #ifndef __cpp_decltype_auto
--- gcc/testsuite/g++.dg/ext/stmtexpr19.C.jj    2022-11-17 08:48:02.730741221 
+0100
+++ gcc/testsuite/g++.dg/ext/stmtexpr19.C       2022-11-17 20:57:06.936206927 
+0100
@@ -8,7 +8,7 @@ const test* setup()
 {
   static constexpr test atest =
     {
-      ({ static const int inner = 123; &inner; }) // { dg-error "static" }
+      ({ static const int inner = 123; &inner; }) // { dg-error "static" "" { 
target c++20_down } }
     };
 
   return &atest;


        Jakub

Reply via email to