diff mbox series

C++ PATCH for c++/87372, __func__ constexpr evaluation

Message ID 20180921035637.GW5587@redhat.com
State New
Headers show
Series C++ PATCH for c++/87372, __func__ constexpr evaluation | expand

Commit Message

Marek Polacek Sept. 21, 2018, 3:56 a.m. UTC
The patch for P0595R1 - is_constant_evaluated had this hunk:

@@ -5279,7 +5315,9 @@ maybe_constant_init_1 (tree t, tree decl, bool allow_non_constant)
   else if (CONSTANT_CLASS_P (t) && allow_non_constant)
     /* No evaluation needed.  */;
   else
-    t = cxx_eval_outermost_constant_expr (t, allow_non_constant, false, decl);
+    t = cxx_eval_outermost_constant_expr (t, allow_non_constant,
+                     !allow_non_constant,
+                     pretend_const_required, decl);
   if (TREE_CODE (t) == TARGET_EXPR)
     {
       tree init = TARGET_EXPR_INITIAL (t);

the false -> !allow_non_constant change means that when calling
cxx_constant_init strict will be true because cxx_constant_init does not allow
non constants.  That means that for VAR_DECLs such as __func__ we'll call
decl_really_constant_value instead of decl_constant_value.  But only the latter
can evaluate __func__ to "foo()".

Jakub, was there a specific reason for this change?  Changing it back still
regtests cleanly and the attached test compiles again.

Bootstrapped/regtested on x86_64-linux, ok for trunk?

2018-09-20  Marek Polacek  <polacek@redhat.com>

	PR c++/87372 - __func__ constexpr evaluation.
	* constexpr.c (maybe_constant_init_1): Pass false for strict down to
	cxx_eval_outermost_constant_expr.

	* g++.dg/cpp1y/func_constexpr2.C: New test.

Comments

Jakub Jelinek Sept. 21, 2018, 7:37 a.m. UTC | #1
On Thu, Sep 20, 2018 at 11:56:37PM -0400, Marek Polacek wrote:
> The patch for P0595R1 - is_constant_evaluated had this hunk:
> 
> @@ -5279,7 +5315,9 @@ maybe_constant_init_1 (tree t, tree decl, bool allow_non_constant)
>    else if (CONSTANT_CLASS_P (t) && allow_non_constant)
>      /* No evaluation needed.  */;
>    else
> -    t = cxx_eval_outermost_constant_expr (t, allow_non_constant, false, decl);
> +    t = cxx_eval_outermost_constant_expr (t, allow_non_constant,
> +                     !allow_non_constant,
> +                     pretend_const_required, decl);
>    if (TREE_CODE (t) == TARGET_EXPR)
>      {
>        tree init = TARGET_EXPR_INITIAL (t);
> 
> the false -> !allow_non_constant change means that when calling
> cxx_constant_init strict will be true because cxx_constant_init does not allow
> non constants.  That means that for VAR_DECLs such as __func__ we'll call
> decl_really_constant_value instead of decl_constant_value.  But only the latter
> can evaluate __func__ to "foo()".
> 
> Jakub, was there a specific reason for this change?  Changing it back still
> regtests cleanly and the attached test compiles again.

It just didn't feel right that cxx_constant_init which looks like a function
that requires strict conformance still passes false as strict.
If there is a reason to pass false, I think we need a comment that explains
it.

> Bootstrapped/regtested on x86_64-linux, ok for trunk?
> 
> 2018-09-20  Marek Polacek  <polacek@redhat.com>
> 
> 	PR c++/87372 - __func__ constexpr evaluation.
> 	* constexpr.c (maybe_constant_init_1): Pass false for strict down to
> 	cxx_eval_outermost_constant_expr.
> 
> 	* g++.dg/cpp1y/func_constexpr2.C: New test.
> 
> diff --git gcc/cp/constexpr.c gcc/cp/constexpr.c
> index fdea769faa9..6436b2f832d 100644
> --- gcc/cp/constexpr.c
> +++ gcc/cp/constexpr.c
> @@ -5361,7 +5361,7 @@ maybe_constant_init_1 (tree t, tree decl, bool allow_non_constant,
>      /* No evaluation needed.  */;
>    else
>      t = cxx_eval_outermost_constant_expr (t, allow_non_constant,
> -					  !allow_non_constant,
> +					  /*strict*/false,
>  					  pretend_const_required, decl);
>    if (TREE_CODE (t) == TARGET_EXPR)
>      {

	Jakub
Marek Polacek Sept. 21, 2018, 3:04 p.m. UTC | #2
On Fri, Sep 21, 2018 at 09:37:53AM +0200, Jakub Jelinek wrote:
> On Thu, Sep 20, 2018 at 11:56:37PM -0400, Marek Polacek wrote:
> > The patch for P0595R1 - is_constant_evaluated had this hunk:
> > 
> > @@ -5279,7 +5315,9 @@ maybe_constant_init_1 (tree t, tree decl, bool allow_non_constant)
> >    else if (CONSTANT_CLASS_P (t) && allow_non_constant)
> >      /* No evaluation needed.  */;
> >    else
> > -    t = cxx_eval_outermost_constant_expr (t, allow_non_constant, false, decl);
> > +    t = cxx_eval_outermost_constant_expr (t, allow_non_constant,
> > +                     !allow_non_constant,
> > +                     pretend_const_required, decl);
> >    if (TREE_CODE (t) == TARGET_EXPR)
> >      {
> >        tree init = TARGET_EXPR_INITIAL (t);
> > 
> > the false -> !allow_non_constant change means that when calling
> > cxx_constant_init strict will be true because cxx_constant_init does not allow
> > non constants.  That means that for VAR_DECLs such as __func__ we'll call
> > decl_really_constant_value instead of decl_constant_value.  But only the latter
> > can evaluate __func__ to "foo()".
> > 
> > Jakub, was there a specific reason for this change?  Changing it back still
> > regtests cleanly and the attached test compiles again.
> 
> It just didn't feel right that cxx_constant_init which looks like a function
> that requires strict conformance still passes false as strict.
> If there is a reason to pass false, I think we need a comment that explains
> it.

I think we use strict = true for *_constant_value, but *_constant_init should
get strict = false.

Marek
Jason Merrill Sept. 21, 2018, 3:19 p.m. UTC | #3
On Fri, Sep 21, 2018 at 11:04 AM, Marek Polacek <polacek@redhat.com> wrote:
> On Fri, Sep 21, 2018 at 09:37:53AM +0200, Jakub Jelinek wrote:
>> On Thu, Sep 20, 2018 at 11:56:37PM -0400, Marek Polacek wrote:
>> > The patch for P0595R1 - is_constant_evaluated had this hunk:
>> >
>> > @@ -5279,7 +5315,9 @@ maybe_constant_init_1 (tree t, tree decl, bool allow_non_constant)
>> >    else if (CONSTANT_CLASS_P (t) && allow_non_constant)
>> >      /* No evaluation needed.  */;
>> >    else
>> > -    t = cxx_eval_outermost_constant_expr (t, allow_non_constant, false, decl);
>> > +    t = cxx_eval_outermost_constant_expr (t, allow_non_constant,
>> > +                     !allow_non_constant,
>> > +                     pretend_const_required, decl);
>> >    if (TREE_CODE (t) == TARGET_EXPR)
>> >      {
>> >        tree init = TARGET_EXPR_INITIAL (t);
>> >
>> > the false -> !allow_non_constant change means that when calling
>> > cxx_constant_init strict will be true because cxx_constant_init does not allow
>> > non constants.  That means that for VAR_DECLs such as __func__ we'll call
>> > decl_really_constant_value instead of decl_constant_value.  But only the latter
>> > can evaluate __func__ to "foo()".
>> >
>> > Jakub, was there a specific reason for this change?  Changing it back still
>> > regtests cleanly and the attached test compiles again.
>>
>> It just didn't feel right that cxx_constant_init which looks like a function
>> that requires strict conformance still passes false as strict.
>> If there is a reason to pass false, I think we need a comment that explains
>> it.
>
> I think we use strict = true for *_constant_value, but *_constant_init should
> get strict = false.

Right.  In _init we try to get constant values for more than just C++
constant expressions.

Jason
Marek Polacek Sept. 21, 2018, 5:40 p.m. UTC | #4
On Fri, Sep 21, 2018 at 11:19:34AM -0400, Jason Merrill wrote:
> On Fri, Sep 21, 2018 at 11:04 AM, Marek Polacek <polacek@redhat.com> wrote:
> > On Fri, Sep 21, 2018 at 09:37:53AM +0200, Jakub Jelinek wrote:
> >> On Thu, Sep 20, 2018 at 11:56:37PM -0400, Marek Polacek wrote:
> >> > The patch for P0595R1 - is_constant_evaluated had this hunk:
> >> >
> >> > @@ -5279,7 +5315,9 @@ maybe_constant_init_1 (tree t, tree decl, bool allow_non_constant)
> >> >    else if (CONSTANT_CLASS_P (t) && allow_non_constant)
> >> >      /* No evaluation needed.  */;
> >> >    else
> >> > -    t = cxx_eval_outermost_constant_expr (t, allow_non_constant, false, decl);
> >> > +    t = cxx_eval_outermost_constant_expr (t, allow_non_constant,
> >> > +                     !allow_non_constant,
> >> > +                     pretend_const_required, decl);
> >> >    if (TREE_CODE (t) == TARGET_EXPR)
> >> >      {
> >> >        tree init = TARGET_EXPR_INITIAL (t);
> >> >
> >> > the false -> !allow_non_constant change means that when calling
> >> > cxx_constant_init strict will be true because cxx_constant_init does not allow
> >> > non constants.  That means that for VAR_DECLs such as __func__ we'll call
> >> > decl_really_constant_value instead of decl_constant_value.  But only the latter
> >> > can evaluate __func__ to "foo()".
> >> >
> >> > Jakub, was there a specific reason for this change?  Changing it back still
> >> > regtests cleanly and the attached test compiles again.
> >>
> >> It just didn't feel right that cxx_constant_init which looks like a function
> >> that requires strict conformance still passes false as strict.
> >> If there is a reason to pass false, I think we need a comment that explains
> >> it.
> >
> > I think we use strict = true for *_constant_value, but *_constant_init should
> > get strict = false.
> 
> Right.  In _init we try to get constant values for more than just C++
> constant expressions.

Is the patch OK then?

Marek
Jason Merrill Sept. 21, 2018, 6:39 p.m. UTC | #5
Yes.

On Fri, Sep 21, 2018 at 1:40 PM, Marek Polacek <polacek@redhat.com> wrote:
> On Fri, Sep 21, 2018 at 11:19:34AM -0400, Jason Merrill wrote:
>> On Fri, Sep 21, 2018 at 11:04 AM, Marek Polacek <polacek@redhat.com> wrote:
>> > On Fri, Sep 21, 2018 at 09:37:53AM +0200, Jakub Jelinek wrote:
>> >> On Thu, Sep 20, 2018 at 11:56:37PM -0400, Marek Polacek wrote:
>> >> > The patch for P0595R1 - is_constant_evaluated had this hunk:
>> >> >
>> >> > @@ -5279,7 +5315,9 @@ maybe_constant_init_1 (tree t, tree decl, bool allow_non_constant)
>> >> >    else if (CONSTANT_CLASS_P (t) && allow_non_constant)
>> >> >      /* No evaluation needed.  */;
>> >> >    else
>> >> > -    t = cxx_eval_outermost_constant_expr (t, allow_non_constant, false, decl);
>> >> > +    t = cxx_eval_outermost_constant_expr (t, allow_non_constant,
>> >> > +                     !allow_non_constant,
>> >> > +                     pretend_const_required, decl);
>> >> >    if (TREE_CODE (t) == TARGET_EXPR)
>> >> >      {
>> >> >        tree init = TARGET_EXPR_INITIAL (t);
>> >> >
>> >> > the false -> !allow_non_constant change means that when calling
>> >> > cxx_constant_init strict will be true because cxx_constant_init does not allow
>> >> > non constants.  That means that for VAR_DECLs such as __func__ we'll call
>> >> > decl_really_constant_value instead of decl_constant_value.  But only the latter
>> >> > can evaluate __func__ to "foo()".
>> >> >
>> >> > Jakub, was there a specific reason for this change?  Changing it back still
>> >> > regtests cleanly and the attached test compiles again.
>> >>
>> >> It just didn't feel right that cxx_constant_init which looks like a function
>> >> that requires strict conformance still passes false as strict.
>> >> If there is a reason to pass false, I think we need a comment that explains
>> >> it.
>> >
>> > I think we use strict = true for *_constant_value, but *_constant_init should
>> > get strict = false.
>>
>> Right.  In _init we try to get constant values for more than just C++
>> constant expressions.
>
> Is the patch OK then?
>
> Marek
diff mbox series

Patch

diff --git gcc/cp/constexpr.c gcc/cp/constexpr.c
index fdea769faa9..6436b2f832d 100644
--- gcc/cp/constexpr.c
+++ gcc/cp/constexpr.c
@@ -5361,7 +5361,7 @@  maybe_constant_init_1 (tree t, tree decl, bool allow_non_constant,
     /* No evaluation needed.  */;
   else
     t = cxx_eval_outermost_constant_expr (t, allow_non_constant,
-					  !allow_non_constant,
+					  /*strict*/false,
 					  pretend_const_required, decl);
   if (TREE_CODE (t) == TARGET_EXPR)
     {
diff --git gcc/testsuite/g++.dg/cpp1y/func_constexpr2.C gcc/testsuite/g++.dg/cpp1y/func_constexpr2.C
index e69de29bb2d..b1576e64960 100644
--- gcc/testsuite/g++.dg/cpp1y/func_constexpr2.C
+++ gcc/testsuite/g++.dg/cpp1y/func_constexpr2.C
@@ -0,0 +1,21 @@ 
+// PR c++/87372
+// { dg-do compile { target c++14 } }
+
+constexpr int
+foo (char const *s)
+{
+  int i = 0;
+  while (s[i])
+    ++i;
+  return i;
+}
+
+constexpr int
+bar ()
+{
+  constexpr int l = foo (__PRETTY_FUNCTION__);
+  constexpr int l2 = foo (__FUNCTION__);
+  constexpr int l3 = foo (__func__);
+  return l + l2 + l3;
+}
+static_assert (bar () == 25, "");