diff mbox series

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

Message ID Y3DYxNPWpM23FCtj@tucnak
State New
Headers show
Series c++, v2: Implement C++23 P2647R1 - Permitting static constexpr variables in constexpr functions | expand

Commit Message

Jakub Jelinek Nov. 13, 2022, 11:45 a.m. UTC
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. 



	Jakub

Comments

Jason Merrill Nov. 15, 2022, 11:36 p.m. UTC | #1
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
>
Jakub Jelinek Nov. 15, 2022, 11:50 p.m. UTC | #2
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
Jonathan Wakely Nov. 16, 2022, 12:26 a.m. UTC | #3
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
> >
>
Jonathan Wakely Nov. 16, 2022, 12:27 a.m. UTC | #4
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
>
Jakub Jelinek Nov. 16, 2022, 6:19 a.m. UTC | #5
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
Jason Merrill Nov. 16, 2022, 1:20 p.m. UTC | #6
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
Jakub Jelinek Nov. 16, 2022, 2:08 p.m. UTC | #7
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
Jason Merrill Nov. 16, 2022, 2:33 p.m. UTC | #8
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
Jakub Jelinek Nov. 16, 2022, 2:46 p.m. UTC | #9
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
Jason Merrill Nov. 16, 2022, 8:26 p.m. UTC | #10
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
diff mbox series

Patch

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