On Thu, 2 Jun 2022, Jason Merrill wrote:

> On 6/1/22 14:20, Patrick Palka wrote:
> > r12-7564-gec0f53a3a542e7 made us instantiate non-constant non-dependent
> > decltype operands by relaxing instantiate_non_dependent_expr to check
> > instantiation_dependent_uneval_expression_p.  But as the testcase below
> > demonstrates, this predicate is too permissive here because it allows
> > value-dependent-only expressions to go through and get instantiated
> > ahead of time, which causes us to crash during constexpr evaluation of
> > (5 % N).
> 
> Why are we doing constexpr evaluation in unevaluated context?

Looks like because cp_build_binary_op attempts to fold the resulting
operator expression via cp_fully_fold (which performs speculate
constexpr evaluation):

6261  if (!processing_template_decl)
6262    {
6263      if (resultcode == SPACESHIP_EXPR)
6264        result = get_target_expr (result, complain);
6265      op0 = cp_fully_fold (op0);
6266      /* Only consider the second argument if the first isn't overflowed.  
*/
6267      if (!CONSTANT_CLASS_P (op0) || TREE_OVERFLOW_P (op0))
6268        return result;
6269      op1 = cp_fully_fold (op1);
6270      if (!CONSTANT_CLASS_P (op1) || TREE_OVERFLOW_P (op1))
6271        return result;
6272    }

But in an unevaluated context I suppose we don't need or want to do this
folding.  I'll work on a patch to that effect.

> 
> > This patch strengthens instantiate_non_dependent_expr to use the
> > non-uneval version of the predicate instead, which does consider value
> > dependence.  In turn, we need to make finish_decltype_type avoid calling
> > i_n_d_e on a value-dependent-only expression; I assume we still want to
> > resolve the decltype ahead of time in this case.  (Doing so seems
> > unintuitive to me since the expression could be ill-formed at
> > instantiation time as in the testcase, but it matches the behavior of
> > Clang and MSVC.)
> 
> I don't think there's any problem with the testcase;  decltype(1/0) is
> well-formed because the expression is not evaluated.

D'oh, that makes sense, not sure what I was on about :)

> 
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> > trunk/12?
> > 
> >     PR c++/105756
> > 
> > gcc/cp/ChangeLog:
> > 
> >     * pt.cc (instantiate_non_dependent_expr_internal): Adjust
> >     comment.
> >     (instantiate_non_dependent_expr_sfinae): Assert i_d_e_p instead
> >     of i_d_u_e_p.
> >     * semantics.cc (finish_decltype_type): Don't instantiate the
> >     expression when i_d_e_p is true.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> >     * g++.dg/cpp0x/decltype82.C: New test.
> > ---
> >   gcc/cp/pt.cc                            |  4 ++--
> >   gcc/cp/semantics.cc                     | 13 ++++++++++++-
> >   gcc/testsuite/g++.dg/cpp0x/decltype82.C | 10 ++++++++++
> >   3 files changed, 24 insertions(+), 3 deletions(-)
> >   create mode 100644 gcc/testsuite/g++.dg/cpp0x/decltype82.C
> > 
> > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> > index e4a473002a0..1ea2545e115 100644
> > --- a/gcc/cp/pt.cc
> > +++ b/gcc/cp/pt.cc
> > @@ -6372,7 +6372,7 @@ redeclare_class_template (tree type, tree parms, tree
> > cons)
> >     /* The actual substitution part of
> > instantiate_non_dependent_expr_sfinae,
> >      to be used when the caller has already checked
> > -    !instantiation_dependent_uneval_expression_p (expr)
> > +    !instantiation_dependent_expression_p (expr)
> >      and cleared processing_template_decl.  */
> >     tree
> > @@ -6397,7 +6397,7 @@ instantiate_non_dependent_expr_sfinae (tree expr,
> > tsubst_flags_t complain)
> >     if (processing_template_decl)
> >       {
> >         /* The caller should have checked this already.  */
> > -      gcc_checking_assert (!instantiation_dependent_uneval_expression_p
> > (expr));
> > +      gcc_checking_assert (!instantiation_dependent_expression_p (expr));
> >         processing_template_decl_sentinel s;
> >         expr = instantiate_non_dependent_expr_internal (expr, complain);
> >       }
> > diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> > index 3600d270ff8..b23848ab94c 100644
> > --- a/gcc/cp/semantics.cc
> > +++ b/gcc/cp/semantics.cc
> > @@ -11302,9 +11302,20 @@ finish_decltype_type (tree expr, bool
> > id_expression_or_member_access_p,
> >           return type;
> >       }
> > +  else if (processing_template_decl
> > +      && potential_constant_expression (expr)
> > +      && value_dependent_expression_p (expr))
> > +    /* The above test is equivalent to instantiation_dependent_expression_p
> > +       after instantiation_dependent_uneval_expression_p has been ruled
> > out.
> > +       In this case the expression is dependent but not type-dependent, so
> > +       we can resolve the decltype ahead of time but we can't instantiate
> > +       the expression.  */;
> >     else if (processing_template_decl)
> >       {
> > -      expr = instantiate_non_dependent_expr_sfinae (expr,
> > complain|tf_decltype);
> > +      /* The expression isn't instantiation dependent, so we can fully
> > +    instantiate it ahead of time.  */
> > +      expr = instantiate_non_dependent_expr_sfinae (expr,
> > +                                               complain|tf_decltype);
> >         if (expr == error_mark_node)
> >     return error_mark_node;
> >         /* Keep processing_template_decl cleared for the rest of the
> > function
> > diff --git a/gcc/testsuite/g++.dg/cpp0x/decltype82.C
> > b/gcc/testsuite/g++.dg/cpp0x/decltype82.C
> > new file mode 100644
> > index 00000000000..915e5e37675
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/cpp0x/decltype82.C
> > @@ -0,0 +1,10 @@
> > +// PR c++/105756
> > +// { dg-do compile { target c++11 } }
> > +
> > +template<int N>
> > +void f() {
> > +  using ty1 = decltype((5 % N) == 0);
> > +  using ty2 = decltype((5 / N) == 0);
> > +}
> > +
> > +template void f<0>();
> 
> 

Reply via email to