public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] c++: Implement C++23 P2647R1 - Permitting static constexpr variables in constexpr functions
@ 2022-11-11 17:07 Jakub Jelinek
  2022-11-13 11:45 ` [PATCH] c++, v2: " Jakub Jelinek
  0 siblings, 1 reply; 25+ messages in thread
From: Jakub Jelinek @ 2022-11-11 17:07 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, Marek Polacek

Hi!

The following patch on top of Marek's P2448 PR106649 patch
(mainly because that patch implements the previous __cpp_constexpr
feature test macro bump so this can't go in earlier; OT,
P2280R4 doesn't have any feature test macro?) implements this
simple paper.

Ok for trunk if it passes bootstrap/regtest and is voted into C++23?

2022-11-11  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_maybe_constant_var_p static or thread_local vars for
	C++23.
	(potential_constant_expression_1): Likewise.
gcc/testsuite/
	* g++.dg/cpp23/constexpr-nonlit17.C: New test.
	* g++.dg/cpp23/feat-cxx2b.C: Adjust expected __cpp_constexpr
	value.

--- gcc/c-family/c-cppbuiltin.cc.jj	2022-11-11 17:14:52.021613271 +0100
+++ gcc/c-family/c-cppbuiltin.cc	2022-11-11 17:17:45.065265246 +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=202110L");
 	  cpp_define (pfile, "__cpp_named_character_escapes=202207L");
 	  cpp_define (pfile, "__cpp_static_call_operator=202207L");
--- gcc/cp/constexpr.cc.jj	2022-11-11 17:14:52.024613231 +0100
+++ gcc/cp/constexpr.cc	2022-11-11 17:16:54.384952917 +0100
@@ -7085,7 +7085,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_maybe_constant_var_p (r)))
 	  {
 	    if (!ctx->quiet)
 	      {
@@ -9577,7 +9578,10 @@ 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 (CP_DECL_THREAD_LOCAL_P (tmp)
+	      && !DECL_REALLY_EXTERN (tmp)
+	      && (cxx_dialect < cxx23
+		  || !decl_maybe_constant_var_p (tmp)))
 	    {
 	      if (flags & tf_error)
 		constexpr_error (DECL_SOURCE_LOCATION (tmp), fundef_p,
@@ -9585,7 +9589,9 @@ potential_constant_expression_1 (tree t,
 				 "%<constexpr%> context", tmp);
 	      return false;
 	    }
-	  else if (TREE_STATIC (tmp))
+	  else if (TREE_STATIC (tmp)
+		   && (cxx_dialect < cxx23
+		       || !decl_maybe_constant_var_p (tmp)))
 	    {
 	      if (flags & tf_error)
 		constexpr_error (DECL_SOURCE_LOCATION (tmp), fundef_p,
--- gcc/testsuite/g++.dg/cpp23/constexpr-nonlit17.C.jj	2022-11-11 17:59:59.972852793 +0100
+++ gcc/testsuite/g++.dg/cpp23/constexpr-nonlit17.C	2022-11-11 17:59:38.725141231 +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/feat-cxx2b.C.jj	2022-11-11 17:14:52.194610922 +0100
+++ gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C	2022-11-11 17:48:56.038865825 +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

	Jakub


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH] c++, v2: Implement C++23 P2647R1 - Permitting static constexpr variables in constexpr functions
  2022-11-11 17:07 [PATCH] c++: Implement C++23 P2647R1 - Permitting static constexpr variables in constexpr functions Jakub Jelinek
@ 2022-11-13 11:45 ` Jakub Jelinek
  2022-11-15 23:36   ` Jason Merrill
  0 siblings, 1 reply; 25+ messages in thread
From: Jakub Jelinek @ 2022-11-13 11:45 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, Marek Polacek

On Fri, Nov 11, 2022 at 06:07:04PM +0100, Jakub Jelinek wrote:
> The following patch on top of Marek's P2448 PR106649 patch
> (mainly because that patch implements the previous __cpp_constexpr
> feature test macro bump so this can't go in earlier; OT,
> P2280R4 doesn't have any feature test macro?) implements this
> simple paper.
> 
> Ok for trunk if it passes bootstrap/regtest and is voted into C++23?

Here is an updated patch that passed bootstrap/regtest, the only
change is another testcase tweak.

2022-11-13  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_maybe_constant_var_p static or thread_local vars for
	C++23.
	(potential_constant_expression_1): Likewise.
gcc/testsuite/
	* g++.dg/cpp23/constexpr-nonlit17.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++23 or later. 

--- gcc/c-family/c-cppbuiltin.cc.jj	2022-11-11 17:14:52.021613271 +0100
+++ gcc/c-family/c-cppbuiltin.cc	2022-11-11 17:17:45.065265246 +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=202110L");
 	  cpp_define (pfile, "__cpp_named_character_escapes=202207L");
 	  cpp_define (pfile, "__cpp_static_call_operator=202207L");
--- gcc/cp/constexpr.cc.jj	2022-11-11 17:14:52.024613231 +0100
+++ gcc/cp/constexpr.cc	2022-11-11 17:16:54.384952917 +0100
@@ -7085,7 +7085,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_maybe_constant_var_p (r)))
 	  {
 	    if (!ctx->quiet)
 	      {
@@ -9577,7 +9578,10 @@ 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 (CP_DECL_THREAD_LOCAL_P (tmp)
+	      && !DECL_REALLY_EXTERN (tmp)
+	      && (cxx_dialect < cxx23
+		  || !decl_maybe_constant_var_p (tmp)))
 	    {
 	      if (flags & tf_error)
 		constexpr_error (DECL_SOURCE_LOCATION (tmp), fundef_p,
@@ -9585,7 +9589,9 @@ potential_constant_expression_1 (tree t,
 				 "%<constexpr%> context", tmp);
 	      return false;
 	    }
-	  else if (TREE_STATIC (tmp))
+	  else if (TREE_STATIC (tmp)
+		   && (cxx_dialect < cxx23
+		       || !decl_maybe_constant_var_p (tmp)))
 	    {
 	      if (flags & tf_error)
 		constexpr_error (DECL_SOURCE_LOCATION (tmp), fundef_p,
--- gcc/testsuite/g++.dg/cpp23/constexpr-nonlit17.C.jj	2022-11-11 17:59:59.972852793 +0100
+++ gcc/testsuite/g++.dg/cpp23/constexpr-nonlit17.C	2022-11-11 17:59:38.725141231 +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/feat-cxx2b.C.jj	2022-11-11 17:14:52.194610922 +0100
+++ gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C	2022-11-11 17:48:56.038865825 +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	2020-01-14 20:02:46.839608995 +0100
+++ gcc/testsuite/g++.dg/ext/stmtexpr19.C	2022-11-12 09:17:40.706245495 +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


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] c++, v2: Implement C++23 P2647R1 - Permitting static constexpr variables in constexpr functions
  2022-11-13 11:45 ` [PATCH] c++, v2: " Jakub Jelinek
@ 2022-11-15 23:36   ` Jason Merrill
  2022-11-15 23:50     ` Jakub Jelinek
  2022-11-16  0:26     ` [PATCH] c++, v2: " Jonathan Wakely
  0 siblings, 2 replies; 25+ messages in thread
From: Jason Merrill @ 2022-11-15 23:36 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches, Marek Polacek, Jonathan Wakely

On 11/13/22 01:45, Jakub Jelinek wrote:
> On Fri, Nov 11, 2022 at 06:07:04PM +0100, Jakub Jelinek wrote:
>> The following patch on top of Marek's P2448 PR106649 patch
>> (mainly because that patch implements the previous __cpp_constexpr
>> feature test macro bump so this can't go in earlier; OT,
>> P2280R4 doesn't have any feature test macro?) implements this
>> simple paper.
>>
>> Ok for trunk if it passes bootstrap/regtest and is voted into C++23?
> 
> Here is an updated patch that passed bootstrap/regtest, the only
> change is another testcase tweak.
> 
> 2022-11-13  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_maybe_constant_var_p static or thread_local vars for
> 	C++23.

This was accepted as a DR, so it shouldn't be limited to C++23 mode. 
Certainly it should be allowed in C++20 mode; I don't have a strong 
opinion about C++14/17.  Jonathan, do you?

> 	(potential_constant_expression_1): Likewise.
> gcc/testsuite/
> 	* g++.dg/cpp23/constexpr-nonlit17.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++23 or later.
> 
> --- gcc/c-family/c-cppbuiltin.cc.jj	2022-11-11 17:14:52.021613271 +0100
> +++ gcc/c-family/c-cppbuiltin.cc	2022-11-11 17:17:45.065265246 +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=202110L");
>   	  cpp_define (pfile, "__cpp_named_character_escapes=202207L");
>   	  cpp_define (pfile, "__cpp_static_call_operator=202207L");
> --- gcc/cp/constexpr.cc.jj	2022-11-11 17:14:52.024613231 +0100
> +++ gcc/cp/constexpr.cc	2022-11-11 17:16:54.384952917 +0100
> @@ -7085,7 +7085,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_maybe_constant_var_p (r)))
>   	  {
>   	    if (!ctx->quiet)
>   	      {
> @@ -9577,7 +9578,10 @@ 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 (CP_DECL_THREAD_LOCAL_P (tmp)
> +	      && !DECL_REALLY_EXTERN (tmp)
> +	      && (cxx_dialect < cxx23
> +		  || !decl_maybe_constant_var_p (tmp)))
>   	    {
>   	      if (flags & tf_error)
>   		constexpr_error (DECL_SOURCE_LOCATION (tmp), fundef_p,
> @@ -9585,7 +9589,9 @@ potential_constant_expression_1 (tree t,
>   				 "%<constexpr%> context", tmp);
>   	      return false;
>   	    }
> -	  else if (TREE_STATIC (tmp))
> +	  else if (TREE_STATIC (tmp)
> +		   && (cxx_dialect < cxx23
> +		       || !decl_maybe_constant_var_p (tmp)))
>   	    {
>   	      if (flags & tf_error)
>   		constexpr_error (DECL_SOURCE_LOCATION (tmp), fundef_p,
> --- gcc/testsuite/g++.dg/cpp23/constexpr-nonlit17.C.jj	2022-11-11 17:59:59.972852793 +0100
> +++ gcc/testsuite/g++.dg/cpp23/constexpr-nonlit17.C	2022-11-11 17:59:38.725141231 +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/feat-cxx2b.C.jj	2022-11-11 17:14:52.194610922 +0100
> +++ gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C	2022-11-11 17:48:56.038865825 +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	2020-01-14 20:02:46.839608995 +0100
> +++ gcc/testsuite/g++.dg/ext/stmtexpr19.C	2022-11-12 09:17:40.706245495 +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
> 


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] c++, v2: Implement C++23 P2647R1 - Permitting static constexpr variables in constexpr functions
  2022-11-15 23:36   ` Jason Merrill
@ 2022-11-15 23:50     ` Jakub Jelinek
  2022-11-16  0:27       ` Jonathan Wakely
  2022-11-16  0:26     ` [PATCH] c++, v2: " Jonathan Wakely
  1 sibling, 1 reply; 25+ messages in thread
From: Jakub Jelinek @ 2022-11-15 23:50 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, Marek Polacek, Jonathan Wakely

On Tue, Nov 15, 2022 at 06:36:38PM -0500, Jason Merrill wrote:
> > Here is an updated patch that passed bootstrap/regtest, the only
> > change is another testcase tweak.
> > 
> > 2022-11-13  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_maybe_constant_var_p static or thread_local vars for
> > 	C++23.
> 
> This was accepted as a DR, so it shouldn't be limited to C++23 mode.
> Certainly it should be allowed in C++20 mode; I don't have a strong opinion
> about C++14/17.  Jonathan, do you?

How will a feature with feature test macro with multiple values work as DR?
Or will everything but the macro be treated as a DR (so __cpp_constexpr >=
202211L only for C++23)?
Because __cpp_constexpr >= 202211L is >= 202207L too and that implies
P2448R2 which wasn't a DR and >= 202110L which implies P2242R3 which wasn't a
DR.  And C++20 added other 2 non-DR papers that bumped the value.
C++17 another one.

> > 	(potential_constant_expression_1): Likewise.
> > gcc/testsuite/
> > 	* g++.dg/cpp23/constexpr-nonlit17.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++23 or later.

	Jakub


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] c++, v2: Implement C++23 P2647R1 - Permitting static constexpr variables in constexpr functions
  2022-11-15 23:36   ` Jason Merrill
  2022-11-15 23:50     ` Jakub Jelinek
@ 2022-11-16  0:26     ` Jonathan Wakely
  1 sibling, 0 replies; 25+ messages in thread
From: Jonathan Wakely @ 2022-11-16  0:26 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Jakub Jelinek, gcc-patches, Marek Polacek

On Tue, 15 Nov 2022 at 23:36, Jason Merrill <jason@redhat.com> wrote:
>
> On 11/13/22 01:45, Jakub Jelinek wrote:
> > On Fri, Nov 11, 2022 at 06:07:04PM +0100, Jakub Jelinek wrote:
> >> The following patch on top of Marek's P2448 PR106649 patch
> >> (mainly because that patch implements the previous __cpp_constexpr
> >> feature test macro bump so this can't go in earlier; OT,
> >> P2280R4 doesn't have any feature test macro?) implements this
> >> simple paper.
> >>
> >> Ok for trunk if it passes bootstrap/regtest and is voted into C++23?
> >
> > Here is an updated patch that passed bootstrap/regtest, the only
> > change is another testcase tweak.
> >
> > 2022-11-13  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_maybe_constant_var_p static or thread_local vars for
> >       C++23.
>
> This was accepted as a DR, so it shouldn't be limited to C++23 mode.
> Certainly it should be allowed in C++20 mode; I don't have a strong
> opinion about C++14/17.  Jonathan, do you?

I don't. The lack of this feature caused some awkwardness implementing
a C++23 library feature in <charconv>, but that means my desire for it
was only in C++23 mode. And that has been mitigated by changes Patrick
made to work around it anyway.

I think it does make sense for C++20, where constexpr is pretty close
to "normal" code, what with dynamic allocations, std::string etc. but
I don't see a great need for it before C++20.

>
> >       (potential_constant_expression_1): Likewise.
> > gcc/testsuite/
> >       * g++.dg/cpp23/constexpr-nonlit17.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++23 or later.
> >
> > --- gcc/c-family/c-cppbuiltin.cc.jj   2022-11-11 17:14:52.021613271 +0100
> > +++ gcc/c-family/c-cppbuiltin.cc      2022-11-11 17:17:45.065265246 +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=202110L");
> >         cpp_define (pfile, "__cpp_named_character_escapes=202207L");
> >         cpp_define (pfile, "__cpp_static_call_operator=202207L");
> > --- gcc/cp/constexpr.cc.jj    2022-11-11 17:14:52.024613231 +0100
> > +++ gcc/cp/constexpr.cc       2022-11-11 17:16:54.384952917 +0100
> > @@ -7085,7 +7085,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_maybe_constant_var_p (r)))
> >         {
> >           if (!ctx->quiet)
> >             {
> > @@ -9577,7 +9578,10 @@ 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 (CP_DECL_THREAD_LOCAL_P (tmp)
> > +           && !DECL_REALLY_EXTERN (tmp)
> > +           && (cxx_dialect < cxx23
> > +               || !decl_maybe_constant_var_p (tmp)))
> >           {
> >             if (flags & tf_error)
> >               constexpr_error (DECL_SOURCE_LOCATION (tmp), fundef_p,
> > @@ -9585,7 +9589,9 @@ potential_constant_expression_1 (tree t,
> >                                "%<constexpr%> context", tmp);
> >             return false;
> >           }
> > -       else if (TREE_STATIC (tmp))
> > +       else if (TREE_STATIC (tmp)
> > +                && (cxx_dialect < cxx23
> > +                    || !decl_maybe_constant_var_p (tmp)))
> >           {
> >             if (flags & tf_error)
> >               constexpr_error (DECL_SOURCE_LOCATION (tmp), fundef_p,
> > --- gcc/testsuite/g++.dg/cpp23/constexpr-nonlit17.C.jj        2022-11-11 17:59:59.972852793 +0100
> > +++ gcc/testsuite/g++.dg/cpp23/constexpr-nonlit17.C   2022-11-11 17:59:38.725141231 +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/feat-cxx2b.C.jj        2022-11-11 17:14:52.194610922 +0100
> > +++ gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C   2022-11-11 17:48:56.038865825 +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  2020-01-14 20:02:46.839608995 +0100
> > +++ gcc/testsuite/g++.dg/ext/stmtexpr19.C     2022-11-12 09:17:40.706245495 +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
> >
>


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] c++, v2: Implement C++23 P2647R1 - Permitting static constexpr variables in constexpr functions
  2022-11-15 23:50     ` Jakub Jelinek
@ 2022-11-16  0:27       ` Jonathan Wakely
  2022-11-16  6:19         ` Jakub Jelinek
  0 siblings, 1 reply; 25+ messages in thread
From: Jonathan Wakely @ 2022-11-16  0:27 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Jason Merrill, gcc-patches, Marek Polacek

On Tue, 15 Nov 2022 at 23:50, Jakub Jelinek <jakub@redhat.com> wrote:
>
> On Tue, Nov 15, 2022 at 06:36:38PM -0500, Jason Merrill wrote:
> > > Here is an updated patch that passed bootstrap/regtest, the only
> > > change is another testcase tweak.
> > >
> > > 2022-11-13  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_maybe_constant_var_p static or thread_local vars for
> > >     C++23.
> >
> > This was accepted as a DR, so it shouldn't be limited to C++23 mode.
> > Certainly it should be allowed in C++20 mode; I don't have a strong opinion
> > about C++14/17.  Jonathan, do you?
>
> How will a feature with feature test macro with multiple values work as DR?
> Or will everything but the macro be treated as a DR (so __cpp_constexpr >=
> 202211L only for C++23)?

Yes, I think so. We just won't be able to advertise this feature as
supported in C++20.

> Because __cpp_constexpr >= 202211L is >= 202207L too and that implies
> P2448R2 which wasn't a DR and >= 202110L which implies P2242R3 which wasn't a
> DR.  And C++20 added other 2 non-DR papers that bumped the value.
> C++17 another one.
>
> > >     (potential_constant_expression_1): Likewise.
> > > gcc/testsuite/
> > >     * g++.dg/cpp23/constexpr-nonlit17.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++23 or later.
>
>         Jakub
>


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] c++, v2: Implement C++23 P2647R1 - Permitting static constexpr variables in constexpr functions
  2022-11-16  0:27       ` Jonathan Wakely
@ 2022-11-16  6:19         ` Jakub Jelinek
  2022-11-16 13:20           ` Jason Merrill
  0 siblings, 1 reply; 25+ messages in thread
From: Jakub Jelinek @ 2022-11-16  6:19 UTC (permalink / raw)
  To: Jason Merrill, Jonathan Wakely; +Cc: gcc-patches, Marek Polacek

On Wed, Nov 16, 2022 at 12:27:02AM +0000, Jonathan Wakely wrote:
> On Tue, 15 Nov 2022 at 23:50, Jakub Jelinek <jakub@redhat.com> wrote:
> >
> > On Tue, Nov 15, 2022 at 06:36:38PM -0500, Jason Merrill wrote:
> > > > Here is an updated patch that passed bootstrap/regtest, the only
> > > > change is another testcase tweak.
> > > >
> > > > 2022-11-13  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_maybe_constant_var_p static or thread_local vars for
> > > >     C++23.
> > >
> > > This was accepted as a DR, so it shouldn't be limited to C++23 mode.
> > > Certainly it should be allowed in C++20 mode; I don't have a strong opinion
> > > about C++14/17.  Jonathan, do you?
> >
> > How will a feature with feature test macro with multiple values work as DR?
> > Or will everything but the macro be treated as a DR (so __cpp_constexpr >=
> > 202211L only for C++23)?
> 
> Yes, I think so. We just won't be able to advertise this feature as
> supported in C++20.

Ok.  But there is another issue, the
https://eel.is/c++draft/expr.const#5.2
spot that P2647R1 is changing didn't exist in C++20, it was only added with
P2242R3.  So, if one would treat P2647R1 as a DR for C++20, one has to come up with
a different standard modification.
Probably change the last bullet of:
[dcl.constexpr]/3
its function-body shall not enclose

    a goto statement,
    an identifier label,
    a definition of a variable of non-literal type or of static or thread storage duration.
to
    a definition of a variable of non-literal type or of a non-constexpr
      variable of static or thread storage duration.
or so.

	Jakub


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] c++, v2: Implement C++23 P2647R1 - Permitting static constexpr variables in constexpr functions
  2022-11-16  6:19         ` Jakub Jelinek
@ 2022-11-16 13:20           ` Jason Merrill
  2022-11-16 14:08             ` Jakub Jelinek
  0 siblings, 1 reply; 25+ messages in thread
From: Jason Merrill @ 2022-11-16 13:20 UTC (permalink / raw)
  To: Jakub Jelinek, Jonathan Wakely; +Cc: gcc-patches, Marek Polacek

On 11/16/22 01:19, Jakub Jelinek wrote:
> On Wed, Nov 16, 2022 at 12:27:02AM +0000, Jonathan Wakely wrote:
>> On Tue, 15 Nov 2022 at 23:50, Jakub Jelinek <jakub@redhat.com> wrote:
>>>
>>> On Tue, Nov 15, 2022 at 06:36:38PM -0500, Jason Merrill wrote:
>>>>> Here is an updated patch that passed bootstrap/regtest, the only
>>>>> change is another testcase tweak.
>>>>>
>>>>> 2022-11-13  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_maybe_constant_var_p static or thread_local vars for
>>>>>      C++23.
>>>>
>>>> This was accepted as a DR, so it shouldn't be limited to C++23 mode.
>>>> Certainly it should be allowed in C++20 mode; I don't have a strong opinion
>>>> about C++14/17.  Jonathan, do you?
>>>
>>> How will a feature with feature test macro with multiple values work as DR?
>>> Or will everything but the macro be treated as a DR (so __cpp_constexpr >=
>>> 202211L only for C++23)?
>>
>> Yes, I think so. We just won't be able to advertise this feature as
>> supported in C++20.
> 
> Ok.  But there is another issue, the
> https://eel.is/c++draft/expr.const#5.2
> spot that P2647R1 is changing didn't exist in C++20, it was only added with
> P2242R3.  So, if one would treat P2647R1 as a DR for C++20, one has to come up with
> a different standard modification.
> Probably change the last bullet of:
> [dcl.constexpr]/3
> its function-body shall not enclose
> 
>      a goto statement,
>      an identifier label,
>      a definition of a variable of non-literal type or of static or thread storage duration.
> to
>      a definition of a variable of non-literal type or of a non-constexpr
>        variable of static or thread storage duration.
> or so.

Indeed, though the hypothetical C++20 change could still use the "usable 
in constant expressions" phrase.

Jason


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] c++, v2: Implement C++23 P2647R1 - Permitting static constexpr variables in constexpr functions
  2022-11-16 13:20           ` Jason Merrill
@ 2022-11-16 14:08             ` Jakub Jelinek
  2022-11-16 14:33               ` Jason Merrill
  0 siblings, 1 reply; 25+ messages in thread
From: Jakub Jelinek @ 2022-11-16 14:08 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Jonathan Wakely, gcc-patches, Marek Polacek

On Wed, Nov 16, 2022 at 08:20:34AM -0500, Jason Merrill wrote:
> > Ok.  But there is another issue, the
> > https://eel.is/c++draft/expr.const#5.2
> > spot that P2647R1 is changing didn't exist in C++20, it was only added with
> > P2242R3.  So, if one would treat P2647R1 as a DR for C++20, one has to come up with
> > a different standard modification.
> > Probably change the last bullet of:
> > [dcl.constexpr]/3
> > its function-body shall not enclose
> > 
> >      a goto statement,
> >      an identifier label,
> >      a definition of a variable of non-literal type or of static or thread storage duration.
> > to
> >      a definition of a variable of non-literal type or of a non-constexpr
> >        variable of static or thread storage duration.
> > or so.
> 
> Indeed, though the hypothetical C++20 change could still use the "usable in
> constant expressions" phrase.

Yes.
Though, with -std=c++20 we are rejected already in start_decl's
  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;
    }
and at that point I fear decl_maybe_constant_var_p will not work
properly.  Shall this hunk be moved somewhere else (cp_finish_decl?)
where we can already call it, or do the above in start_decl for
cxx_dialect < cxx20 and add a cxx_dialect == cxx20 hunk in cp_finish_decl?

	Jakub


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] c++, v2: Implement C++23 P2647R1 - Permitting static constexpr variables in constexpr functions
  2022-11-16 14:08             ` Jakub Jelinek
@ 2022-11-16 14:33               ` Jason Merrill
  2022-11-16 14:46                 ` Jakub Jelinek
  0 siblings, 1 reply; 25+ messages in thread
From: Jason Merrill @ 2022-11-16 14:33 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Jonathan Wakely, gcc-patches, Marek Polacek

On 11/16/22 09:08, Jakub Jelinek wrote:
> On Wed, Nov 16, 2022 at 08:20:34AM -0500, Jason Merrill wrote:
>>> Ok.  But there is another issue, the
>>> https://eel.is/c++draft/expr.const#5.2
>>> spot that P2647R1 is changing didn't exist in C++20, it was only added with
>>> P2242R3.  So, if one would treat P2647R1 as a DR for C++20, one has to come up with
>>> a different standard modification.
>>> Probably change the last bullet of:
>>> [dcl.constexpr]/3
>>> its function-body shall not enclose
>>>
>>>       a goto statement,
>>>       an identifier label,
>>>       a definition of a variable of non-literal type or of static or thread storage duration.
>>> to
>>>       a definition of a variable of non-literal type or of a non-constexpr
>>>         variable of static or thread storage duration.
>>> or so.
>>
>> Indeed, though the hypothetical C++20 change could still use the "usable in
>> constant expressions" phrase.
> 
> Yes.
> Though, with -std=c++20 we are rejected already in start_decl's
>    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;
>      }
> and at that point I fear decl_maybe_constant_var_p will not work
> properly.  Shall this hunk be moved somewhere else (cp_finish_decl?)
> where we can already call it, or do the above in start_decl for
> cxx_dialect < cxx20 and add a cxx_dialect == cxx20 hunk in cp_finish_decl?

Hmm, I'd expect decl_maybe_constant_var_p to work fine at this point.

Jason


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] c++, v2: Implement C++23 P2647R1 - Permitting static constexpr variables in constexpr functions
  2022-11-16 14:33               ` Jason Merrill
@ 2022-11-16 14:46                 ` Jakub Jelinek
  2022-11-16 20:26                   ` Jason Merrill
  0 siblings, 1 reply; 25+ messages in thread
From: Jakub Jelinek @ 2022-11-16 14:46 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Jonathan Wakely, gcc-patches, Marek Polacek

On Wed, Nov 16, 2022 at 09:33:27AM -0500, Jason Merrill wrote:
> > and at that point I fear decl_maybe_constant_var_p will not work
> > properly.  Shall this hunk be moved somewhere else (cp_finish_decl?)
> > where we can already call it, or do the above in start_decl for
> > cxx_dialect < cxx20 and add a cxx_dialect == cxx20 hunk in cp_finish_decl?
> 
> Hmm, I'd expect decl_maybe_constant_var_p to work fine at this point.

For static constexpr vars sure, but what about
static const where start_decl doesn't know the initializer?
Sure, decl_maybe_constant_var_p will not crash in that case, but
it will return true even if the static const var doesn't have
a constant initializer.  Sure, we'd catch that later on when actually
trying to constexpr evaluate the function and hitting there the
spots added for C++23 in potential_constant_expression*/cxx_eval_*,
but it would mean that we don't reject it when nothing calls the functions.

I meant something like:
constexpr int bar (int x) { if (x) throw 1; return 0; }
constexpr int foo () { static const int a = bar (1); return 0; }
with -std=c++20 IMHO shouldn't be accepted, while in C++23 it should.

With
constexpr int a = foo ();
added we reject it in C++23 (correct), but the diagnostics is too weird:
test.C:3:23:   in ‘constexpr’ expansion of ‘foo()’
test.C:3:24: error: ‘__atomic_load_1((& _ZGVZ3foovE1a), 2)’ is not a constant expression
    3 | constexpr int a = foo ();
      |                        ^

	Jakub


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] c++, v2: Implement C++23 P2647R1 - Permitting static constexpr variables in constexpr functions
  2022-11-16 14:46                 ` Jakub Jelinek
@ 2022-11-16 20:26                   ` Jason Merrill
  2022-11-17  9:13                     ` [PATCH] c++, v3: " Jakub Jelinek
  0 siblings, 1 reply; 25+ messages in thread
From: Jason Merrill @ 2022-11-16 20:26 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Jonathan Wakely, gcc-patches, Marek Polacek

On 11/16/22 09:46, Jakub Jelinek wrote:
> On Wed, Nov 16, 2022 at 09:33:27AM -0500, Jason Merrill wrote:
>>> and at that point I fear decl_maybe_constant_var_p will not work
>>> properly.  Shall this hunk be moved somewhere else (cp_finish_decl?)
>>> where we can already call it, or do the above in start_decl for
>>> cxx_dialect < cxx20 and add a cxx_dialect == cxx20 hunk in cp_finish_decl?
>>
>> Hmm, I'd expect decl_maybe_constant_var_p to work fine at this point.
> 
> For static constexpr vars sure, but what about
> static const where start_decl doesn't know the initializer?
> Sure, decl_maybe_constant_var_p will not crash in that case, but
> it will return true even if the static const var doesn't have
> a constant initializer.  Sure, we'd catch that later on when actually
> trying to constexpr evaluate the function and hitting there the
> spots added for C++23 in potential_constant_expression*/cxx_eval_*,
> but it would mean that we don't reject it when nothing calls the functions.
> 
> I meant something like:
> constexpr int bar (int x) { if (x) throw 1; return 0; }
> constexpr int foo () { static const int a = bar (1); return 0; }
> with -std=c++20 IMHO shouldn't be accepted, while in C++23 it should.

I'd expect us to reject that in C++20 in potential_constant_expression, 
but it's a fair point; it is awkward that P2242 wasn't also accepted as 
a DR.

Moving the check from start_decl to cp_finish_decl makes sense to me.

Jason


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH] c++, v3: Implement C++23 P2647R1 - Permitting static constexpr variables in constexpr functions
  2022-11-16 20:26                   ` Jason Merrill
@ 2022-11-17  9:13                     ` Jakub Jelinek
  2022-11-17 14:42                       ` Jason Merrill
  0 siblings, 1 reply; 25+ messages in thread
From: Jakub Jelinek @ 2022-11-17  9:13 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Jonathan Wakely, gcc-patches, Marek Polacek

On Wed, Nov 16, 2022 at 03:26:32PM -0500, Jason Merrill wrote:
> On 11/16/22 09:46, Jakub Jelinek wrote:
> > On Wed, Nov 16, 2022 at 09:33:27AM -0500, Jason Merrill wrote:
> > > > and at that point I fear decl_maybe_constant_var_p will not work
> > > > properly.  Shall this hunk be moved somewhere else (cp_finish_decl?)
> > > > where we can already call it, or do the above in start_decl for
> > > > cxx_dialect < cxx20 and add a cxx_dialect == cxx20 hunk in cp_finish_decl?
> > > 
> > > Hmm, I'd expect decl_maybe_constant_var_p to work fine at this point.
> > 
> > For static constexpr vars sure, but what about
> > static const where start_decl doesn't know the initializer?
> > Sure, decl_maybe_constant_var_p will not crash in that case, but
> > it will return true even if the static const var doesn't have
> > a constant initializer.  Sure, we'd catch that later on when actually
> > trying to constexpr evaluate the function and hitting there the
> > spots added for C++23 in potential_constant_expression*/cxx_eval_*,
> > but it would mean that we don't reject it when nothing calls the functions.
> > 
> > I meant something like:
> > constexpr int bar (int x) { if (x) throw 1; return 0; }
> > constexpr int foo () { static const int a = bar (1); return 0; }
> > with -std=c++20 IMHO shouldn't be accepted, while in C++23 it should.
> 
> I'd expect us to reject that in C++20 in potential_constant_expression, but
> it's a fair point; it is awkward that P2242 wasn't also accepted as a DR.
> 
> Moving the check from start_decl to cp_finish_decl makes sense to me.

So like this?  I had to outline the check from start_decl to a function
because it is needed in cp_finish_decl in two different places (the
processing_template_decl path and at the end and it can't be done before the
processing_template_decl spot, because the initializer isn't finalized at
that point for !procesing_template_decl).  Also, decl_maybe_constant_var_p
doesn't do what is needed when !processing_template_decl, but I think
we want decl_maybe_constant_var_p in templates so that we don't instantiate
anything.

Lightly tested so far, ok for trunk if it passes full bootstrap/regtest?

2022-11-17  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_constant_var_p static or thread_local vars for
	C++20 and later.
	(potential_constant_expression_1): For C++20 or later, allow
	static or thread_local decl_maybe_constant_var_p vars, for
	!processing_template_decl only decl_constant_var_p vars.
	* decl.cc (diagnose_static_in_constexpr): New function.
	(start_decl): Use it for C++17 or earlier.
	(cp_finish_decl): Call it for C++20.
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 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 09:56:50.479522863 +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 < cxx20 || !decl_constant_var_p (r)))
 	  {
 	    if (!ctx->quiet)
 	      {
@@ -9588,7 +9589,12 @@ 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 (CP_DECL_THREAD_LOCAL_P (tmp)
+	      && !DECL_REALLY_EXTERN (tmp)
+	      && (cxx_dialect < cxx20
+		  || (processing_template_decl
+		      ? !decl_maybe_constant_var_p (tmp)
+		      : !decl_constant_var_p (tmp))))
 	    {
 	      if (flags & tf_error)
 		constexpr_error (DECL_SOURCE_LOCATION (tmp), fundef_p,
@@ -9596,7 +9602,11 @@ potential_constant_expression_1 (tree t,
 				 "%<constexpr%> context", tmp);
 	      return false;
 	    }
-	  else if (TREE_STATIC (tmp))
+	  else if (TREE_STATIC (tmp)
+		   && (cxx_dialect < cxx20
+		       || (processing_template_decl
+			   ? !decl_maybe_constant_var_p (tmp)
+			   : !decl_constant_var_p (tmp))))
 	    {
 	      if (flags & tf_error)
 		constexpr_error (DECL_SOURCE_LOCATION (tmp), fundef_p,
--- gcc/cp/decl.cc.jj	2022-11-16 14:44:43.692339668 +0100
+++ gcc/cp/decl.cc	2022-11-17 09:54:30.556482833 +0100
@@ -5600,6 +5600,41 @@ 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 (current_function_decl && VAR_P (decl)
+      && DECL_DECLARED_CONSTEXPR_P (current_function_decl)
+      && cxx_dialect < cxx23
+      && (cxx_dialect < cxx20
+	  || (processing_template_decl
+	      ? !decl_maybe_constant_var_p (decl)
+	      : !decl_constant_var_p (decl))))
+    {
+      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;
+    }
+}
+
 /* Process a DECLARATOR for a function-scope or namespace-scope
    variable or function declaration.
    (Function definitions go through start_function; class member
@@ -5860,28 +5895,8 @@ 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 (cxx_dialect < cxx20)
+    diagnose_static_in_constexpr (decl);
 
   if (!processing_template_decl && VAR_P (decl))
     start_decl_1 (decl, initialized);
@@ -8424,6 +8439,10 @@ cp_finish_decl (tree decl, tree init, bo
 	  set_user_assembler_name (decl, asmspec);
 	  DECL_HARD_REGISTER (decl) = 1;
 	}
+
+      if (cxx_dialect == cxx20)
+	diagnose_static_in_constexpr (decl);
+
       return;
     }
 
@@ -8749,6 +8768,9 @@ cp_finish_decl (tree decl, tree init, bo
       && !DECL_HARD_REGISTER (decl))
     targetm.lower_local_decl_alignment (decl);
 
+  if (cxx_dialect == cxx20)
+    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 09:00:42.108248984 +0100
@@ -0,0 +1,12 @@
+// P2647R1 - Permitting static constexpr variables in constexpr functions
+// { dg-do compile { target c++20 } }
+
+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 10:04:32.894045579 +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++17_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++17_down } }
+  return 0;
+}
+
+constexpr int
+f6 ()					// { dg-message "declared here" "" { target c++17_down } }
+{
+  static const int a = f1 (0);		// { dg-error "'a' defined 'static' in 'constexpr' function only available with" "" { target c++17_down } }
+  return 0;
+}
+
+constexpr int a6 = f6 ();		// { dg-error "called in a constant expression" "" { target c++17_down } }
--- 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 09:00:42.109248970 +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++17_down } }
     };
 
   return &atest;


	Jakub


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] c++, v3: Implement C++23 P2647R1 - Permitting static constexpr variables in constexpr functions
  2022-11-17  9:13                     ` [PATCH] c++, v3: " Jakub Jelinek
@ 2022-11-17 14:42                       ` Jason Merrill
  2022-11-17 18:42                         ` Jakub Jelinek
  0 siblings, 1 reply; 25+ messages in thread
From: Jason Merrill @ 2022-11-17 14:42 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Jonathan Wakely, gcc-patches, Marek Polacek

On 11/17/22 04:13, Jakub Jelinek wrote:
> On Wed, Nov 16, 2022 at 03:26:32PM -0500, Jason Merrill wrote:
>> On 11/16/22 09:46, Jakub Jelinek wrote:
>>> On Wed, Nov 16, 2022 at 09:33:27AM -0500, Jason Merrill wrote:
>>>>> and at that point I fear decl_maybe_constant_var_p will not work
>>>>> properly.  Shall this hunk be moved somewhere else (cp_finish_decl?)
>>>>> where we can already call it, or do the above in start_decl for
>>>>> cxx_dialect < cxx20 and add a cxx_dialect == cxx20 hunk in cp_finish_decl?
>>>>
>>>> Hmm, I'd expect decl_maybe_constant_var_p to work fine at this point.
>>>
>>> For static constexpr vars sure, but what about
>>> static const where start_decl doesn't know the initializer?
>>> Sure, decl_maybe_constant_var_p will not crash in that case, but
>>> it will return true even if the static const var doesn't have
>>> a constant initializer.  Sure, we'd catch that later on when actually
>>> trying to constexpr evaluate the function and hitting there the
>>> spots added for C++23 in potential_constant_expression*/cxx_eval_*,
>>> but it would mean that we don't reject it when nothing calls the functions.
>>>
>>> I meant something like:
>>> constexpr int bar (int x) { if (x) throw 1; return 0; }
>>> constexpr int foo () { static const int a = bar (1); return 0; }
>>> with -std=c++20 IMHO shouldn't be accepted, while in C++23 it should.
>>
>> I'd expect us to reject that in C++20 in potential_constant_expression, but
>> it's a fair point; it is awkward that P2242 wasn't also accepted as a DR.

I pointed out that inconsistency on the reflectors, and it seems that 
EWG didn't actually intend P2647 to be a DR, either; it was a CWG error 
to propose it as such.  But let's go ahead and build on the work you've 
done.

>> Moving the check from start_decl to cp_finish_decl makes sense to me.
> 
> So like this?  I had to outline the check from start_decl to a function
> because it is needed in cp_finish_decl in two different places (the
> processing_template_decl path and at the end and it can't be done before the
> processing_template_decl spot, because the initializer isn't finalized at
> that point for !procesing_template_decl).  Also, decl_maybe_constant_var_p
> doesn't do what is needed when !processing_template_decl, but I think
> we want decl_maybe_constant_var_p in templates so that we don't instantiate
> anything.
> 
> Lightly tested so far, ok for trunk if it passes full bootstrap/regtest?
> 
> 2022-11-17  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_constant_var_p static or thread_local vars for
> 	C++20 and later.
> 	(potential_constant_expression_1): For C++20 or later, allow
> 	static or thread_local decl_maybe_constant_var_p vars, for
> 	!processing_template_decl only decl_constant_var_p vars.
> 	* decl.cc (diagnose_static_in_constexpr): New function.
> 	(start_decl): Use it for C++17 or earlier.
> 	(cp_finish_decl): Call it for C++20.
> 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 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 09:56:50.479522863 +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 < cxx20 || !decl_constant_var_p (r)))

I don't think we need to check cxx_dialect here since 
diagnose_static_in_constexpr will have already complained.

>   	  {
>   	    if (!ctx->quiet)
>   	      {
> @@ -9588,7 +9589,12 @@ 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 (CP_DECL_THREAD_LOCAL_P (tmp)
> +	      && !DECL_REALLY_EXTERN (tmp)
> +	      && (cxx_dialect < cxx20
> +		  || (processing_template_decl
> +		      ? !decl_maybe_constant_var_p (tmp)
> +		      : !decl_constant_var_p (tmp))))

Or here.

>   	    {
>   	      if (flags & tf_error)
>   		constexpr_error (DECL_SOURCE_LOCATION (tmp), fundef_p,
> @@ -9596,7 +9602,11 @@ potential_constant_expression_1 (tree t,
>   				 "%<constexpr%> context", tmp);
>   	      return false;
>   	    }
> -	  else if (TREE_STATIC (tmp))
> +	  else if (TREE_STATIC (tmp)
> +		   && (cxx_dialect < cxx20
> +		       || (processing_template_decl
> +			   ? !decl_maybe_constant_var_p (tmp)
> +			   : !decl_constant_var_p (tmp))))
>   	    {
>   	      if (flags & tf_error)
>   		constexpr_error (DECL_SOURCE_LOCATION (tmp), fundef_p,
> --- gcc/cp/decl.cc.jj	2022-11-16 14:44:43.692339668 +0100
> +++ gcc/cp/decl.cc	2022-11-17 09:54:30.556482833 +0100
> @@ -5600,6 +5600,41 @@ 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 (current_function_decl && VAR_P (decl)
> +      && DECL_DECLARED_CONSTEXPR_P (current_function_decl)
> +      && cxx_dialect < cxx23
> +      && (cxx_dialect < cxx20
> +	  || (processing_template_decl
> +	      ? !decl_maybe_constant_var_p (decl)
> +	      : !decl_constant_var_p (decl))))

For (maybe) constant variables let's make this error a pedwarn in C++20 
and below.

> +    {
> +      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;
> +    }
> +}
> +
>   /* Process a DECLARATOR for a function-scope or namespace-scope
>      variable or function declaration.
>      (Function definitions go through start_function; class member
> @@ -5860,28 +5895,8 @@ 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 (cxx_dialect < cxx20)
> +    diagnose_static_in_constexpr (decl);

Can we drop this call (and make the ones in cp_finish_decl unconditional)?

>   
>     if (!processing_template_decl && VAR_P (decl))
>       start_decl_1 (decl, initialized);
> @@ -8424,6 +8439,10 @@ cp_finish_decl (tree decl, tree init, bo
>   	  set_user_assembler_name (decl, asmspec);
>   	  DECL_HARD_REGISTER (decl) = 1;
>   	}
> +
> +      if (cxx_dialect == cxx20)
> +	diagnose_static_in_constexpr (decl);
> +
>         return;
>       }
>   
> @@ -8749,6 +8768,9 @@ cp_finish_decl (tree decl, tree init, bo
>         && !DECL_HARD_REGISTER (decl))
>       targetm.lower_local_decl_alignment (decl);
>   
> +  if (cxx_dialect == cxx20)
> +    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 09:00:42.108248984 +0100
> @@ -0,0 +1,12 @@
> +// P2647R1 - Permitting static constexpr variables in constexpr functions
> +// { dg-do compile { target c++20 } }
> +
> +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 10:04:32.894045579 +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++17_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++17_down } }
> +  return 0;
> +}
> +
> +constexpr int
> +f6 ()					// { dg-message "declared here" "" { target c++17_down } }
> +{
> +  static const int a = f1 (0);		// { dg-error "'a' defined 'static' in 'constexpr' function only available with" "" { target c++17_down } }
> +  return 0;
> +}
> +
> +constexpr int a6 = f6 ();		// { dg-error "called in a constant expression" "" { target c++17_down } }
> --- 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 09:00:42.109248970 +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++17_down } }
>       };
>   
>     return &atest;
> 
> 
> 	Jakub
> 


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] c++, v3: Implement C++23 P2647R1 - Permitting static constexpr variables in constexpr functions
  2022-11-17 14:42                       ` Jason Merrill
@ 2022-11-17 18:42                         ` Jakub Jelinek
  2022-11-17 20:42                           ` [PATCH] c++, v4: " Jakub Jelinek
  0 siblings, 1 reply; 25+ messages in thread
From: Jakub Jelinek @ 2022-11-17 18:42 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Jonathan Wakely, gcc-patches, Marek Polacek

On Thu, Nov 17, 2022 at 09:42:18AM -0500, Jason Merrill wrote:
> > --- gcc/cp/constexpr.cc.jj	2022-11-17 08:48:30.530357181 +0100
> > +++ gcc/cp/constexpr.cc	2022-11-17 09:56:50.479522863 +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 < cxx20 || !decl_constant_var_p (r)))
> 
> I don't think we need to check cxx_dialect here since
> diagnose_static_in_constexpr will have already complained.

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.

> 
> >   	  {
> >   	    if (!ctx->quiet)
> >   	      {
> > @@ -9588,7 +9589,12 @@ 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 (CP_DECL_THREAD_LOCAL_P (tmp)
> > +	      && !DECL_REALLY_EXTERN (tmp)
> > +	      && (cxx_dialect < cxx20
> > +		  || (processing_template_decl
> > +		      ? !decl_maybe_constant_var_p (tmp)
> > +		      : !decl_constant_var_p (tmp))))
> 
> Or here.
> 
> >   	    {
> >   	      if (flags & tf_error)
> >   		constexpr_error (DECL_SOURCE_LOCATION (tmp), fundef_p,
> > @@ -9596,7 +9602,11 @@ potential_constant_expression_1 (tree t,
> >   				 "%<constexpr%> context", tmp);
> >   	      return false;
> >   	    }
> > -	  else if (TREE_STATIC (tmp))
> > +	  else if (TREE_STATIC (tmp)
> > +		   && (cxx_dialect < cxx20
> > +		       || (processing_template_decl
> > +			   ? !decl_maybe_constant_var_p (tmp)
> > +			   : !decl_constant_var_p (tmp))))
> >   	    {
> >   	      if (flags & tf_error)
> >   		constexpr_error (DECL_SOURCE_LOCATION (tmp), fundef_p,

And these too.

> > +static void
> > +diagnose_static_in_constexpr (tree decl)
> > +{
> > +  if (current_function_decl && VAR_P (decl)
> > +      && DECL_DECLARED_CONSTEXPR_P (current_function_decl)
> > +      && cxx_dialect < cxx23
> > +      && (cxx_dialect < cxx20
> > +	  || (processing_template_decl
> > +	      ? !decl_maybe_constant_var_p (decl)
> > +	      : !decl_constant_var_p (decl))))
> 
> For (maybe) constant variables let's make this error a pedwarn in C++20 and
> below.

Ok.
> 
> > +    {
> > +      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;
> > +    }
> > +}
> > +
> >   /* Process a DECLARATOR for a function-scope or namespace-scope
> >      variable or function declaration.
> >      (Function definitions go through start_function; class member
> > @@ -5860,28 +5895,8 @@ 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 (cxx_dialect < cxx20)
> > +    diagnose_static_in_constexpr (decl);
> 
> Can we drop this call (and make the ones in cp_finish_decl unconditional)?

Yes, will do it.

	Jakub


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH] c++, v4: Implement C++23 P2647R1 - Permitting static constexpr variables in constexpr functions
  2022-11-17 18:42                         ` Jakub Jelinek
@ 2022-11-17 20:42                           ` Jakub Jelinek
  2022-11-18  0:15                             ` Marek Polacek
  2022-11-18  0:28                             ` Jason Merrill
  0 siblings, 2 replies; 25+ messages in thread
From: Jakub Jelinek @ 2022-11-17 20:42 UTC (permalink / raw)
  To: Jason Merrill, Jonathan Wakely, gcc-patches, Marek Polacek

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  <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_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


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] c++, v4: Implement C++23 P2647R1 - Permitting static constexpr variables in constexpr functions
  2022-11-17 20:42                           ` [PATCH] c++, v4: " Jakub Jelinek
@ 2022-11-18  0:15                             ` Marek Polacek
  2022-11-18  7:48                               ` Jakub Jelinek
  2022-11-18  0:28                             ` Jason Merrill
  1 sibling, 1 reply; 25+ messages in thread
From: Marek Polacek @ 2022-11-18  0:15 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Jason Merrill, Jonathan Wakely, gcc-patches

On Thu, Nov 17, 2022 at 09:42:17PM +0100, 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.
> 
> 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  <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_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;

FWIW, I couldn't find a way to trigger this code.

> +	      }
> +	    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

In C++17 we don't support consteval so I guess drop the "or consteval "?

BTW, I notice that the patch breaks
g++.dg/cpp1y/lambda-generic-func1.C
g++.dg/cpp1z/constexpr-lambda16.C
Maybe they just need dg- tweaks.

Marek


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] c++, v4: Implement C++23 P2647R1 - Permitting static constexpr variables in constexpr functions
  2022-11-17 20:42                           ` [PATCH] c++, v4: " Jakub Jelinek
  2022-11-18  0:15                             ` Marek Polacek
@ 2022-11-18  0:28                             ` Jason Merrill
  2022-11-18  9:10                               ` [PATCH] c++, v5: " Jakub Jelinek
  1 sibling, 1 reply; 25+ messages in thread
From: Jason Merrill @ 2022-11-18  0:28 UTC (permalink / raw)
  To: Jakub Jelinek, Jonathan Wakely, gcc-patches, Marek Polacek

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.

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);

> 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  <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_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
> 


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] c++, v4: Implement C++23 P2647R1 - Permitting static constexpr variables in constexpr functions
  2022-11-18  0:15                             ` Marek Polacek
@ 2022-11-18  7:48                               ` Jakub Jelinek
  2022-11-18 15:03                                 ` Marek Polacek
  0 siblings, 1 reply; 25+ messages in thread
From: Jakub Jelinek @ 2022-11-18  7:48 UTC (permalink / raw)
  To: Jason Merrill, Marek Polacek; +Cc: Jonathan Wakely, gcc-patches

On Thu, Nov 17, 2022 at 07:15:05PM -0500, Marek Polacek wrote:
> > --- 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
> 
> In C++17 we don't support consteval so I guess drop the "or consteval "?

I just forgot to update the function comment.

Anyway, I think:

> BTW, I notice that the patch breaks
> g++.dg/cpp1y/lambda-generic-func1.C
> g++.dg/cpp1z/constexpr-lambda16.C
> Maybe they just need dg- tweaks.

this is actually a real bug and I'm not sure how to resolve that.

We have there:

int main()
{
  [](auto i) { if (i) { int j; static int k; return i + j; } return i; }(0);
}

and for C++17/20 I presume something (haven't figured out yet what) marks
the lambda operator() when still a template as constexpr and then
cp_finish_decl -> diagnose_static_in_constexpr pedwarns on it.
For the above perhaps we could figure out there is a static int k; in the
operator() and don't turn it into constexpr, but what if there is
something that would e.g. satisfy decl_maybe_constant_var_p but not
decl_constant_var_p when actually instantiated?
Without my patch, the diagnostics is in start_decl which isn't called again
during instantiation, so I presume we mark it as constexpr and then we'd
diagnose it during constant evaluation.

	Jakub


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH] c++, v5: Implement C++23 P2647R1 - Permitting static constexpr variables in constexpr functions
  2022-11-18  0:28                             ` Jason Merrill
@ 2022-11-18  9:10                               ` Jakub Jelinek
  0 siblings, 0 replies; 25+ messages in thread
From: Jakub Jelinek @ 2022-11-18  9:10 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Jonathan Wakely, gcc-patches, Marek Polacek

[-- Attachment #1: Type: text/plain, Size: 2160 bytes --]

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

[-- Attachment #2: R656 --]
[-- Type: text/plain, Size: 12930 bytes --]

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.

--- 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(){}

[-- Attachment #3: R656h --]
[-- Type: text/plain, Size: 5799 bytes --]

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(){}

[-- Attachment #4: R656i --]
[-- Type: text/plain, Size: 5920 bytes --]

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(){}

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] c++, v4: Implement C++23 P2647R1 - Permitting static constexpr variables in constexpr functions
  2022-11-18  7:48                               ` Jakub Jelinek
@ 2022-11-18 15:03                                 ` Marek Polacek
  2022-11-18 15:14                                   ` Jakub Jelinek
  2022-11-18 16:24                                   ` Jason Merrill
  0 siblings, 2 replies; 25+ messages in thread
From: Marek Polacek @ 2022-11-18 15:03 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Jason Merrill, Jonathan Wakely, gcc-patches

On Fri, Nov 18, 2022 at 08:48:32AM +0100, Jakub Jelinek wrote:
> On Thu, Nov 17, 2022 at 07:15:05PM -0500, Marek Polacek wrote:
> > > --- 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
> > 
> > In C++17 we don't support consteval so I guess drop the "or consteval "?
> 
> I just forgot to update the function comment.
> 
> Anyway, I think:
> 
> > BTW, I notice that the patch breaks
> > g++.dg/cpp1y/lambda-generic-func1.C
> > g++.dg/cpp1z/constexpr-lambda16.C
> > Maybe they just need dg- tweaks.
> 
> this is actually a real bug and I'm not sure how to resolve that.
> 
> We have there:
> 
> int main()
> {
>   [](auto i) { if (i) { int j; static int k; return i + j; } return i; }(0);
> }
> 
> and for C++17/20 I presume something (haven't figured out yet what) marks

Right, that's the C++17 implicit constexpr for lambdas, finish_function:

  /* Lambda closure members are implicitly constexpr if possible.  */
  if (cxx_dialect >= cxx17
      && LAMBDA_TYPE_P (CP_DECL_CONTEXT (fndecl)))
    DECL_DECLARED_CONSTEXPR_P (fndecl)
      = ((processing_template_decl
          || is_valid_constexpr_fn (fndecl, /*complain*/false))
         && potential_constant_expression (DECL_SAVED_TREE (fndecl)));

> the lambda operator() when still a template as constexpr and then
> cp_finish_decl -> diagnose_static_in_constexpr pedwarns on it.
> For the above perhaps we could figure out there is a static int k; in the
> operator() and don't turn it into constexpr, but what if there is
> something that would e.g. satisfy decl_maybe_constant_var_p but not
> decl_constant_var_p when actually instantiated?
> Without my patch, the diagnostics is in start_decl which isn't called again
> during instantiation, so I presume we mark it as constexpr and then we'd
> diagnose it during constant evaluation.

Um, can we give up on trying to handle C++17/C++20 then?

Marek


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] c++, v4: Implement C++23 P2647R1 - Permitting static constexpr variables in constexpr functions
  2022-11-18 15:03                                 ` Marek Polacek
@ 2022-11-18 15:14                                   ` Jakub Jelinek
  2022-11-18 16:24                                   ` Jason Merrill
  1 sibling, 0 replies; 25+ messages in thread
From: Jakub Jelinek @ 2022-11-18 15:14 UTC (permalink / raw)
  To: Marek Polacek; +Cc: Jason Merrill, Jonathan Wakely, gcc-patches

On Fri, Nov 18, 2022 at 10:03:18AM -0500, Marek Polacek wrote:
> > the lambda operator() when still a template as constexpr and then
> > cp_finish_decl -> diagnose_static_in_constexpr pedwarns on it.
> > For the above perhaps we could figure out there is a static int k; in the
> > operator() and don't turn it into constexpr, but what if there is
> > something that would e.g. satisfy decl_maybe_constant_var_p but not
> > decl_constant_var_p when actually instantiated?
> > Without my patch, the diagnostics is in start_decl which isn't called again
> > during instantiation, so I presume we mark it as constexpr and then we'd
> > diagnose it during constant evaluation.
> 
> Um, can we give up on trying to handle C++17/C++20 then?

That was why I've posted the other two variant patches (with the 3rd one
being a strict C++23 only change).  Even if it is just a temporary state,
make C++23 work first and then iterate if it is possible to make C++17/20
working with the pedwarns right.

	Jakub


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] c++, v4: Implement C++23 P2647R1 - Permitting static constexpr variables in constexpr functions
  2022-11-18 15:03                                 ` Marek Polacek
  2022-11-18 15:14                                   ` Jakub Jelinek
@ 2022-11-18 16:24                                   ` Jason Merrill
  2022-11-18 16:34                                     ` Jakub Jelinek
  1 sibling, 1 reply; 25+ messages in thread
From: Jason Merrill @ 2022-11-18 16:24 UTC (permalink / raw)
  To: Marek Polacek, Jakub Jelinek; +Cc: Jonathan Wakely, gcc-patches

On 11/18/22 10:03, Marek Polacek wrote:
> On Fri, Nov 18, 2022 at 08:48:32AM +0100, Jakub Jelinek wrote:
>> On Thu, Nov 17, 2022 at 07:15:05PM -0500, Marek Polacek wrote:
>>>> --- 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
>>>
>>> In C++17 we don't support consteval so I guess drop the "or consteval "?
>>
>> I just forgot to update the function comment.
>>
>> Anyway, I think:
>>
>>> BTW, I notice that the patch breaks
>>> g++.dg/cpp1y/lambda-generic-func1.C
>>> g++.dg/cpp1z/constexpr-lambda16.C
>>> Maybe they just need dg- tweaks.
>>
>> this is actually a real bug and I'm not sure how to resolve that.
>>
>> We have there:
>>
>> int main()
>> {
>>    [](auto i) { if (i) { int j; static int k; return i + j; } return i; }(0);
>> }
>>
>> and for C++17/20 I presume something (haven't figured out yet what) marks
> 
> Right, that's the C++17 implicit constexpr for lambdas, finish_function:
> 
>    /* Lambda closure members are implicitly constexpr if possible.  */
>    if (cxx_dialect >= cxx17
>        && LAMBDA_TYPE_P (CP_DECL_CONTEXT (fndecl)))
>      DECL_DECLARED_CONSTEXPR_P (fndecl)
>        = ((processing_template_decl
>            || is_valid_constexpr_fn (fndecl, /*complain*/false))
>           && potential_constant_expression (DECL_SAVED_TREE (fndecl)));

Yeah, I guess potential_constant_expression needs to be stricter in a 
lambda. Or perhaps any function that isn't already 
DECL_DECLARED_CONSTEXPR_P?

>> the lambda operator() when still a template as constexpr and then
>> cp_finish_decl -> diagnose_static_in_constexpr pedwarns on it.
>> For the above perhaps we could figure out there is a static int k; in the
>> operator() and don't turn it into constexpr, but what if there is
>> something that would e.g. satisfy decl_maybe_constant_var_p but not
>> decl_constant_var_p when actually instantiated?

I'd expect the above change to potential_c_e to handle that case.

Jason


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] c++, v4: Implement C++23 P2647R1 - Permitting static constexpr variables in constexpr functions
  2022-11-18 16:24                                   ` Jason Merrill
@ 2022-11-18 16:34                                     ` Jakub Jelinek
  2022-11-18 16:52                                       ` Jason Merrill
  0 siblings, 1 reply; 25+ messages in thread
From: Jakub Jelinek @ 2022-11-18 16:34 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Marek Polacek, Jonathan Wakely, gcc-patches

On Fri, Nov 18, 2022 at 11:24:45AM -0500, Jason Merrill wrote:
> > Right, that's the C++17 implicit constexpr for lambdas, finish_function:
> > 
> >    /* Lambda closure members are implicitly constexpr if possible.  */
> >    if (cxx_dialect >= cxx17
> >        && LAMBDA_TYPE_P (CP_DECL_CONTEXT (fndecl)))
> >      DECL_DECLARED_CONSTEXPR_P (fndecl)
> >        = ((processing_template_decl
> >            || is_valid_constexpr_fn (fndecl, /*complain*/false))
> >           && potential_constant_expression (DECL_SAVED_TREE (fndecl)));
> 
> Yeah, I guess potential_constant_expression needs to be stricter in a
> lambda. Or perhaps any function that isn't already
> DECL_DECLARED_CONSTEXPR_P?

potential_constant_expression can't be relied on that it catches up
everything if it, even a simple if statement with a condition not yet
known to be 0 or non-0 results in just a requirement that at least
one of the substatements is potential constant, etc.
Similarly switch statements etc.
If there is a way to distinguish between functions with user
specified constexpr/consteval and DECL_DECLARED_CONSTEXPR_P set
through the above if condition, sure, cp_finish_decl ->
check_static_in_constexpr could be perhaps silent about those, but then
we want to diagnose it during constexpr evaluation at least.  But in that
case having it a pedwarn rather than "this is a constant expression"
vs. "this is not a constant expression, if !ctx->quiet emit an error"
is something I don't see how to handle.  Because something needs
to be returned, it is a constant expression or it is not.

	Jakub


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] c++, v4: Implement C++23 P2647R1 - Permitting static constexpr variables in constexpr functions
  2022-11-18 16:34                                     ` Jakub Jelinek
@ 2022-11-18 16:52                                       ` Jason Merrill
  0 siblings, 0 replies; 25+ messages in thread
From: Jason Merrill @ 2022-11-18 16:52 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Marek Polacek, Jonathan Wakely, gcc-patches

On 11/18/22 11:34, Jakub Jelinek wrote:
> On Fri, Nov 18, 2022 at 11:24:45AM -0500, Jason Merrill wrote:
>>> Right, that's the C++17 implicit constexpr for lambdas, finish_function:
>>>
>>>     /* Lambda closure members are implicitly constexpr if possible.  */
>>>     if (cxx_dialect >= cxx17
>>>         && LAMBDA_TYPE_P (CP_DECL_CONTEXT (fndecl)))
>>>       DECL_DECLARED_CONSTEXPR_P (fndecl)
>>>         = ((processing_template_decl
>>>             || is_valid_constexpr_fn (fndecl, /*complain*/false))
>>>            && potential_constant_expression (DECL_SAVED_TREE (fndecl)));
>>
>> Yeah, I guess potential_constant_expression needs to be stricter in a
>> lambda. Or perhaps any function that isn't already
>> DECL_DECLARED_CONSTEXPR_P?
> 
> potential_constant_expression can't be relied on that it catches up
> everything if it, even a simple if statement with a condition not yet
> known to be 0 or non-0 results in just a requirement that at least
> one of the substatements is potential constant, etc.
> Similarly switch statements etc.
> If there is a way to distinguish between functions with user
> specified constexpr/consteval and DECL_DECLARED_CONSTEXPR_P set
> through the above if condition, sure, cp_finish_decl ->
> check_static_in_constexpr could be perhaps silent about those, but then
> we want to diagnose it during constexpr evaluation at least.  But in that
> case having it a pedwarn rather than "this is a constant expression"
> vs. "this is not a constant expression, if !ctx->quiet emit an error"
> is something I don't see how to handle.  Because something needs
> to be returned, it is a constant expression or it is not.

True.  Let's go with your option 2, then, thanks.

Jason


^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2022-11-18 16:52 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-11-11 17:07 [PATCH] c++: Implement C++23 P2647R1 - Permitting static constexpr variables in constexpr functions Jakub Jelinek
2022-11-13 11:45 ` [PATCH] c++, v2: " Jakub Jelinek
2022-11-15 23:36   ` Jason Merrill
2022-11-15 23:50     ` Jakub Jelinek
2022-11-16  0:27       ` Jonathan Wakely
2022-11-16  6:19         ` Jakub Jelinek
2022-11-16 13:20           ` Jason Merrill
2022-11-16 14:08             ` Jakub Jelinek
2022-11-16 14:33               ` Jason Merrill
2022-11-16 14:46                 ` Jakub Jelinek
2022-11-16 20:26                   ` Jason Merrill
2022-11-17  9:13                     ` [PATCH] c++, v3: " Jakub Jelinek
2022-11-17 14:42                       ` Jason Merrill
2022-11-17 18:42                         ` Jakub Jelinek
2022-11-17 20:42                           ` [PATCH] c++, v4: " Jakub Jelinek
2022-11-18  0:15                             ` Marek Polacek
2022-11-18  7:48                               ` Jakub Jelinek
2022-11-18 15:03                                 ` Marek Polacek
2022-11-18 15:14                                   ` Jakub Jelinek
2022-11-18 16:24                                   ` Jason Merrill
2022-11-18 16:34                                     ` Jakub Jelinek
2022-11-18 16:52                                       ` Jason Merrill
2022-11-18  0:28                             ` Jason Merrill
2022-11-18  9:10                               ` [PATCH] c++, v5: " Jakub Jelinek
2022-11-16  0:26     ` [PATCH] c++, v2: " Jonathan Wakely

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).