Message ID | 20180921035637.GW5587@redhat.com |
---|---|
State | New |
Headers | show |
Series | C++ PATCH for c++/87372, __func__ constexpr evaluation | expand |
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
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
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
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
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 --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, "");