On Tue, 28 Apr 2020, Patrick Palka wrote:

> On Tue, 28 Apr 2020, Jason Merrill wrote:
> 
> > On 4/28/20 1:41 PM, Patrick Palka wrote:
> > > On Tue, 28 Apr 2020, Patrick Palka wrote:
> > > 
> > > > On Tue, 28 Apr 2020, Jason Merrill wrote:
> > > > > On 4/28/20 9:48 AM, Patrick Palka wrote:
> > > > > > When printing the substituted parameter list of a 
> > > > > > requires-expression
> > > > > > as
> > > > > > part of the "in requirements with ..." context line during concepts
> > > > > > diagnostics, we weren't considering that substitution into a 
> > > > > > parameter
> > > > > > pack can yield zero or multiple parameters.
> > > > > > 
> > > > > > Since this patch affects only concepts diagnostics, so far I tested
> > > > > > with
> > > > > > RUNTESTFLAGS="dg.exp=*concepts*" and also verified that we no longer
> > > > > > ICE
> > > > > > with the unreduced testcase in the PR.  Is this OK to commit after a
> > > > > > full bootstrap and regtest?
> > > > > 
> > > > > OK.
> > > > 
> > > > Thanks for the review.
> > > > 
> > > > > 
> > > > > Though I wonder about printing the dependent form and template 
> > > > > arguments
> > > > > instead.  Do you have an opinion?
> > > > 
> > > > I was going to say that on the one hand, it's convenient to have the
> > > > substituted form printed since it would let us to see through
> > > > complicated dependent type aliases, but it seems we don't strip type
> > > > aliases when pretty printing a parameter and its type with '%q#D'
> > > > anyway.  And I can't think of any other possible advantage of printing
> > > > the substituted form.
> > > > 
> > > > So IMHO printing the dependent form and template arguments instead would
> > > > be better here.  I'll try to write a patch for this today.
> > > 
> > > Like so, tested so far with RUNTESTFLAGS="dg.exp=*concepts*" and also
> > > verified we no longer ICE with the unreduced testcase in the PR.  Does
> > > the following look OK to commit after a full bootstrap and regtest?
> > > 
> > > -- >8 --
> > > 
> > > Subject: [PATCH] c++: Parameter pack in requires parameter list [PR94808]
> > > 
> > > When printing the substituted parameter list of a requires-expression as
> > > part of the "in requirements with ..." context line during concepts
> > > diagnostics, we weren't considering that substitution into a parameter
> > > pack can yield zero or multiple parameters.
> > > 
> > > This patch changes the way we print the parameter list of a
> > > requires-expression in print_requires_expression_info.  We now print the
> > > dependent form of the parameter list (along with its template parameter
> > > mapping) instead of printing its substituted form.  Besides being an
> > > improvement in its own, this also sidesteps the above parameter pack
> > > expansion issue altogether.
> > > 
> > > Tested with RUNTESTFLAGS="dg.exp=*concepts*" and also verified we longer
> > > ICE with the unreduced testcase in the PR.  Does this look OK to commit
> > > after a bootstrap and regtest?
> > > 
> > > gcc/cp/ChangeLog:
> > > 
> > >   PR c++/94808
> > >   * error.c (print_requires_expression_info): Print the dependent
> > >   form of the parameter list with its template parameter mapping,
> > >   rather than printing the substituted form.
> > > 
> > > gcc/testsuite/ChangeLog:
> > > 
> > >   PR c++/94808
> > >   * g++.dg/concepts/diagnostic12.C: New test.
> > >   * g++.dg/concepts/diagnostic5.C: Adjust expected diagnostic.
> > > ---
> > >   gcc/cp/error.c                               | 16 ++++------------
> > >   gcc/testsuite/g++.dg/concepts/diagnostic12.C | 16 ++++++++++++++++
> > >   gcc/testsuite/g++.dg/concepts/diagnostic5.C  |  4 ++--
> > >   3 files changed, 22 insertions(+), 14 deletions(-)
> > >   create mode 100644 gcc/testsuite/g++.dg/concepts/diagnostic12.C
> > > 
> > > diff --git a/gcc/cp/error.c b/gcc/cp/error.c
> > > index 98c163db572..46970f9b699 100644
> > > --- a/gcc/cp/error.c
> > > +++ b/gcc/cp/error.c
> > > @@ -3746,7 +3746,6 @@ print_requires_expression_info (diagnostic_context
> > > *context, tree constr, tree a
> > >     map = tsubst_parameter_mapping (map, args, tf_none, NULL_TREE);
> > >     if (map == error_mark_node)
> > >       return;
> > > -  args = get_mapped_args (map);
> > >       print_location (context, cp_expr_loc_or_input_loc (expr));
> > >     pp_verbatim (context->printer, "in requirements ");
> > > @@ -3756,19 +3755,12 @@ print_requires_expression_info (diagnostic_context
> > > *context, tree constr, tree a
> > >       pp_verbatim (context->printer, "with ");
> > >     while (parms)
> > >       {
> > > -      tree next = TREE_CHAIN (parms);
> > > -
> > > -      TREE_CHAIN (parms) = NULL_TREE;
> > > -      cp_unevaluated u;
> > > -      tree p = tsubst (parms, args, tf_none, NULL_TREE);
> > > -      pp_verbatim (context->printer, "%q#D", p);
> > > -      TREE_CHAIN (parms) = next;
> > > -
> > > -      if (next)
> > > +      pp_verbatim (context->printer, "%q#D", parms);
> > > +      if (TREE_CHAIN (parms))
> > >           pp_separate_with_comma ((cxx_pretty_printer *)context->printer);
> > > -
> > > -      parms = next;
> > > +      parms = TREE_CHAIN (parms);
> > >       }
> > > +  pp_cxx_parameter_mapping ((cxx_pretty_printer *)context->printer, map);
> > >       pp_verbatim (context->printer, "\n");
> > >   }
> > > diff --git a/gcc/testsuite/g++.dg/concepts/diagnostic12.C
> > > b/gcc/testsuite/g++.dg/concepts/diagnostic12.C
> > > new file mode 100644
> > > index 00000000000..a757342f754
> > > --- /dev/null
> > > +++ b/gcc/testsuite/g++.dg/concepts/diagnostic12.C
> > > @@ -0,0 +1,16 @@
> > > +// PR c++/94808
> > > +// { dg-do compile { target concepts } }
> > > +
> > > +template<typename T, typename... Args>
> > > +  concept c1 = requires (T t, Args... args) { *t; };
> > > +// { dg-message "in requirements with .T t., .Args ... args. .with.* 
> > > Args =
> > > \{\}" "" { target *-*-* } .-1 }
> > 
> > Doesn't this print a binding for T?
> 
> Yes, but the order in which the binding for T and the binding for Args
> is printed appears to be nondeterministic, so I lazily opted to check
> for just one of the bindings.
> 
> This nondeterminism stems from how find_template_parameters is
> implemented, which uses a hash_set<tree> to keep track of seen template
> parameters and then builds a TREE_LIST of mappings according to the
> (nondeterministic) order of entries in the table.  I think it is
> harmless semantically but it does affect diagnostics such as these.

I've just created PR94830 for this issue.

> 
> > 
> > > +
> > > +static_assert(c1<int>); // { dg-error "failed" }
> > > +
> > > +void f(...);
> > > +
> > > +template<typename... Args>
> > > +  concept c2 = requires (Args... args) { f(*args...); };
> > > +// { dg-message "in requirements with .Args ... args. .with Args = \{int,
> > > char\}" "" { target *-*-* } .-1 }
> > > +
> > > +static_assert(c2<int, char>); // { dg-error "failed" }
> > > diff --git a/gcc/testsuite/g++.dg/concepts/diagnostic5.C
> > > b/gcc/testsuite/g++.dg/concepts/diagnostic5.C
> > > index 0d890d6f548..81705f6a0c6 100644
> > > --- a/gcc/testsuite/g++.dg/concepts/diagnostic5.C
> > > +++ b/gcc/testsuite/g++.dg/concepts/diagnostic5.C
> > > @@ -9,7 +9,7 @@ template<typename T>
> > >   template<typename T>
> > >     concept c2 = requires (T x) { *x; };
> > >   // { dg-message "satisfaction of .c2<T>. .with T = char." "" { target
> > > *-*-* } .-1 }
> > > -// { dg-message "in requirements with .char x." "" { target *-*-* } .-2 }
> > > +// { dg-message "in requirements with .T x. .with T = char." "" { target
> > > *-*-* } .-2 }
> > >   // { dg-message "required expression .* is invalid" "" { target *-*-* }
> > > .-3 }
> > >     template<typename T>
> > > @@ -25,7 +25,7 @@ template<typename T>
> > >   template<typename T>
> > >     concept c5 = requires (T x) { { &x } -> c1; };
> > >   // { dg-message "satisfaction of .c5<T>. .with T = char." "" { target
> > > *-*-* } .-1 }
> > > -// { dg-message "in requirements with .char x." "" { target *-*-* } .-2 }
> > > +// { dg-message "in requirements with .T x. .with T = char." "" { target
> > > *-*-* } .-2 }
> > >     template<typename T>
> > >     requires (c1<T> || c2<T>) || (c3<T> || c4<T>) || c5<T> // { dg-message
> > > "49: no operand" }
> > > 
> > 
> > 
> 

Reply via email to