On Sun, 29 May 2022, Jason Merrill wrote:

> On 5/29/22 22:10, Jason Merrill wrote:
> > On 5/27/22 14:05, Patrick Palka wrote:
> > > This makes us avoid substituting into the TEMPLATE_PARM_CONSTRAINT of
> > > each template parameter except as necessary for (friend) declaration
> > > matching, like we already do for the overall TEMPLATE_PARMS_CONSTRAINTS
> > > of a template parameter list.
> > > 
> > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> > > trunk and perhaps 12.2?  Also tested on range-v3 and cmcstl2.
> > 
> > Are there already tests that cover the friend cases?

Yes, by cpp2a/concepts-friend{2,3,7}.C I think.

> 
> Also, don't you also need to handle specialization of partial instantiations?

Hmm, do you have an example?  IIUC we call tsubst_friend_function and
tsubst_friend_class only from instantiate_class_template_1, which always
uses the most general template and full template argument set to
instantiate any friend declarations.  So friend declarations are never
partially instantiated I think.  (And IIUC non-friends are irrelevant
here since we don't ever want to substitute their constraints outside of
satisfaction.)

> 
> > >     PR c++/100374
> > > 
> > > gcc/cp/ChangeLog:
> > > 
> > >     * pt.cc (tsubst_each_template_parm_constraint): Define.
> > >     (tsubst_friend_function): Use it.
> > >     (tsubst_friend_class): Use it.
> > >     (tsubst_template_parm): Don't substitute TEMPLATE_PARM_CONSTRAINT.
> > > 
> > > gcc/testsuite/ChangeLog:
> > > 
> > >     * g++.dg/cpp2a/concepts-template-parm11.C: New test.
> > > ---
> > >   gcc/cp/pt.cc                                  | 35 ++++++++++++++++---
> > >   .../g++.dg/cpp2a/concepts-template-parm11.C   | 16 +++++++++
> > >   2 files changed, 47 insertions(+), 4 deletions(-)
> > >   create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-template-parm11.C
> > > 
> > > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> > > index 24bbe2f4060..ec168234325 100644
> > > --- a/gcc/cp/pt.cc
> > > +++ b/gcc/cp/pt.cc
> > > @@ -184,6 +184,7 @@ static int unify_pack_expansion (tree, tree, tree,
> > >                    tree, unification_kind_t, bool, bool);
> > >   static tree copy_template_args (tree);
> > >   static tree tsubst_template_parms (tree, tree, tsubst_flags_t);
> > > +static void tsubst_each_template_parm_constraint (tree, tree,
> > > tsubst_flags_t);
> > >   tree most_specialized_partial_spec (tree, tsubst_flags_t);
> > >   static tree tsubst_aggr_type (tree, tree, tsubst_flags_t, tree, int);
> > >   static tree tsubst_arg_types (tree, tree, tree, tsubst_flags_t, tree);
> > > @@ -11254,7 +11255,12 @@ tsubst_friend_function (tree decl, tree args)
> > >         tree parms = DECL_TEMPLATE_PARMS (new_friend);
> > >         tree treqs = TEMPLATE_PARMS_CONSTRAINTS (parms);
> > >         treqs = maybe_substitute_reqs_for (treqs, new_friend);
> > > -      TEMPLATE_PARMS_CONSTRAINTS (parms) = treqs;
> > > +      if (treqs != TEMPLATE_PARMS_CONSTRAINTS (parms))
> > > +    {
> > > +      TEMPLATE_PARMS_CONSTRAINTS (parms) = treqs;
> > > +      /* As well as each TEMPLATE_PARM_CONSTRAINT.  */
> > > +      tsubst_each_template_parm_constraint (parms, args,
> > > tf_warning_or_error);
> > > +    }
> > >       }
> > >     /* The mangled name for the NEW_FRIEND is incorrect.  The function
> > > @@ -11500,6 +11506,8 @@ tsubst_friend_class (tree friend_tmpl, tree args)
> > >       {
> > >         tree parms = tsubst_template_parms (DECL_TEMPLATE_PARMS
> > > (friend_tmpl),
> > >                             args, tf_warning_or_error);
> > > +      tsubst_each_template_parm_constraint (parms, args,
> > > +                        tf_warning_or_error);
> > >             location_t saved_input_location = input_location;
> > >             input_location = DECL_SOURCE_LOCATION (friend_tmpl);
> > >             tree cons = get_constraints (tmpl);
> > > @@ -11534,6 +11542,8 @@ tsubst_friend_class (tree friend_tmpl, tree args)
> > >                          DECL_FRIEND_CONTEXT (friend_tmpl));
> > >             --processing_template_decl;
> > >             set_constraints (tmpl, ci);
> > > +          tsubst_each_template_parm_constraint (DECL_TEMPLATE_PARMS
> > > (tmpl),
> > > +                            args, tf_warning_or_error);
> > >           }
> > >         /* Inject this template into the enclosing namspace scope.  */
> > > @@ -13656,7 +13666,6 @@ tsubst_template_parm (tree t, tree args,
> > > tsubst_flags_t complain)
> > >     default_value = TREE_PURPOSE (t);
> > >     parm_decl = TREE_VALUE (t);
> > > -  tree constraint = TEMPLATE_PARM_CONSTRAINTS (t);
> > >     parm_decl = tsubst (parm_decl, args, complain, NULL_TREE);
> > >     if (TREE_CODE (parm_decl) == PARM_DECL
> > > @@ -13664,13 +13673,31 @@ tsubst_template_parm (tree t, tree args,
> > > tsubst_flags_t complain)
> > >       parm_decl = error_mark_node;
> > >     default_value = tsubst_template_arg (default_value, args,
> > >                          complain, NULL_TREE);
> > > -  constraint = tsubst_constraint (constraint, args, complain, NULL_TREE);
> > >     tree r = build_tree_list (default_value, parm_decl);
> > > -  TEMPLATE_PARM_CONSTRAINTS (r) = constraint;
> > > +  TEMPLATE_PARM_CONSTRAINTS (r) = TEMPLATE_PARM_CONSTRAINTS (t);
> > >     return r;
> > >   }
> > > +/* Substitute in-place the TEMPLATE_PARM_CONSTRAINT of each template
> > > +   parameter in PARMS for sake of declaration matching.  */
> > > +
> > > +static void
> > > +tsubst_each_template_parm_constraint (tree parms, tree args,
> > > +                      tsubst_flags_t complain)
> > > +{
> > > +  ++processing_template_decl;
> > > +  for (; parms; parms = TREE_CHAIN (parms))
> > > +    {
> > > +      tree level = TREE_VALUE (parms);
> > > +      for (tree parm : tree_vec_range (level))
> > > +    TEMPLATE_PARM_CONSTRAINTS (parm)
> > > +      = tsubst_constraint (TEMPLATE_PARM_CONSTRAINTS (parm), args,
> > > +                   complain, NULL_TREE);
> > > +    }
> > > +  --processing_template_decl;
> > > +}
> > > +
> > >   /* Substitute the ARGS into the indicated aggregate (or enumeration)
> > >      type T.  If T is not an aggregate or enumeration type, it is
> > >      handled as if by tsubst.  IN_DECL is as for tsubst.  If
> > > diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-template-parm11.C
> > > b/gcc/testsuite/g++.dg/cpp2a/concepts-template-parm11.C
> > > new file mode 100644
> > > index 00000000000..f70de341a07
> > > --- /dev/null
> > > +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-template-parm11.C
> > > @@ -0,0 +1,16 @@
> > > +// PR c++/100374
> > > +// { dg-do compile { target c++20 } }
> > > +
> > > +template<class T, class U>
> > > +concept C = true;
> > > +
> > > +template<class T>
> > > +struct A {
> > > +  template<C<typename T::value_type> U>
> > > +  void f();
> > > +
> > > +  template<C<typename T::value_type> U>
> > > +  struct B;
> > > +};
> > > +
> > > +template struct A<float>;
> > 
> 
> 

Reply via email to