c++, v5: Implement C++23 P2647R1 - Permitting static constexpr variables in constexpr functions

Message ID Y3dL8nv/qF+qb1j3@tucnak
State New
Headers
Series c++, v5: Implement C++23 P2647R1 - Permitting static constexpr variables in constexpr functions |

Commit Message

Jakub Jelinek Nov. 18, 2022, 9:10 a.m. UTC
  On Thu, Nov 17, 2022 at 07:28:56PM -0500, Jason Merrill wrote:
> On 11/17/22 15:42, Jakub Jelinek wrote:
> > 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.
> 
> We could, but I wouldn't bother to enforce this specially for
> statement-expressions, which are already an extension.

Ok.

> OTOH, we should test that static constexpr is handled properly for lambdas,
> i.e. this should still fail:
> 
> constexpr int q = [](int i)
> { static constexpr int x = 42; return x+i; }(24);

I guess that is related on how to handle the
lambda-generic-func1.C constexpr-lambda16.C
FAILs.

Attached are 3 patches, one is just an updated version of the previous
patch with simplified constexpr.cc (and fixed the function comment
Marek talked about), this one will accept the statement
expression case with decl_constant_var_p static in it, and passes
GXX_TESTSUITE_STDS=98,11,14,17,20,2b make check-g++ \
RUNTESTFLAGS="--target_board=unix\{-m32,-m64\} dg.exp='constexpr-nonlit* feat-cxx2b* stmtexpr19.C stmtexpr25.C lambda-generic-func1.C constexpr-lambda16.C'"
except for:
+FAIL: g++.dg/cpp1y/lambda-generic-func1.C  -std=c++17 (test for excess errors)
+FAIL: g++.dg/cpp1y/lambda-generic-func1.C  -std=c++20 (test for excess errors)
+FAIL: g++.dg/cpp1z/constexpr-lambda16.C  -std=c++17 (test for excess errors)
+FAIL: g++.dg/cpp1z/constexpr-lambda16.C  -std=c++20 (test for excess errors)
plus the testcase above needs to be dealt with if we want to pedwarn on it
for older C++.

The third one is if we just want something for C++23 and don't want to touch
C++20 and older at all (that one doesn't regress anything), the second one
similarly but will no longer reject the statement expression cases for C++11
.. 20.

	Jakub
2022-11-18  Jakub Jelinek  <jakub@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_EXPRs of decl_constant_var_p static or thread_local vars.
	(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.
	* g++.dg/ext/stmtexpr25.C: New test.
2022-11-18  Jakub Jelinek  <jakub@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_EXPRs of decl_constant_var_p static or thread_local vars.
	(potential_constant_expression_1): Similarly, except use
	decl_maybe_constant_var_p instead of decl_constant_var_p if
	processing_template_decl.
gcc/testsuite/
	* g++.dg/cpp23/constexpr-nonlit17.C: New test.
	* g++.dg/cpp23/constexpr-nonlit18.C: New test.
	* g++.dg/cpp23/feat-cxx2b.C: Adjust expected __cpp_constexpr
	value.
	* g++.dg/ext/stmtexpr19.C: Don't expect an error.
	* g++.dg/ext/stmtexpr25.C: New test.

--- gcc/c-family/c-cppbuiltin.cc.jj	2022-11-18 09:00:17.102704379 +0100
+++ gcc/c-family/c-cppbuiltin.cc	2022-11-18 09:32:00.389372850 +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-18 09:00:17.108704295 +0100
+++ gcc/cp/constexpr.cc	2022-11-18 09:35:39.822342414 +0100
@@ -7098,7 +7098,8 @@ cxx_eval_constant_expression (const cons
 	    && (TREE_STATIC (r)
 		|| (CP_DECL_THREAD_LOCAL_P (r) && !DECL_REALLY_EXTERN (r)))
 	    /* Allow __FUNCTION__ etc.  */
-	    && !DECL_ARTIFICIAL (r))
+	    && !DECL_ARTIFICIAL (r)
+	    && !decl_constant_var_p (r))
 	  {
 	    if (!ctx->quiet)
 	      {
@@ -9586,7 +9587,10 @@ potential_constant_expression_1 (tree t,
 
     case DECL_EXPR:
       tmp = DECL_EXPR_DECL (t);
-      if (VAR_P (tmp) && !DECL_ARTIFICIAL (tmp))
+      if (VAR_P (tmp) && !DECL_ARTIFICIAL (tmp)
+	  && (processing_template_decl
+	      ? !decl_maybe_constant_var_p (tmp)
+	      : !decl_constant_var_p (tmp)))
 	{
 	  if (CP_DECL_THREAD_LOCAL_P (tmp) && !DECL_REALLY_EXTERN (tmp))
 	    {
--- gcc/testsuite/g++.dg/cpp23/constexpr-nonlit17.C.jj	2022-11-18 09:32:00.393372795 +0100
+++ gcc/testsuite/g++.dg/cpp23/constexpr-nonlit17.C	2022-11-18 09:32:00.393372795 +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-18 09:32:00.394372781 +0100
+++ gcc/testsuite/g++.dg/cpp23/constexpr-nonlit18.C	2022-11-18 09:57:48.159986371 +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 ();		// { dg-error "called in a constant expression" "" { target c++20_down } }
--- gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C.jj	2022-11-18 09:00:17.293701708 +0100
+++ gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C	2022-11-18 09:32:00.394372781 +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-18 09:00:17.367700673 +0100
+++ gcc/testsuite/g++.dg/ext/stmtexpr19.C	2022-11-18 09:43:20.682975254 +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; })
     };
 
   return &atest;
--- gcc/testsuite/g++.dg/ext/stmtexpr25.C.jj	2022-11-18 09:43:08.505143556 +0100
+++ gcc/testsuite/g++.dg/ext/stmtexpr25.C	2022-11-18 09:44:39.672883560 +0100
@@ -0,0 +1,17 @@
+// PR c++/81073
+// { dg-options "" }
+// { dg-do compile { target c++11 } }
+
+struct test { const int *addr; };
+
+const test* setup()
+{
+  static constexpr test atest =
+    {
+      ({ static const int inner = (throw 1, 1); &inner; }) // { dg-error "static" "" }
+    };
+
+  return &atest;
+}
+
+int main(){}
2022-11-18  Jakub Jelinek  <jakub@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_EXPRs of decl_constant_var_p static or thread_local vars
	for C++23.
	(potential_constant_expression_1): Similarly, except use
	decl_maybe_constant_var_p instead of decl_constant_var_p if
	processing_template_decl.
gcc/testsuite/
	* g++.dg/cpp23/constexpr-nonlit17.C: New test.
	* g++.dg/cpp23/constexpr-nonlit18.C: New test.
	* g++.dg/cpp23/feat-cxx2b.C: Adjust expected __cpp_constexpr
	value.
	* g++.dg/ext/stmtexpr19.C: Don't expect an error.
	* g++.dg/ext/stmtexpr25.C: New test.

--- gcc/c-family/c-cppbuiltin.cc.jj	2022-11-18 09:00:17.102704379 +0100
+++ gcc/c-family/c-cppbuiltin.cc	2022-11-18 09:32:00.389372850 +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-18 09:00:17.108704295 +0100
+++ gcc/cp/constexpr.cc	2022-11-18 09:35:39.822342414 +0100
@@ -7098,7 +7098,8 @@ cxx_eval_constant_expression (const cons
 	    && (TREE_STATIC (r)
 		|| (CP_DECL_THREAD_LOCAL_P (r) && !DECL_REALLY_EXTERN (r)))
 	    /* Allow __FUNCTION__ etc.  */
-	    && !DECL_ARTIFICIAL (r))
+	    && !DECL_ARTIFICIAL (r)
+	    && (cxx_dialect < cxx23 || !decl_constant_var_p (r)))
 	  {
 	    if (!ctx->quiet)
 	      {
@@ -9586,7 +9587,10 @@ potential_constant_expression_1 (tree t,
 
     case DECL_EXPR:
       tmp = DECL_EXPR_DECL (t);
-      if (VAR_P (tmp) && !DECL_ARTIFICIAL (tmp))
+      if (VAR_P (tmp) && !DECL_ARTIFICIAL (tmp)
+	  && (cxx_dialect < cxx23 || (processing_template_decl
+				      ? !decl_maybe_constant_var_p (tmp)
+				      : !decl_constant_var_p (tmp))))
 	{
 	  if (CP_DECL_THREAD_LOCAL_P (tmp) && !DECL_REALLY_EXTERN (tmp))
 	    {
--- gcc/testsuite/g++.dg/cpp23/constexpr-nonlit17.C.jj	2022-11-18 09:32:00.393372795 +0100
+++ gcc/testsuite/g++.dg/cpp23/constexpr-nonlit17.C	2022-11-18 09:32:00.393372795 +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-18 09:32:00.394372781 +0100
+++ gcc/testsuite/g++.dg/cpp23/constexpr-nonlit18.C	2022-11-18 09:57:48.159986371 +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 ();		// { dg-error "called in a constant expression" "" { target c++20_down } }
--- gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C.jj	2022-11-18 09:00:17.293701708 +0100
+++ gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C	2022-11-18 09:32:00.394372781 +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-18 09:00:17.367700673 +0100
+++ gcc/testsuite/g++.dg/ext/stmtexpr19.C	2022-11-18 09:43:20.682975254 +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 } .-1 }
     };
 
   return &atest;
--- gcc/testsuite/g++.dg/ext/stmtexpr25.C.jj	2022-11-18 09:43:08.505143556 +0100
+++ gcc/testsuite/g++.dg/ext/stmtexpr25.C	2022-11-18 09:44:39.672883560 +0100
@@ -0,0 +1,17 @@
+// PR c++/81073
+// { dg-options "" }
+// { dg-do compile { target c++11 } }
+
+struct test { const int *addr; };
+
+const test* setup()
+{
+  static constexpr test atest =
+    {
+      ({ static const int inner = (throw 1, 1); &inner; }) // { dg-error "static" "" }
+    };
+
+  return &atest;
+}
+
+int main(){}
  

Patch

--- gcc/c-family/c-cppbuiltin.cc.jj	2022-11-18 09:00:17.102704379 +0100
+++ gcc/c-family/c-cppbuiltin.cc	2022-11-18 09:32:00.389372850 +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-18 09:00:17.108704295 +0100
+++ gcc/cp/constexpr.cc	2022-11-18 09:35:39.822342414 +0100
@@ -7098,7 +7098,8 @@  cxx_eval_constant_expression (const cons
 	    && (TREE_STATIC (r)
 		|| (CP_DECL_THREAD_LOCAL_P (r) && !DECL_REALLY_EXTERN (r)))
 	    /* Allow __FUNCTION__ etc.  */
-	    && !DECL_ARTIFICIAL (r))
+	    && !DECL_ARTIFICIAL (r)
+	    && !decl_constant_var_p (r))
 	  {
 	    if (!ctx->quiet)
 	      {
@@ -9586,7 +9587,10 @@  potential_constant_expression_1 (tree t,
 
     case DECL_EXPR:
       tmp = DECL_EXPR_DECL (t);
-      if (VAR_P (tmp) && !DECL_ARTIFICIAL (tmp))
+      if (VAR_P (tmp) && !DECL_ARTIFICIAL (tmp)
+	  && (processing_template_decl
+	      ? !decl_maybe_constant_var_p (tmp)
+	      : !decl_constant_var_p (tmp)))
 	{
 	  if (CP_DECL_THREAD_LOCAL_P (tmp) && !DECL_REALLY_EXTERN (tmp))
 	    {
--- gcc/cp/decl.cc.jj	2022-11-18 09:03:51.592704514 +0100
+++ gcc/cp/decl.cc	2022-11-18 09:32:00.393372795 +0100
@@ -5600,6 +5600,57 @@  groktypename (cp_decl_specifier_seq *typ
   return type;
 }
 
+/* For C++20 and older diagnose static or thread_local decls in constexpr
+   or consteval functions.  If they are usable in constant expressions,
+   just pedwarn on them.  */
+
+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-18 09:32:00.393372795 +0100
+++ gcc/testsuite/g++.dg/cpp23/constexpr-nonlit17.C	2022-11-18 09:32:00.393372795 +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-18 09:32:00.394372781 +0100
+++ gcc/testsuite/g++.dg/cpp23/constexpr-nonlit18.C	2022-11-18 09:32:00.394372781 +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-18 09:32:00.394372781 +0100
+++ gcc/testsuite/g++.dg/cpp23/constexpr-nonlit19.C	2022-11-18 09:32:00.394372781 +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-18 09:32:00.394372781 +0100
+++ gcc/testsuite/g++.dg/cpp23/constexpr-nonlit20.C	2022-11-18 09:32:00.394372781 +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-18 09:00:17.293701708 +0100
+++ gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C	2022-11-18 09:32:00.394372781 +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-18 09:00:17.367700673 +0100
+++ gcc/testsuite/g++.dg/ext/stmtexpr19.C	2022-11-18 09:43:20.682975254 +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; })
     };
 
   return &atest;
--- gcc/testsuite/g++.dg/ext/stmtexpr25.C.jj	2022-11-18 09:43:08.505143556 +0100
+++ gcc/testsuite/g++.dg/ext/stmtexpr25.C	2022-11-18 09:44:39.672883560 +0100
@@ -0,0 +1,17 @@ 
+// PR c++/81073
+// { dg-options "" }
+// { dg-do compile { target c++11 } }
+
+struct test { const int *addr; };
+
+const test* setup()
+{
+  static constexpr test atest =
+    {
+      ({ static const int inner = (throw 1, 1); &inner; }) // { dg-error "static" "" }
+    };
+
+  return &atest;
+}
+
+int main(){}