diff mbox series

c++: ICE with deduction guide in checking type-dep [PR99009, PR97034]

Message ID 20210212231212.3247549-1-polacek@redhat.com
State New
Headers show
Series c++: ICE with deduction guide in checking type-dep [PR99009, PR97034] | expand

Commit Message

Marek Polacek Feb. 12, 2021, 11:12 p.m. UTC
We represent deduction guides with FUNCTION_DECLs, but they are built
without DECL_CONTEXT, leading to an ICE in type_dependent_expression_p
on the assert that the type of a function template with no dependent
(innermost!) template arguments must be non-dependent.  Consider the
attached class-deduction79.C: we create a deduction guide:

  template<class T> G(T)-> E<Z>::G<T>

we deduce T and create a partial instantiation:

  G(T) -> E<Z>::G<T> [with T = int]

And then do_class_deduction wants to create a CALL_EXPR from the above
using build_new_function_call -> build_over_call which calls mark_used
-> maybe_instantiate_noexcept -> type_dependent_expression_p.

There, the innermost template arguments are non-dependent (<int>), but
the fntype is dependent -- the return type is a TYPENAME_TYPE, and
since we have no DECL_CONTEXT, this check holds:

  /* Otherwise, if the function decl isn't from a dependent scope, it can't be
     type-dependent.  Checking this is important for functions with auto return
     type, which looks like a dependent type.  */
  if (TREE_CODE (expression) == FUNCTION_DECL
      && !(DECL_CLASS_SCOPE_P (expression)
           && dependent_type_p (DECL_CONTEXT (expression)))

whereupon we ICE.

Experiments with setting DECL_CONTEXT didn't pan out.  So perhaps we
just want to skip the assert for deduction guides, because they are
a little special.  Better ideas solicited.

Bootstrapped/regtested on x86_64-pc-linux-gnu.

gcc/cp/ChangeLog:

	PR c++/97034
	PR c++/99009
	* pt.c (type_dependent_expression_p): Don't assert that the type
	of a deduction guide must non-dependent.

gcc/testsuite/ChangeLog:

	PR c++/97034
	PR c++/99009
	* g++.dg/cpp1z/class-deduction79.C: New test.
	* g++.dg/cpp1z/class-deduction80.C: New test.
	* g++.dg/cpp2a/class-deduction-aggr8.C: New test.
	* g++.dg/cpp2a/class-deduction-aggr9.C: New test.
---
 gcc/cp/pt.c                                   |  5 ++++-
 .../g++.dg/cpp1z/class-deduction79.C          | 20 +++++++++++++++++++
 .../g++.dg/cpp1z/class-deduction80.C          | 12 +++++++++++
 .../g++.dg/cpp2a/class-deduction-aggr8.C      | 19 ++++++++++++++++++
 .../g++.dg/cpp2a/class-deduction-aggr9.C      | 18 +++++++++++++++++
 5 files changed, 73 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction79.C
 create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction80.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr8.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr9.C


base-commit: eb64b0b285b4fda9e8eeda4c2f370e636b1ab2ae

Comments

Marek Polacek Feb. 25, 2021, 12:12 a.m. UTC | #1
Ping.

On Fri, Feb 12, 2021 at 06:12:12PM -0500, Marek Polacek via Gcc-patches wrote:
> We represent deduction guides with FUNCTION_DECLs, but they are built
> without DECL_CONTEXT, leading to an ICE in type_dependent_expression_p
> on the assert that the type of a function template with no dependent
> (innermost!) template arguments must be non-dependent.  Consider the
> attached class-deduction79.C: we create a deduction guide:
> 
>   template<class T> G(T)-> E<Z>::G<T>
> 
> we deduce T and create a partial instantiation:
> 
>   G(T) -> E<Z>::G<T> [with T = int]
> 
> And then do_class_deduction wants to create a CALL_EXPR from the above
> using build_new_function_call -> build_over_call which calls mark_used
> -> maybe_instantiate_noexcept -> type_dependent_expression_p.
> 
> There, the innermost template arguments are non-dependent (<int>), but
> the fntype is dependent -- the return type is a TYPENAME_TYPE, and
> since we have no DECL_CONTEXT, this check holds:
> 
>   /* Otherwise, if the function decl isn't from a dependent scope, it can't be
>      type-dependent.  Checking this is important for functions with auto return
>      type, which looks like a dependent type.  */
>   if (TREE_CODE (expression) == FUNCTION_DECL
>       && !(DECL_CLASS_SCOPE_P (expression)
>            && dependent_type_p (DECL_CONTEXT (expression)))
> 
> whereupon we ICE.
> 
> Experiments with setting DECL_CONTEXT didn't pan out.  So perhaps we
> just want to skip the assert for deduction guides, because they are
> a little special.  Better ideas solicited.
> 
> Bootstrapped/regtested on x86_64-pc-linux-gnu.
> 
> gcc/cp/ChangeLog:
> 
> 	PR c++/97034
> 	PR c++/99009
> 	* pt.c (type_dependent_expression_p): Don't assert that the type
> 	of a deduction guide must non-dependent.
> 
> gcc/testsuite/ChangeLog:
> 
> 	PR c++/97034
> 	PR c++/99009
> 	* g++.dg/cpp1z/class-deduction79.C: New test.
> 	* g++.dg/cpp1z/class-deduction80.C: New test.
> 	* g++.dg/cpp2a/class-deduction-aggr8.C: New test.
> 	* g++.dg/cpp2a/class-deduction-aggr9.C: New test.
> ---
>  gcc/cp/pt.c                                   |  5 ++++-
>  .../g++.dg/cpp1z/class-deduction79.C          | 20 +++++++++++++++++++
>  .../g++.dg/cpp1z/class-deduction80.C          | 12 +++++++++++
>  .../g++.dg/cpp2a/class-deduction-aggr8.C      | 19 ++++++++++++++++++
>  .../g++.dg/cpp2a/class-deduction-aggr9.C      | 18 +++++++++++++++++
>  5 files changed, 73 insertions(+), 1 deletion(-)
>  create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction79.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction80.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr8.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr9.C
> 
> diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
> index 60de8e93ff7..3e6f3407d40 100644
> --- a/gcc/cp/pt.c
> +++ b/gcc/cp/pt.c
> @@ -27282,7 +27282,10 @@ type_dependent_expression_p (tree expression)
>  	   && DECL_UNIQUE_FRIEND_P (expression)
>  	   && (!DECL_FRIEND_CONTEXT (expression)
>  	       || dependent_type_p (DECL_FRIEND_CONTEXT (expression))))
> -      && !DECL_LOCAL_DECL_P (expression))
> +      && !DECL_LOCAL_DECL_P (expression)
> +      /* We build deduction guides without any DECL_CONTEXT, but they can
> +	 be type-dependent.  */
> +      && !deduction_guide_p (expression))
>      {
>        gcc_assert (!dependent_type_p (TREE_TYPE (expression))
>  		  || undeduced_auto_decl (expression));
> diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction79.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction79.C
> new file mode 100644
> index 00000000000..86a68248157
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction79.C
> @@ -0,0 +1,20 @@
> +// PR c++/97034
> +// { dg-do compile { target c++17 } }
> +
> +template <typename Z>
> +struct E {
> +  template <typename T>
> +  struct G {
> +    T t;
> +    G(T) { }
> +  };
> +
> +  void fn() { G{1}; }
> +};
> +
> +void
> +g ()
> +{
> +  E<int> e;
> +  e.fn ();
> +}
> diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction80.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction80.C
> new file mode 100644
> index 00000000000..238024c508f
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction80.C
> @@ -0,0 +1,12 @@
> +// PR c++/99009
> +// { dg-do compile { target c++17 } }
> +
> +template<typename> struct B {
> +  B(int = A()) {}
> +  template <typename ...> struct A;
> +};
> +
> +template<typename T> struct X {
> +  template <T...> struct Y;
> +  X() { Y y; };
> +};
> diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr8.C b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr8.C
> new file mode 100644
> index 00000000000..399061100ae
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr8.C
> @@ -0,0 +1,19 @@
> +// PR c++/97034
> +// { dg-do compile { target c++20 } }
> +
> +namespace N {
> +template <typename, typename> struct S {
> +  template <typename T, typename U> S(T, U);
> +};
> +} // namespace N
> +template <int> struct E {
> +  template <typename T> struct G { T t; };
> +  void fn() { G{N::S<char, int>{'a', 1}}; }
> +};
> +
> +void
> +g ()
> +{
> +  E<1> e;
> +  e.fn ();
> +}
> diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr9.C b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr9.C
> new file mode 100644
> index 00000000000..245a04cd5f9
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr9.C
> @@ -0,0 +1,18 @@
> +// PR c++/97034
> +// { dg-do compile { target c++20 } }
> +
> +template<typename>
> +struct E {
> +  template <typename T>
> +  struct G {
> +    T t;
> +  };
> +
> +  void fn() { G{1}; }
> +};
> +
> +void
> +g () {
> +  E<int> e;
> +  e.fn ();
> +}
> 
> base-commit: eb64b0b285b4fda9e8eeda4c2f370e636b1ab2ae
> -- 
> 2.29.2
> 

Marek
Jason Merrill Feb. 25, 2021, 3:59 p.m. UTC | #2
On 2/12/21 6:12 PM, Marek Polacek wrote:
> We represent deduction guides with FUNCTION_DECLs, but they are built
> without DECL_CONTEXT

Hmm, that seems wrong: "A deduction-guide shall be declared in the
same scope as the corresponding class template and, for a member class 
template, with the same access."  But it probably isn't necessary to 
change this:

> leading to an ICE in type_dependent_expression_p
> on the assert that the type of a function template with no dependent
> (innermost!) template arguments must be non-dependent.  Consider the
> attached class-deduction79.C: we create a deduction guide:
> 
>    template<class T> G(T)-> E<Z>::G<T>
> 
> we deduce T and create a partial instantiation:
> 
>    G(T) -> E<Z>::G<T> [with T = int]
> 
> And then do_class_deduction wants to create a CALL_EXPR from the above
> using build_new_function_call -> build_over_call which calls mark_used
> -> maybe_instantiate_noexcept -> type_dependent_expression_p.
> 
> There, the innermost template arguments are non-dependent (<int>), but
> the fntype is dependent -- the return type is a TYPENAME_TYPE, and
> since we have no DECL_CONTEXT, this check holds:
> 
>    /* Otherwise, if the function decl isn't from a dependent scope, it can't be
>       type-dependent.  Checking this is important for functions with auto return
>       type, which looks like a dependent type.  */
>    if (TREE_CODE (expression) == FUNCTION_DECL
>        && !(DECL_CLASS_SCOPE_P (expression)
>             && dependent_type_p (DECL_CONTEXT (expression)))
> 
> whereupon we ICE.
> 
> Experiments with setting DECL_CONTEXT didn't pan out.

In c8 of the PR it looks like you were using the class itself as 
DECL_CONTEXT; the quote above says that the right context is the 
enclosing scope of the class.

> So perhaps we
> just want to skip the assert for deduction guides, because they are
> a little special.  Better ideas solicited.

In c3 you mention that one of the variants broke with r269093; this is 
because my change to check CLASSTYPE_TEMPLATE_INSTANTIATION is false for 
the template pattern itself (E<Z>).

But I think probably the right answer is to defer this deduction until 
the enclosing scope is non-dependent, i.e. (untested)
Marek Polacek Feb. 25, 2021, 10:41 p.m. UTC | #3
On Thu, Feb 25, 2021 at 10:59:49AM -0500, Jason Merrill wrote:
> On 2/12/21 6:12 PM, Marek Polacek wrote:
> > We represent deduction guides with FUNCTION_DECLs, but they are built
> > without DECL_CONTEXT
> 
> Hmm, that seems wrong: "A deduction-guide shall be declared in the
> same scope as the corresponding class template and, for a member class
> template, with the same access."  But it probably isn't necessary to change
> this:
> 
> > leading to an ICE in type_dependent_expression_p
> > on the assert that the type of a function template with no dependent
> > (innermost!) template arguments must be non-dependent.  Consider the
> > attached class-deduction79.C: we create a deduction guide:
> > 
> >    template<class T> G(T)-> E<Z>::G<T>
> > 
> > we deduce T and create a partial instantiation:
> > 
> >    G(T) -> E<Z>::G<T> [with T = int]
> > 
> > And then do_class_deduction wants to create a CALL_EXPR from the above
> > using build_new_function_call -> build_over_call which calls mark_used
> > -> maybe_instantiate_noexcept -> type_dependent_expression_p.
> > 
> > There, the innermost template arguments are non-dependent (<int>), but
> > the fntype is dependent -- the return type is a TYPENAME_TYPE, and
> > since we have no DECL_CONTEXT, this check holds:
> > 
> >    /* Otherwise, if the function decl isn't from a dependent scope, it can't be
> >       type-dependent.  Checking this is important for functions with auto return
> >       type, which looks like a dependent type.  */
> >    if (TREE_CODE (expression) == FUNCTION_DECL
> >        && !(DECL_CLASS_SCOPE_P (expression)
> >             && dependent_type_p (DECL_CONTEXT (expression)))
> > 
> > whereupon we ICE.
> > 
> > Experiments with setting DECL_CONTEXT didn't pan out.
> 
> In c8 of the PR it looks like you were using the class itself as
> DECL_CONTEXT; the quote above says that the right context is the enclosing
> scope of the class.

Sadly, using CP_TYPE_CONTEXT (type) would result in a crash in
retrieve_specialization:

  /* There should be as many levels of arguments as there are
     levels of parameters.  */
  gcc_assert (TMPL_ARGS_DEPTH (args)
              == (TREE_CODE (tmpl) == TEMPLATE_DECL
                  ? TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (tmpl))
                  : template_class_depth (DECL_CONTEXT (tmpl))));

> > So perhaps we
> > just want to skip the assert for deduction guides, because they are
> > a little special.  Better ideas solicited.
> 
> In c3 you mention that one of the variants broke with r269093; this is
> because my change to check CLASSTYPE_TEMPLATE_INSTANTIATION is false for the
> template pattern itself (E<Z>).

And the original test started with my r11-1713 because using TREE_TYPE
directly instead of decltype (which is a non-deduced context) means we
can deduced from the argument.
 
> But I think probably the right answer is to defer this deduction until the
> enclosing scope is non-dependent, i.e. (untested)

Thanks.  That mostly works, except the new class-deduction-aggr[89].C
tests.  Consider 8:

namespace N {
template <typename, typename> struct S {
  template <typename T, typename U> S(T, U);
};
} // namespace N
template <int> struct E {
  template <typename T> struct G { T t; };
  void fn() { G{N::S<char, int>{'a', 1}}; }
};

void
g ()
{
  E<1> e;
  e.fn ();
}

With your patch, when in do_class_deduction when processing_template_decl,
we just return.  When we call do_class_deduction again when p_t_d is 0,
maybe_aggr_guide returns early here:

  if (!CP_AGGREGATE_TYPE_P (type))
    return NULL_TREE

because G is not complete (and rightly so, we didn't instantiate it).  So
we aren't able to deduce the template parameters.  I'm not sure if I should
pursue this direction further.  :(

Marek
Jason Merrill Feb. 26, 2021, 3:45 a.m. UTC | #4
On 2/25/21 5:41 PM, Marek Polacek wrote:
> On Thu, Feb 25, 2021 at 10:59:49AM -0500, Jason Merrill wrote:
>> On 2/12/21 6:12 PM, Marek Polacek wrote:
>>> We represent deduction guides with FUNCTION_DECLs, but they are built
>>> without DECL_CONTEXT
>>
>> Hmm, that seems wrong: "A deduction-guide shall be declared in the
>> same scope as the corresponding class template and, for a member class
>> template, with the same access."  But it probably isn't necessary to change
>> this:
>>
>>> leading to an ICE in type_dependent_expression_p
>>> on the assert that the type of a function template with no dependent
>>> (innermost!) template arguments must be non-dependent.  Consider the
>>> attached class-deduction79.C: we create a deduction guide:
>>>
>>>     template<class T> G(T)-> E<Z>::G<T>
>>>
>>> we deduce T and create a partial instantiation:
>>>
>>>     G(T) -> E<Z>::G<T> [with T = int]
>>>
>>> And then do_class_deduction wants to create a CALL_EXPR from the above
>>> using build_new_function_call -> build_over_call which calls mark_used
>>> -> maybe_instantiate_noexcept -> type_dependent_expression_p.
>>>
>>> There, the innermost template arguments are non-dependent (<int>), but
>>> the fntype is dependent -- the return type is a TYPENAME_TYPE, and
>>> since we have no DECL_CONTEXT, this check holds:
>>>
>>>     /* Otherwise, if the function decl isn't from a dependent scope, it can't be
>>>        type-dependent.  Checking this is important for functions with auto return
>>>        type, which looks like a dependent type.  */
>>>     if (TREE_CODE (expression) == FUNCTION_DECL
>>>         && !(DECL_CLASS_SCOPE_P (expression)
>>>              && dependent_type_p (DECL_CONTEXT (expression)))
>>>
>>> whereupon we ICE.
>>>
>>> Experiments with setting DECL_CONTEXT didn't pan out.
>>
>> In c8 of the PR it looks like you were using the class itself as
>> DECL_CONTEXT; the quote above says that the right context is the enclosing
>> scope of the class.
> 
> Sadly, using CP_TYPE_CONTEXT (type) would result in a crash in
> retrieve_specialization:
> 
>    /* There should be as many levels of arguments as there are
>       levels of parameters.  */
>    gcc_assert (TMPL_ARGS_DEPTH (args)
>                == (TREE_CODE (tmpl) == TEMPLATE_DECL
>                    ? TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (tmpl))
>                    : template_class_depth (DECL_CONTEXT (tmpl))));

Yeah, probably simpler not to bother.

>>> So perhaps we
>>> just want to skip the assert for deduction guides, because they are
>>> a little special.  Better ideas solicited.
>>
>> In c3 you mention that one of the variants broke with r269093; this is
>> because my change to check CLASSTYPE_TEMPLATE_INSTANTIATION is false for the
>> template pattern itself (E<Z>).
> 
> And the original test started with my r11-1713 because using TREE_TYPE
> directly instead of decltype (which is a non-deduced context) means we
> can deduced from the argument.
>   
>> But I think probably the right answer is to defer this deduction until the
>> enclosing scope is non-dependent, i.e. (untested)
> 
> Thanks.  That mostly works, except the new class-deduction-aggr[89].C
> tests.  Consider 8:
> 
> namespace N {
> template <typename, typename> struct S {
>    template <typename T, typename U> S(T, U);
> };
> } // namespace N
> template <int> struct E {
>    template <typename T> struct G { T t; };
>    void fn() { G{N::S<char, int>{'a', 1}}; }
> };
> 
> void
> g ()
> {
>    E<1> e;
>    e.fn ();
> }
> 
> With your patch, when in do_class_deduction when processing_template_decl,
> we just return.  When we call do_class_deduction again when p_t_d is 0,
> maybe_aggr_guide returns early here:
> 
>    if (!CP_AGGREGATE_TYPE_P (type))
>      return NULL_TREE
> 
> because G is not complete (and rightly so, we didn't instantiate it).  So
> we aren't able to deduce the template parameters.  I'm not sure if I should
> pursue this direction further.  :(

I think so; we just need to test CP_AGGREGATE_TYPE_P on the original 
template pattern instead of the instantiation E<1>::G.

Jason
Marek Polacek March 1, 2021, 7:54 p.m. UTC | #5
On Thu, Feb 25, 2021 at 10:45:29PM -0500, Jason Merrill via Gcc-patches wrote:
> On 2/25/21 5:41 PM, Marek Polacek wrote:
> > On Thu, Feb 25, 2021 at 10:59:49AM -0500, Jason Merrill wrote:
> > > On 2/12/21 6:12 PM, Marek Polacek wrote:
> > > > We represent deduction guides with FUNCTION_DECLs, but they are built
> > > > without DECL_CONTEXT
> > > 
> > > Hmm, that seems wrong: "A deduction-guide shall be declared in the
> > > same scope as the corresponding class template and, for a member class
> > > template, with the same access."  But it probably isn't necessary to change
> > > this:
> > > 
> > > > leading to an ICE in type_dependent_expression_p
> > > > on the assert that the type of a function template with no dependent
> > > > (innermost!) template arguments must be non-dependent.  Consider the
> > > > attached class-deduction79.C: we create a deduction guide:
> > > > 
> > > >     template<class T> G(T)-> E<Z>::G<T>
> > > > 
> > > > we deduce T and create a partial instantiation:
> > > > 
> > > >     G(T) -> E<Z>::G<T> [with T = int]
> > > > 
> > > > And then do_class_deduction wants to create a CALL_EXPR from the above
> > > > using build_new_function_call -> build_over_call which calls mark_used
> > > > -> maybe_instantiate_noexcept -> type_dependent_expression_p.
> > > > 
> > > > There, the innermost template arguments are non-dependent (<int>), but
> > > > the fntype is dependent -- the return type is a TYPENAME_TYPE, and
> > > > since we have no DECL_CONTEXT, this check holds:
> > > > 
> > > >     /* Otherwise, if the function decl isn't from a dependent scope, it can't be
> > > >        type-dependent.  Checking this is important for functions with auto return
> > > >        type, which looks like a dependent type.  */
> > > >     if (TREE_CODE (expression) == FUNCTION_DECL
> > > >         && !(DECL_CLASS_SCOPE_P (expression)
> > > >              && dependent_type_p (DECL_CONTEXT (expression)))
> > > > 
> > > > whereupon we ICE.
> > > > 
> > > > Experiments with setting DECL_CONTEXT didn't pan out.
> > > 
> > > In c8 of the PR it looks like you were using the class itself as
> > > DECL_CONTEXT; the quote above says that the right context is the enclosing
> > > scope of the class.
> > 
> > Sadly, using CP_TYPE_CONTEXT (type) would result in a crash in
> > retrieve_specialization:
> > 
> >    /* There should be as many levels of arguments as there are
> >       levels of parameters.  */
> >    gcc_assert (TMPL_ARGS_DEPTH (args)
> >                == (TREE_CODE (tmpl) == TEMPLATE_DECL
> >                    ? TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (tmpl))
> >                    : template_class_depth (DECL_CONTEXT (tmpl))));
> 
> Yeah, probably simpler not to bother.
> 
> > > > So perhaps we
> > > > just want to skip the assert for deduction guides, because they are
> > > > a little special.  Better ideas solicited.
> > > 
> > > In c3 you mention that one of the variants broke with r269093; this is
> > > because my change to check CLASSTYPE_TEMPLATE_INSTANTIATION is false for the
> > > template pattern itself (E<Z>).
> > 
> > And the original test started with my r11-1713 because using TREE_TYPE
> > directly instead of decltype (which is a non-deduced context) means we
> > can deduced from the argument.
> > > But I think probably the right answer is to defer this deduction until the
> > > enclosing scope is non-dependent, i.e. (untested)
> > 
> > Thanks.  That mostly works, except the new class-deduction-aggr[89].C
> > tests.  Consider 8:
> > 
> > namespace N {
> > template <typename, typename> struct S {
> >    template <typename T, typename U> S(T, U);
> > };
> > } // namespace N
> > template <int> struct E {
> >    template <typename T> struct G { T t; };
> >    void fn() { G{N::S<char, int>{'a', 1}}; }
> > };
> > 
> > void
> > g ()
> > {
> >    E<1> e;
> >    e.fn ();
> > }
> > 
> > With your patch, when in do_class_deduction when processing_template_decl,
> > we just return.  When we call do_class_deduction again when p_t_d is 0,
> > maybe_aggr_guide returns early here:
> > 
> >    if (!CP_AGGREGATE_TYPE_P (type))
> >      return NULL_TREE
> > 
> > because G is not complete (and rightly so, we didn't instantiate it).  So
> > we aren't able to deduce the template parameters.  I'm not sure if I should
> > pursue this direction further.  :(
> 
> I think so; we just need to test CP_AGGREGATE_TYPE_P on the original
> template pattern instead of the instantiation E<1>::G.

I'm sorry, I've got stuck again.

Yes, using the original template pattern helps us get past the
CP_AGGREGATE_TYPE_P check.

However, using TREE_TYPE (DECL_TI_TEMPLATE (tmpl)) as the type of the deduction guide
means the guide will be "template<class T> G(T)-> E<<anonymous> >::G<T>" which
results in

  class-deduction-aggr8.C:11:15: error: invalid use of dependent type 'typename E<<anonymous> >::G<N::S<char, int> >'

which makes sense I guess: when we defer building up the guide until
we've instantiated E<1>, finding the dependent type E<> is not expected.

But creating the guide with "struct E<1>::G<T>" as its type seems
wrong; I'm not even sure if a guide like

  template<class T> G(T)-> E<1>::G<T>

makes sense.  In any case the deduction fails (when we call
build_new_function_call in do_class_deduction), because we've got
a mismatch: the template parameter T has level 1, but the template
function parameter has level 2.

Marek
Jason Merrill March 1, 2021, 8:08 p.m. UTC | #6
On 3/1/21 2:54 PM, Marek Polacek wrote:
> On Thu, Feb 25, 2021 at 10:45:29PM -0500, Jason Merrill via Gcc-patches wrote:
>> On 2/25/21 5:41 PM, Marek Polacek wrote:
>>> On Thu, Feb 25, 2021 at 10:59:49AM -0500, Jason Merrill wrote:
>>>> On 2/12/21 6:12 PM, Marek Polacek wrote:
>>>>> We represent deduction guides with FUNCTION_DECLs, but they are built
>>>>> without DECL_CONTEXT
>>>>
>>>> Hmm, that seems wrong: "A deduction-guide shall be declared in the
>>>> same scope as the corresponding class template and, for a member class
>>>> template, with the same access."  But it probably isn't necessary to change
>>>> this:
>>>>
>>>>> leading to an ICE in type_dependent_expression_p
>>>>> on the assert that the type of a function template with no dependent
>>>>> (innermost!) template arguments must be non-dependent.  Consider the
>>>>> attached class-deduction79.C: we create a deduction guide:
>>>>>
>>>>>      template<class T> G(T)-> E<Z>::G<T>
>>>>>
>>>>> we deduce T and create a partial instantiation:
>>>>>
>>>>>      G(T) -> E<Z>::G<T> [with T = int]
>>>>>
>>>>> And then do_class_deduction wants to create a CALL_EXPR from the above
>>>>> using build_new_function_call -> build_over_call which calls mark_used
>>>>> -> maybe_instantiate_noexcept -> type_dependent_expression_p.
>>>>>
>>>>> There, the innermost template arguments are non-dependent (<int>), but
>>>>> the fntype is dependent -- the return type is a TYPENAME_TYPE, and
>>>>> since we have no DECL_CONTEXT, this check holds:
>>>>>
>>>>>      /* Otherwise, if the function decl isn't from a dependent scope, it can't be
>>>>>         type-dependent.  Checking this is important for functions with auto return
>>>>>         type, which looks like a dependent type.  */
>>>>>      if (TREE_CODE (expression) == FUNCTION_DECL
>>>>>          && !(DECL_CLASS_SCOPE_P (expression)
>>>>>               && dependent_type_p (DECL_CONTEXT (expression)))
>>>>>
>>>>> whereupon we ICE.
>>>>>
>>>>> Experiments with setting DECL_CONTEXT didn't pan out.
>>>>
>>>> In c8 of the PR it looks like you were using the class itself as
>>>> DECL_CONTEXT; the quote above says that the right context is the enclosing
>>>> scope of the class.
>>>
>>> Sadly, using CP_TYPE_CONTEXT (type) would result in a crash in
>>> retrieve_specialization:
>>>
>>>     /* There should be as many levels of arguments as there are
>>>        levels of parameters.  */
>>>     gcc_assert (TMPL_ARGS_DEPTH (args)
>>>                 == (TREE_CODE (tmpl) == TEMPLATE_DECL
>>>                     ? TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (tmpl))
>>>                     : template_class_depth (DECL_CONTEXT (tmpl))));
>>
>> Yeah, probably simpler not to bother.
>>
>>>>> So perhaps we
>>>>> just want to skip the assert for deduction guides, because they are
>>>>> a little special.  Better ideas solicited.
>>>>
>>>> In c3 you mention that one of the variants broke with r269093; this is
>>>> because my change to check CLASSTYPE_TEMPLATE_INSTANTIATION is false for the
>>>> template pattern itself (E<Z>).
>>>
>>> And the original test started with my r11-1713 because using TREE_TYPE
>>> directly instead of decltype (which is a non-deduced context) means we
>>> can deduced from the argument.
>>>> But I think probably the right answer is to defer this deduction until the
>>>> enclosing scope is non-dependent, i.e. (untested)
>>>
>>> Thanks.  That mostly works, except the new class-deduction-aggr[89].C
>>> tests.  Consider 8:
>>>
>>> namespace N {
>>> template <typename, typename> struct S {
>>>     template <typename T, typename U> S(T, U);
>>> };
>>> } // namespace N
>>> template <int> struct E {
>>>     template <typename T> struct G { T t; };
>>>     void fn() { G{N::S<char, int>{'a', 1}}; }
>>> };
>>>
>>> void
>>> g ()
>>> {
>>>     E<1> e;
>>>     e.fn ();
>>> }
>>>
>>> With your patch, when in do_class_deduction when processing_template_decl,
>>> we just return.  When we call do_class_deduction again when p_t_d is 0,
>>> maybe_aggr_guide returns early here:
>>>
>>>     if (!CP_AGGREGATE_TYPE_P (type))
>>>       return NULL_TREE
>>>
>>> because G is not complete (and rightly so, we didn't instantiate it).  So
>>> we aren't able to deduce the template parameters.  I'm not sure if I should
>>> pursue this direction further.  :(
>>
>> I think so; we just need to test CP_AGGREGATE_TYPE_P on the original
>> template pattern instead of the instantiation E<1>::G.
> 
> I'm sorry, I've got stuck again.
> 
> Yes, using the original template pattern helps us get past the
> CP_AGGREGATE_TYPE_P check.
> 
> However, using TREE_TYPE (DECL_TI_TEMPLATE (tmpl)) as the type of the deduction guide
> means the guide will be "template<class T> G(T)-> E<<anonymous> >::G<T>" which
> results in
> 
>    class-deduction-aggr8.C:11:15: error: invalid use of dependent type 'typename E<<anonymous> >::G<N::S<char, int> >'
> 
> which makes sense I guess: when we defer building up the guide until
> we've instantiated E<1>, finding the dependent type E<> is not expected.

Yeah, I was only thinking to use the pattern for the aggregate check.

> But creating the guide with "struct E<1>::G<T>" as its type seems
> wrong; I'm not even sure if a guide like
> 
>    template<class T> G(T)-> E<1>::G<T>
> 
> makes sense.

It looks fine to me.

> In any case the deduction fails (when we call
> build_new_function_call in do_class_deduction), because we've got
> a mismatch: the template parameter T has level 1, but the template
> function parameter has level 2.

Sure, because E<1>::G<T> has been partially instantiated, so the T has 
been reduced from level 2 to 1.

You'll need to do a similar partial instantiation for building the 
deduction guide, either as part of the deduction guide rewriting or on 
the constructor before rewriting.

It might also work to do something tricky like giving the E template 
parameter a default argument of 1, but that seems like it would need 
more invention.

Jason
Marek Polacek March 2, 2021, 12:59 a.m. UTC | #7
On Mon, Mar 01, 2021 at 03:08:58PM -0500, Jason Merrill wrote:
> On 3/1/21 2:54 PM, Marek Polacek wrote:
> > On Thu, Feb 25, 2021 at 10:45:29PM -0500, Jason Merrill via Gcc-patches wrote:
> > > On 2/25/21 5:41 PM, Marek Polacek wrote:
> > > > On Thu, Feb 25, 2021 at 10:59:49AM -0500, Jason Merrill wrote:
> > > > > On 2/12/21 6:12 PM, Marek Polacek wrote:
> > > > > > We represent deduction guides with FUNCTION_DECLs, but they are built
> > > > > > without DECL_CONTEXT
> > > > > 
> > > > > Hmm, that seems wrong: "A deduction-guide shall be declared in the
> > > > > same scope as the corresponding class template and, for a member class
> > > > > template, with the same access."  But it probably isn't necessary to change
> > > > > this:
> > > > > 
> > > > > > leading to an ICE in type_dependent_expression_p
> > > > > > on the assert that the type of a function template with no dependent
> > > > > > (innermost!) template arguments must be non-dependent.  Consider the
> > > > > > attached class-deduction79.C: we create a deduction guide:
> > > > > > 
> > > > > >      template<class T> G(T)-> E<Z>::G<T>
> > > > > > 
> > > > > > we deduce T and create a partial instantiation:
> > > > > > 
> > > > > >      G(T) -> E<Z>::G<T> [with T = int]
> > > > > > 
> > > > > > And then do_class_deduction wants to create a CALL_EXPR from the above
> > > > > > using build_new_function_call -> build_over_call which calls mark_used
> > > > > > -> maybe_instantiate_noexcept -> type_dependent_expression_p.
> > > > > > 
> > > > > > There, the innermost template arguments are non-dependent (<int>), but
> > > > > > the fntype is dependent -- the return type is a TYPENAME_TYPE, and
> > > > > > since we have no DECL_CONTEXT, this check holds:
> > > > > > 
> > > > > >      /* Otherwise, if the function decl isn't from a dependent scope, it can't be
> > > > > >         type-dependent.  Checking this is important for functions with auto return
> > > > > >         type, which looks like a dependent type.  */
> > > > > >      if (TREE_CODE (expression) == FUNCTION_DECL
> > > > > >          && !(DECL_CLASS_SCOPE_P (expression)
> > > > > >               && dependent_type_p (DECL_CONTEXT (expression)))
> > > > > > 
> > > > > > whereupon we ICE.
> > > > > > 
> > > > > > Experiments with setting DECL_CONTEXT didn't pan out.
> > > > > 
> > > > > In c8 of the PR it looks like you were using the class itself as
> > > > > DECL_CONTEXT; the quote above says that the right context is the enclosing
> > > > > scope of the class.
> > > > 
> > > > Sadly, using CP_TYPE_CONTEXT (type) would result in a crash in
> > > > retrieve_specialization:
> > > > 
> > > >     /* There should be as many levels of arguments as there are
> > > >        levels of parameters.  */
> > > >     gcc_assert (TMPL_ARGS_DEPTH (args)
> > > >                 == (TREE_CODE (tmpl) == TEMPLATE_DECL
> > > >                     ? TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (tmpl))
> > > >                     : template_class_depth (DECL_CONTEXT (tmpl))));
> > > 
> > > Yeah, probably simpler not to bother.
> > > 
> > > > > > So perhaps we
> > > > > > just want to skip the assert for deduction guides, because they are
> > > > > > a little special.  Better ideas solicited.
> > > > > 
> > > > > In c3 you mention that one of the variants broke with r269093; this is
> > > > > because my change to check CLASSTYPE_TEMPLATE_INSTANTIATION is false for the
> > > > > template pattern itself (E<Z>).
> > > > 
> > > > And the original test started with my r11-1713 because using TREE_TYPE
> > > > directly instead of decltype (which is a non-deduced context) means we
> > > > can deduced from the argument.
> > > > > But I think probably the right answer is to defer this deduction until the
> > > > > enclosing scope is non-dependent, i.e. (untested)
> > > > 
> > > > Thanks.  That mostly works, except the new class-deduction-aggr[89].C
> > > > tests.  Consider 8:
> > > > 
> > > > namespace N {
> > > > template <typename, typename> struct S {
> > > >     template <typename T, typename U> S(T, U);
> > > > };
> > > > } // namespace N
> > > > template <int> struct E {
> > > >     template <typename T> struct G { T t; };
> > > >     void fn() { G{N::S<char, int>{'a', 1}}; }
> > > > };
> > > > 
> > > > void
> > > > g ()
> > > > {
> > > >     E<1> e;
> > > >     e.fn ();
> > > > }
> > > > 
> > > > With your patch, when in do_class_deduction when processing_template_decl,
> > > > we just return.  When we call do_class_deduction again when p_t_d is 0,
> > > > maybe_aggr_guide returns early here:
> > > > 
> > > >     if (!CP_AGGREGATE_TYPE_P (type))
> > > >       return NULL_TREE
> > > > 
> > > > because G is not complete (and rightly so, we didn't instantiate it).  So
> > > > we aren't able to deduce the template parameters.  I'm not sure if I should
> > > > pursue this direction further.  :(
> > > 
> > > I think so; we just need to test CP_AGGREGATE_TYPE_P on the original
> > > template pattern instead of the instantiation E<1>::G.
> > 
> > I'm sorry, I've got stuck again.
> > 
> > Yes, using the original template pattern helps us get past the
> > CP_AGGREGATE_TYPE_P check.
> > 
> > However, using TREE_TYPE (DECL_TI_TEMPLATE (tmpl)) as the type of the deduction guide
> > means the guide will be "template<class T> G(T)-> E<<anonymous> >::G<T>" which
> > results in
> > 
> >    class-deduction-aggr8.C:11:15: error: invalid use of dependent type 'typename E<<anonymous> >::G<N::S<char, int> >'
> > 
> > which makes sense I guess: when we defer building up the guide until
> > we've instantiated E<1>, finding the dependent type E<> is not expected.
> 
> Yeah, I was only thinking to use the pattern for the aggregate check.

Ack.  Though I think I also have to use the pattern here:

  init = reshape_init (type, init, complain);

otherwise reshape_init returns a TARGET_EXPR and we immediately
crash in collect_ctor_idx_types because that only expects a CONSTRUCTOR. 
And what we need to get is the type T -- of the constructor's index.
 
> > But creating the guide with "struct E<1>::G<T>" as its type seems
> > wrong; I'm not even sure if a guide like
> > 
> >    template<class T> G(T)-> E<1>::G<T>
> > 
> > makes sense.
> 
> It looks fine to me.
> 
> > In any case the deduction fails (when we call
> > build_new_function_call in do_class_deduction), because we've got
> > a mismatch: the template parameter T has level 1, but the template
> > function parameter has level 2.
> 
> Sure, because E<1>::G<T> has been partially instantiated, so the T has been
> reduced from level 2 to 1.

Right.
 
> You'll need to do a similar partial instantiation for building the deduction
> guide, either as part of the deduction guide rewriting or on the constructor
> before rewriting.

So I've tried.  I can't actually tsubst the constructor itself, because it
at this point contains an AGGR_INIT_EXPR, which tsubst* can't handle.  But
what I could do is

  parms = tsubst (parms, DECL_TI_ARGS (tmpl), complain, init);

just after the call to collect_ctor_idx_types.  After all, this is what
we care about and create the function template parameters from.  So now
T's level is reduced to 1, and the guide we create is

  template<class T> G(T)-> E<1>::G<T>

This guide is then chosen in do_class_deduction -> build_new_function_call,
but we crash in fn_type_unification -> instantiate_template (after we've
deduced T to N::S<char, int>) in retrieve_specialization:

  gcc_assert (TMPL_ARGS_DEPTH (args)
              == (TREE_CODE (tmpl) == TEMPLATE_DECL
                  ? TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (tmpl))
                  : template_class_depth (DECL_CONTEXT (tmpl))));

args is <1, S> (depth 2), tmpl is our deduction guide, and
DECL_TEMPLATE_PARMS (tmpl) is [1 T] (depth 1).

:/

> It might also work to do something tricky like giving the E template
> parameter a default argument of 1, but that seems like it would need more
> invention.

I haven't tried this, but I'm not sure if it'd avoid the problem above.

Marek
Jason Merrill March 2, 2021, 2:29 a.m. UTC | #8
On 3/1/21 7:59 PM, Marek Polacek wrote:
> On Mon, Mar 01, 2021 at 03:08:58PM -0500, Jason Merrill wrote:
>> On 3/1/21 2:54 PM, Marek Polacek wrote:
>>> On Thu, Feb 25, 2021 at 10:45:29PM -0500, Jason Merrill via Gcc-patches wrote:
>>>> On 2/25/21 5:41 PM, Marek Polacek wrote:
>>>>> On Thu, Feb 25, 2021 at 10:59:49AM -0500, Jason Merrill wrote:
>>>>>> On 2/12/21 6:12 PM, Marek Polacek wrote:
>>>>>>> We represent deduction guides with FUNCTION_DECLs, but they are built
>>>>>>> without DECL_CONTEXT
>>>>>>
>>>>>> Hmm, that seems wrong: "A deduction-guide shall be declared in the
>>>>>> same scope as the corresponding class template and, for a member class
>>>>>> template, with the same access."  But it probably isn't necessary to change
>>>>>> this:
>>>>>>
>>>>>>> leading to an ICE in type_dependent_expression_p
>>>>>>> on the assert that the type of a function template with no dependent
>>>>>>> (innermost!) template arguments must be non-dependent.  Consider the
>>>>>>> attached class-deduction79.C: we create a deduction guide:
>>>>>>>
>>>>>>>       template<class T> G(T)-> E<Z>::G<T>
>>>>>>>
>>>>>>> we deduce T and create a partial instantiation:
>>>>>>>
>>>>>>>       G(T) -> E<Z>::G<T> [with T = int]
>>>>>>>
>>>>>>> And then do_class_deduction wants to create a CALL_EXPR from the above
>>>>>>> using build_new_function_call -> build_over_call which calls mark_used
>>>>>>> -> maybe_instantiate_noexcept -> type_dependent_expression_p.
>>>>>>>
>>>>>>> There, the innermost template arguments are non-dependent (<int>), but
>>>>>>> the fntype is dependent -- the return type is a TYPENAME_TYPE, and
>>>>>>> since we have no DECL_CONTEXT, this check holds:
>>>>>>>
>>>>>>>       /* Otherwise, if the function decl isn't from a dependent scope, it can't be
>>>>>>>          type-dependent.  Checking this is important for functions with auto return
>>>>>>>          type, which looks like a dependent type.  */
>>>>>>>       if (TREE_CODE (expression) == FUNCTION_DECL
>>>>>>>           && !(DECL_CLASS_SCOPE_P (expression)
>>>>>>>                && dependent_type_p (DECL_CONTEXT (expression)))
>>>>>>>
>>>>>>> whereupon we ICE.
>>>>>>>
>>>>>>> Experiments with setting DECL_CONTEXT didn't pan out.
>>>>>>
>>>>>> In c8 of the PR it looks like you were using the class itself as
>>>>>> DECL_CONTEXT; the quote above says that the right context is the enclosing
>>>>>> scope of the class.
>>>>>
>>>>> Sadly, using CP_TYPE_CONTEXT (type) would result in a crash in
>>>>> retrieve_specialization:
>>>>>
>>>>>      /* There should be as many levels of arguments as there are
>>>>>         levels of parameters.  */
>>>>>      gcc_assert (TMPL_ARGS_DEPTH (args)
>>>>>                  == (TREE_CODE (tmpl) == TEMPLATE_DECL
>>>>>                      ? TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (tmpl))
>>>>>                      : template_class_depth (DECL_CONTEXT (tmpl))));
>>>>
>>>> Yeah, probably simpler not to bother.
>>>>
>>>>>>> So perhaps we
>>>>>>> just want to skip the assert for deduction guides, because they are
>>>>>>> a little special.  Better ideas solicited.
>>>>>>
>>>>>> In c3 you mention that one of the variants broke with r269093; this is
>>>>>> because my change to check CLASSTYPE_TEMPLATE_INSTANTIATION is false for the
>>>>>> template pattern itself (E<Z>).
>>>>>
>>>>> And the original test started with my r11-1713 because using TREE_TYPE
>>>>> directly instead of decltype (which is a non-deduced context) means we
>>>>> can deduced from the argument.
>>>>>> But I think probably the right answer is to defer this deduction until the
>>>>>> enclosing scope is non-dependent, i.e. (untested)
>>>>>
>>>>> Thanks.  That mostly works, except the new class-deduction-aggr[89].C
>>>>> tests.  Consider 8:
>>>>>
>>>>> namespace N {
>>>>> template <typename, typename> struct S {
>>>>>      template <typename T, typename U> S(T, U);
>>>>> };
>>>>> } // namespace N
>>>>> template <int> struct E {
>>>>>      template <typename T> struct G { T t; };
>>>>>      void fn() { G{N::S<char, int>{'a', 1}}; }
>>>>> };
>>>>>
>>>>> void
>>>>> g ()
>>>>> {
>>>>>      E<1> e;
>>>>>      e.fn ();
>>>>> }
>>>>>
>>>>> With your patch, when in do_class_deduction when processing_template_decl,
>>>>> we just return.  When we call do_class_deduction again when p_t_d is 0,
>>>>> maybe_aggr_guide returns early here:
>>>>>
>>>>>      if (!CP_AGGREGATE_TYPE_P (type))
>>>>>        return NULL_TREE
>>>>>
>>>>> because G is not complete (and rightly so, we didn't instantiate it).  So
>>>>> we aren't able to deduce the template parameters.  I'm not sure if I should
>>>>> pursue this direction further.  :(
>>>>
>>>> I think so; we just need to test CP_AGGREGATE_TYPE_P on the original
>>>> template pattern instead of the instantiation E<1>::G.
>>>
>>> I'm sorry, I've got stuck again.
>>>
>>> Yes, using the original template pattern helps us get past the
>>> CP_AGGREGATE_TYPE_P check.
>>>
>>> However, using TREE_TYPE (DECL_TI_TEMPLATE (tmpl)) as the type of the deduction guide
>>> means the guide will be "template<class T> G(T)-> E<<anonymous> >::G<T>" which
>>> results in
>>>
>>>     class-deduction-aggr8.C:11:15: error: invalid use of dependent type 'typename E<<anonymous> >::G<N::S<char, int> >'
>>>
>>> which makes sense I guess: when we defer building up the guide until
>>> we've instantiated E<1>, finding the dependent type E<> is not expected.
>>
>> Yeah, I was only thinking to use the pattern for the aggregate check.
> 
> Ack.  Though I think I also have to use the pattern here:
> 
>    init = reshape_init (type, init, complain);
> 
> otherwise reshape_init returns a TARGET_EXPR and we immediately
> crash in collect_ctor_idx_types because that only expects a CONSTRUCTOR.
> And what we need to get is the type T -- of the constructor's index.
>   
>>> But creating the guide with "struct E<1>::G<T>" as its type seems
>>> wrong; I'm not even sure if a guide like
>>>
>>>     template<class T> G(T)-> E<1>::G<T>
>>>
>>> makes sense.
>>
>> It looks fine to me.
>>
>>> In any case the deduction fails (when we call
>>> build_new_function_call in do_class_deduction), because we've got
>>> a mismatch: the template parameter T has level 1, but the template
>>> function parameter has level 2.
>>
>> Sure, because E<1>::G<T> has been partially instantiated, so the T has been
>> reduced from level 2 to 1.
> 
> Right.
>   
>> You'll need to do a similar partial instantiation for building the deduction
>> guide, either as part of the deduction guide rewriting or on the constructor
>> before rewriting.
> 
> So I've tried.  I can't actually tsubst the constructor itself, because it
> at this point contains an AGGR_INIT_EXPR, which tsubst* can't handle.  But
> what I could do is
> 
>    parms = tsubst (parms, DECL_TI_ARGS (tmpl), complain, init);
> 
> just after the call to collect_ctor_idx_types.  After all, this is what
> we care about and create the function template parameters from.  So now
> T's level is reduced to 1, and the guide we create is
> 
>    template<class T> G(T)-> E<1>::G<T>
> 
> This guide is then chosen in do_class_deduction -> build_new_function_call,
> but we crash in fn_type_unification -> instantiate_template (after we've
> deduced T to N::S<char, int>) in retrieve_specialization:
> 
>    gcc_assert (TMPL_ARGS_DEPTH (args)
>                == (TREE_CODE (tmpl) == TEMPLATE_DECL
>                    ? TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (tmpl))
>                    : template_class_depth (DECL_CONTEXT (tmpl))));
> 
> args is <1, S> (depth 2), tmpl is our deduction guide, and
> DECL_TEMPLATE_PARMS (tmpl) is [1 T] (depth 1).

I'd think args should only be S (depth 1).

> :/
> 
>> It might also work to do something tricky like giving the E template
>> parameter a default argument of 1, but that seems like it would need more
>> invention.
> 
> I haven't tried this, but I'm not sure if it'd avoid the problem above.
> 
> Marek
>
Marek Polacek March 2, 2021, 9:51 p.m. UTC | #9
On Mon, Mar 01, 2021 at 09:29:19PM -0500, Jason Merrill via Gcc-patches wrote:
> On 3/1/21 7:59 PM, Marek Polacek wrote:
> > On Mon, Mar 01, 2021 at 03:08:58PM -0500, Jason Merrill wrote:
> > > On 3/1/21 2:54 PM, Marek Polacek wrote:
> > > > On Thu, Feb 25, 2021 at 10:45:29PM -0500, Jason Merrill via Gcc-patches wrote:
> > > > > On 2/25/21 5:41 PM, Marek Polacek wrote:
> > > > > > On Thu, Feb 25, 2021 at 10:59:49AM -0500, Jason Merrill wrote:
> > > > > > > On 2/12/21 6:12 PM, Marek Polacek wrote:
> > > > > > > > We represent deduction guides with FUNCTION_DECLs, but they are built
> > > > > > > > without DECL_CONTEXT
> > > > > > > 
> > > > > > > Hmm, that seems wrong: "A deduction-guide shall be declared in the
> > > > > > > same scope as the corresponding class template and, for a member class
> > > > > > > template, with the same access."  But it probably isn't necessary to change
> > > > > > > this:
> > > > > > > 
> > > > > > > > leading to an ICE in type_dependent_expression_p
> > > > > > > > on the assert that the type of a function template with no dependent
> > > > > > > > (innermost!) template arguments must be non-dependent.  Consider the
> > > > > > > > attached class-deduction79.C: we create a deduction guide:
> > > > > > > > 
> > > > > > > >       template<class T> G(T)-> E<Z>::G<T>
> > > > > > > > 
> > > > > > > > we deduce T and create a partial instantiation:
> > > > > > > > 
> > > > > > > >       G(T) -> E<Z>::G<T> [with T = int]
> > > > > > > > 
> > > > > > > > And then do_class_deduction wants to create a CALL_EXPR from the above
> > > > > > > > using build_new_function_call -> build_over_call which calls mark_used
> > > > > > > > -> maybe_instantiate_noexcept -> type_dependent_expression_p.
> > > > > > > > 
> > > > > > > > There, the innermost template arguments are non-dependent (<int>), but
> > > > > > > > the fntype is dependent -- the return type is a TYPENAME_TYPE, and
> > > > > > > > since we have no DECL_CONTEXT, this check holds:
> > > > > > > > 
> > > > > > > >       /* Otherwise, if the function decl isn't from a dependent scope, it can't be
> > > > > > > >          type-dependent.  Checking this is important for functions with auto return
> > > > > > > >          type, which looks like a dependent type.  */
> > > > > > > >       if (TREE_CODE (expression) == FUNCTION_DECL
> > > > > > > >           && !(DECL_CLASS_SCOPE_P (expression)
> > > > > > > >                && dependent_type_p (DECL_CONTEXT (expression)))
> > > > > > > > 
> > > > > > > > whereupon we ICE.
> > > > > > > > 
> > > > > > > > Experiments with setting DECL_CONTEXT didn't pan out.
> > > > > > > 
> > > > > > > In c8 of the PR it looks like you were using the class itself as
> > > > > > > DECL_CONTEXT; the quote above says that the right context is the enclosing
> > > > > > > scope of the class.
> > > > > > 
> > > > > > Sadly, using CP_TYPE_CONTEXT (type) would result in a crash in
> > > > > > retrieve_specialization:
> > > > > > 
> > > > > >      /* There should be as many levels of arguments as there are
> > > > > >         levels of parameters.  */
> > > > > >      gcc_assert (TMPL_ARGS_DEPTH (args)
> > > > > >                  == (TREE_CODE (tmpl) == TEMPLATE_DECL
> > > > > >                      ? TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (tmpl))
> > > > > >                      : template_class_depth (DECL_CONTEXT (tmpl))));
> > > > > 
> > > > > Yeah, probably simpler not to bother.
> > > > > 
> > > > > > > > So perhaps we
> > > > > > > > just want to skip the assert for deduction guides, because they are
> > > > > > > > a little special.  Better ideas solicited.
> > > > > > > 
> > > > > > > In c3 you mention that one of the variants broke with r269093; this is
> > > > > > > because my change to check CLASSTYPE_TEMPLATE_INSTANTIATION is false for the
> > > > > > > template pattern itself (E<Z>).
> > > > > > 
> > > > > > And the original test started with my r11-1713 because using TREE_TYPE
> > > > > > directly instead of decltype (which is a non-deduced context) means we
> > > > > > can deduced from the argument.
> > > > > > > But I think probably the right answer is to defer this deduction until the
> > > > > > > enclosing scope is non-dependent, i.e. (untested)
> > > > > > 
> > > > > > Thanks.  That mostly works, except the new class-deduction-aggr[89].C
> > > > > > tests.  Consider 8:
> > > > > > 
> > > > > > namespace N {
> > > > > > template <typename, typename> struct S {
> > > > > >      template <typename T, typename U> S(T, U);
> > > > > > };
> > > > > > } // namespace N
> > > > > > template <int> struct E {
> > > > > >      template <typename T> struct G { T t; };
> > > > > >      void fn() { G{N::S<char, int>{'a', 1}}; }
> > > > > > };
> > > > > > 
> > > > > > void
> > > > > > g ()
> > > > > > {
> > > > > >      E<1> e;
> > > > > >      e.fn ();
> > > > > > }
> > > > > > 
> > > > > > With your patch, when in do_class_deduction when processing_template_decl,
> > > > > > we just return.  When we call do_class_deduction again when p_t_d is 0,
> > > > > > maybe_aggr_guide returns early here:
> > > > > > 
> > > > > >      if (!CP_AGGREGATE_TYPE_P (type))
> > > > > >        return NULL_TREE
> > > > > > 
> > > > > > because G is not complete (and rightly so, we didn't instantiate it).  So
> > > > > > we aren't able to deduce the template parameters.  I'm not sure if I should
> > > > > > pursue this direction further.  :(
> > > > > 
> > > > > I think so; we just need to test CP_AGGREGATE_TYPE_P on the original
> > > > > template pattern instead of the instantiation E<1>::G.
> > > > 
> > > > I'm sorry, I've got stuck again.
> > > > 
> > > > Yes, using the original template pattern helps us get past the
> > > > CP_AGGREGATE_TYPE_P check.
> > > > 
> > > > However, using TREE_TYPE (DECL_TI_TEMPLATE (tmpl)) as the type of the deduction guide
> > > > means the guide will be "template<class T> G(T)-> E<<anonymous> >::G<T>" which
> > > > results in
> > > > 
> > > >     class-deduction-aggr8.C:11:15: error: invalid use of dependent type 'typename E<<anonymous> >::G<N::S<char, int> >'
> > > > 
> > > > which makes sense I guess: when we defer building up the guide until
> > > > we've instantiated E<1>, finding the dependent type E<> is not expected.
> > > 
> > > Yeah, I was only thinking to use the pattern for the aggregate check.
> > 
> > Ack.  Though I think I also have to use the pattern here:
> > 
> >    init = reshape_init (type, init, complain);
> > 
> > otherwise reshape_init returns a TARGET_EXPR and we immediately
> > crash in collect_ctor_idx_types because that only expects a CONSTRUCTOR.
> > And what we need to get is the type T -- of the constructor's index.
> > > > But creating the guide with "struct E<1>::G<T>" as its type seems
> > > > wrong; I'm not even sure if a guide like
> > > > 
> > > >     template<class T> G(T)-> E<1>::G<T>
> > > > 
> > > > makes sense.
> > > 
> > > It looks fine to me.
> > > 
> > > > In any case the deduction fails (when we call
> > > > build_new_function_call in do_class_deduction), because we've got
> > > > a mismatch: the template parameter T has level 1, but the template
> > > > function parameter has level 2.
> > > 
> > > Sure, because E<1>::G<T> has been partially instantiated, so the T has been
> > > reduced from level 2 to 1.
> > 
> > Right.
> > > You'll need to do a similar partial instantiation for building the deduction
> > > guide, either as part of the deduction guide rewriting or on the constructor
> > > before rewriting.
> > 
> > So I've tried.  I can't actually tsubst the constructor itself, because it
> > at this point contains an AGGR_INIT_EXPR, which tsubst* can't handle.  But
> > what I could do is
> > 
> >    parms = tsubst (parms, DECL_TI_ARGS (tmpl), complain, init);
> > 
> > just after the call to collect_ctor_idx_types.  After all, this is what
> > we care about and create the function template parameters from.  So now
> > T's level is reduced to 1, and the guide we create is
> > 
> >    template<class T> G(T)-> E<1>::G<T>
> > 
> > This guide is then chosen in do_class_deduction -> build_new_function_call,
> > but we crash in fn_type_unification -> instantiate_template (after we've
> > deduced T to N::S<char, int>) in retrieve_specialization:
> > 
> >    gcc_assert (TMPL_ARGS_DEPTH (args)
> >                == (TREE_CODE (tmpl) == TEMPLATE_DECL
> >                    ? TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (tmpl))
> >                    : template_class_depth (DECL_CONTEXT (tmpl))));
> > 
> > args is <1, S> (depth 2), tmpl is our deduction guide, and
> > DECL_TEMPLATE_PARMS (tmpl) is [1 T] (depth 1).
> 
> I'd think args should only be S (depth 1).

Ah!  I think I finally got a working patch.  Thanks for all the help!

Added class-deduction-aggr10.C to test the deduction in more nested classes.

Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
Additionally, I've built cmcstl2 and Boost 1.75.

-- >8 --
We represent deduction guides with FUNCTION_DECLs, but they are built
without DECL_CONTEXT, leading to an ICE in type_dependent_expression_p
on the assert that the type of a function template with no dependent
(innermost!) template arguments must be non-dependent.  Consider the
attached class-deduction79.C: we create a deduction guide:

  template<class T> G(T)-> E<Z>::G<T>

we deduce T and create a partial instantiation:

  G(T) -> E<Z>::G<T> [with T = int]

And then do_class_deduction wants to create a CALL_EXPR from the above
using build_new_function_call -> build_over_call which calls mark_used
-> maybe_instantiate_noexcept -> type_dependent_expression_p.

There, the innermost template arguments are non-dependent (<int>), but
the fntype is dependent -- the return type is a TYPENAME_TYPE, and
since we have no DECL_CONTEXT, this check holds:

  /* Otherwise, if the function decl isn't from a dependent scope, it can't be
     type-dependent.  Checking this is important for functions with auto return
     type, which looks like a dependent type.  */
  if (TREE_CODE (expression) == FUNCTION_DECL
      && !(DECL_CLASS_SCOPE_P (expression)
           && dependent_type_p (DECL_CONTEXT (expression)))

whereupon we ICE.

This patch fixes it by deferring the class deduction until the
enclosing scope is non-dependent.  build_deduction_guide and maybe_aggr_guide
needed a little tweaking to make the deduction work in a member
template.

Co-Authored-By: Jason Merrill <jason@redhat.com>

gcc/cp/ChangeLog:

	PR c++/97034
	PR c++/99009
	* pt.c (build_deduction_guide): Use INNERMOST_TEMPLATE_ARGS.
	(maybe_aggr_guide): Use the original template type where needed.  In
	a class member template, partially instantiate the result of
	collect_ctor_idx_types.
	(do_class_deduction): Defer the deduction until the enclosing
	scope is non-dependent.

gcc/testsuite/ChangeLog:

	PR c++/97034
	PR c++/99009
	* g++.dg/cpp1z/class-deduction81.C: New test.
	* g++.dg/cpp1z/class-deduction82.C: New test.
	* g++.dg/cpp2a/class-deduction-aggr8.C: New test.
	* g++.dg/cpp2a/class-deduction-aggr9.C: New test.
	* g++.dg/cpp2a/class-deduction-aggr10.C: New test.
---
 gcc/cp/pt.c                                   | 36 +++++++++++++++++--
 .../g++.dg/cpp1z/class-deduction81.C          | 20 +++++++++++
 .../g++.dg/cpp1z/class-deduction82.C          | 12 +++++++
 .../g++.dg/cpp2a/class-deduction-aggr10.C     | 21 +++++++++++
 .../g++.dg/cpp2a/class-deduction-aggr8.C      | 19 ++++++++++
 .../g++.dg/cpp2a/class-deduction-aggr9.C      | 18 ++++++++++
 6 files changed, 123 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction81.C
 create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction82.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr10.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr8.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr9.C

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 8d65a6e5bd2..a4686e0affb 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -28643,7 +28643,7 @@ build_deduction_guide (tree type, tree ctor, tree outer_args, tsubst_flags_t com
 
       tree ctmpl = CLASSTYPE_TI_TEMPLATE (type);
       tparms = DECL_TEMPLATE_PARMS (ctmpl);
-      targs = CLASSTYPE_TI_ARGS (type);
+      targs = INNERMOST_TEMPLATE_ARGS (CLASSTYPE_TI_ARGS (type));
       ci = NULL_TREE;
       fargs = NULL_TREE;
       loc = DECL_SOURCE_LOCATION (ctmpl);
@@ -28866,8 +28866,22 @@ maybe_aggr_guide (tree tmpl, tree init, vec<tree,va_gc> *args)
   if (init == NULL_TREE)
     return NULL_TREE;
 
+  /* We might be creating a guide for a class member template, e.g.,
+
+       template<typename U> struct A {
+	 template<typename T> struct B { T t; };
+       };
+
+     At this point, A will have been instantiated.  Below, we need to
+     use both A<U>::B<T> (TEMPLATE_TYPE) and A<int>::B<T> (TYPE) types.  */
+  const bool member_template_p
+    = (DECL_TEMPLATE_INFO (tmpl)
+       && DECL_MEMBER_TEMPLATE_P (DECL_TI_TEMPLATE (tmpl)));
   tree type = TREE_TYPE (tmpl);
-  if (!CP_AGGREGATE_TYPE_P (type))
+  tree template_type = (member_template_p
+			? TREE_TYPE (DECL_TI_TEMPLATE (tmpl))
+			: type);
+  if (!CP_AGGREGATE_TYPE_P (template_type))
     return NULL_TREE;
 
   /* No aggregate candidate for copy-initialization.  */
@@ -28884,10 +28898,21 @@ maybe_aggr_guide (tree tmpl, tree init, vec<tree,va_gc> *args)
   tree parms = NULL_TREE;
   if (BRACE_ENCLOSED_INITIALIZER_P (init))
     {
-      init = reshape_init (type, init, complain);
+      init = reshape_init (template_type, init, complain);
       if (init == error_mark_node)
 	return NULL_TREE;
       parms = collect_ctor_idx_types (init, parms);
+      /* If we're creating a deduction guide for a member class template,
+	 we've used the original template pattern type for the reshape_init
+	 above; this is done because we want PARMS to be a template parameter
+	 type, something that can be deduced when used as a function template
+	 parameter.  At this point the outer class template has already been
+	 partially instantiated (we deferred the deduction until the enclosing
+	 scope is non-dependent).  Therefore we have to partially instantiate
+	 PARMS, so that its template level is properly reduced and we don't get
+	 mismatches when deducing types using the guide with PARMS.  */
+      if (member_template_p)
+	parms = tsubst (parms, DECL_TI_ARGS (tmpl), complain, init);
     }
   else if (TREE_CODE (init) == TREE_LIST)
     {
@@ -29225,6 +29250,11 @@ do_class_deduction (tree ptype, tree tmpl, tree init,
   if (DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl))
     return ptype;
 
+  /* Wait until the enclosing scope is non-dependent.  */
+  if (DECL_CLASS_SCOPE_P (tmpl)
+      && dependent_type_p (DECL_CONTEXT (tmpl)))
+    return ptype;
+
   /* Initializing one placeholder from another.  */
   if (init && TREE_CODE (init) == TEMPLATE_PARM_INDEX
       && is_auto (TREE_TYPE (init))
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction81.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction81.C
new file mode 100644
index 00000000000..86a68248157
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction81.C
@@ -0,0 +1,20 @@
+// PR c++/97034
+// { dg-do compile { target c++17 } }
+
+template <typename Z>
+struct E {
+  template <typename T>
+  struct G {
+    T t;
+    G(T) { }
+  };
+
+  void fn() { G{1}; }
+};
+
+void
+g ()
+{
+  E<int> e;
+  e.fn ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction82.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction82.C
new file mode 100644
index 00000000000..238024c508f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction82.C
@@ -0,0 +1,12 @@
+// PR c++/99009
+// { dg-do compile { target c++17 } }
+
+template<typename> struct B {
+  B(int = A()) {}
+  template <typename ...> struct A;
+};
+
+template<typename T> struct X {
+  template <T...> struct Y;
+  X() { Y y; };
+};
diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr10.C b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr10.C
new file mode 100644
index 00000000000..be922bbfb73
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr10.C
@@ -0,0 +1,21 @@
+// PR c++/97034
+// { dg-do compile { target c++20 } }
+
+namespace N {
+template <typename, typename> struct S {
+  template <typename T, typename U> S(T, U);
+};
+} // namespace N
+template <int I> struct E {
+  template<typename U> struct M {
+    template <typename T> struct G { T t; };
+    void fn() { G{N::S<char, int>{'a', 1}}; }
+  };
+};
+
+void
+g ()
+{
+  E<1>::M<int> m;
+  m.fn ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr8.C b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr8.C
new file mode 100644
index 00000000000..399061100ae
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr8.C
@@ -0,0 +1,19 @@
+// PR c++/97034
+// { dg-do compile { target c++20 } }
+
+namespace N {
+template <typename, typename> struct S {
+  template <typename T, typename U> S(T, U);
+};
+} // namespace N
+template <int> struct E {
+  template <typename T> struct G { T t; };
+  void fn() { G{N::S<char, int>{'a', 1}}; }
+};
+
+void
+g ()
+{
+  E<1> e;
+  e.fn ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr9.C b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr9.C
new file mode 100644
index 00000000000..245a04cd5f9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr9.C
@@ -0,0 +1,18 @@
+// PR c++/97034
+// { dg-do compile { target c++20 } }
+
+template<typename>
+struct E {
+  template <typename T>
+  struct G {
+    T t;
+  };
+
+  void fn() { G{1}; }
+};
+
+void
+g () {
+  E<int> e;
+  e.fn ();
+}

base-commit: 41fbacdd10305654b1d10f887fa3f4677f9b8f34
Jason Merrill March 3, 2021, 1:57 p.m. UTC | #10
On 3/2/21 4:51 PM, Marek Polacek wrote:
> On Mon, Mar 01, 2021 at 09:29:19PM -0500, Jason Merrill via Gcc-patches wrote:
>> On 3/1/21 7:59 PM, Marek Polacek wrote:
>>> On Mon, Mar 01, 2021 at 03:08:58PM -0500, Jason Merrill wrote:
>>>> On 3/1/21 2:54 PM, Marek Polacek wrote:
>>>>> On Thu, Feb 25, 2021 at 10:45:29PM -0500, Jason Merrill via Gcc-patches wrote:
>>>>>> On 2/25/21 5:41 PM, Marek Polacek wrote:
>>>>>>> On Thu, Feb 25, 2021 at 10:59:49AM -0500, Jason Merrill wrote:
>>>>>>>> On 2/12/21 6:12 PM, Marek Polacek wrote:
>>>>>>>>> We represent deduction guides with FUNCTION_DECLs, but they are built
>>>>>>>>> without DECL_CONTEXT
>>>>>>>>
>>>>>>>> Hmm, that seems wrong: "A deduction-guide shall be declared in the
>>>>>>>> same scope as the corresponding class template and, for a member class
>>>>>>>> template, with the same access."  But it probably isn't necessary to change
>>>>>>>> this:
>>>>>>>>
>>>>>>>>> leading to an ICE in type_dependent_expression_p
>>>>>>>>> on the assert that the type of a function template with no dependent
>>>>>>>>> (innermost!) template arguments must be non-dependent.  Consider the
>>>>>>>>> attached class-deduction79.C: we create a deduction guide:
>>>>>>>>>
>>>>>>>>>        template<class T> G(T)-> E<Z>::G<T>
>>>>>>>>>
>>>>>>>>> we deduce T and create a partial instantiation:
>>>>>>>>>
>>>>>>>>>        G(T) -> E<Z>::G<T> [with T = int]
>>>>>>>>>
>>>>>>>>> And then do_class_deduction wants to create a CALL_EXPR from the above
>>>>>>>>> using build_new_function_call -> build_over_call which calls mark_used
>>>>>>>>> -> maybe_instantiate_noexcept -> type_dependent_expression_p.
>>>>>>>>>
>>>>>>>>> There, the innermost template arguments are non-dependent (<int>), but
>>>>>>>>> the fntype is dependent -- the return type is a TYPENAME_TYPE, and
>>>>>>>>> since we have no DECL_CONTEXT, this check holds:
>>>>>>>>>
>>>>>>>>>        /* Otherwise, if the function decl isn't from a dependent scope, it can't be
>>>>>>>>>           type-dependent.  Checking this is important for functions with auto return
>>>>>>>>>           type, which looks like a dependent type.  */
>>>>>>>>>        if (TREE_CODE (expression) == FUNCTION_DECL
>>>>>>>>>            && !(DECL_CLASS_SCOPE_P (expression)
>>>>>>>>>                 && dependent_type_p (DECL_CONTEXT (expression)))
>>>>>>>>>
>>>>>>>>> whereupon we ICE.
>>>>>>>>>
>>>>>>>>> Experiments with setting DECL_CONTEXT didn't pan out.
>>>>>>>>
>>>>>>>> In c8 of the PR it looks like you were using the class itself as
>>>>>>>> DECL_CONTEXT; the quote above says that the right context is the enclosing
>>>>>>>> scope of the class.
>>>>>>>
>>>>>>> Sadly, using CP_TYPE_CONTEXT (type) would result in a crash in
>>>>>>> retrieve_specialization:
>>>>>>>
>>>>>>>       /* There should be as many levels of arguments as there are
>>>>>>>          levels of parameters.  */
>>>>>>>       gcc_assert (TMPL_ARGS_DEPTH (args)
>>>>>>>                   == (TREE_CODE (tmpl) == TEMPLATE_DECL
>>>>>>>                       ? TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (tmpl))
>>>>>>>                       : template_class_depth (DECL_CONTEXT (tmpl))));
>>>>>>
>>>>>> Yeah, probably simpler not to bother.
>>>>>>
>>>>>>>>> So perhaps we
>>>>>>>>> just want to skip the assert for deduction guides, because they are
>>>>>>>>> a little special.  Better ideas solicited.
>>>>>>>>
>>>>>>>> In c3 you mention that one of the variants broke with r269093; this is
>>>>>>>> because my change to check CLASSTYPE_TEMPLATE_INSTANTIATION is false for the
>>>>>>>> template pattern itself (E<Z>).
>>>>>>>
>>>>>>> And the original test started with my r11-1713 because using TREE_TYPE
>>>>>>> directly instead of decltype (which is a non-deduced context) means we
>>>>>>> can deduced from the argument.
>>>>>>>> But I think probably the right answer is to defer this deduction until the
>>>>>>>> enclosing scope is non-dependent, i.e. (untested)
>>>>>>>
>>>>>>> Thanks.  That mostly works, except the new class-deduction-aggr[89].C
>>>>>>> tests.  Consider 8:
>>>>>>>
>>>>>>> namespace N {
>>>>>>> template <typename, typename> struct S {
>>>>>>>       template <typename T, typename U> S(T, U);
>>>>>>> };
>>>>>>> } // namespace N
>>>>>>> template <int> struct E {
>>>>>>>       template <typename T> struct G { T t; };
>>>>>>>       void fn() { G{N::S<char, int>{'a', 1}}; }
>>>>>>> };
>>>>>>>
>>>>>>> void
>>>>>>> g ()
>>>>>>> {
>>>>>>>       E<1> e;
>>>>>>>       e.fn ();
>>>>>>> }
>>>>>>>
>>>>>>> With your patch, when in do_class_deduction when processing_template_decl,
>>>>>>> we just return.  When we call do_class_deduction again when p_t_d is 0,
>>>>>>> maybe_aggr_guide returns early here:
>>>>>>>
>>>>>>>       if (!CP_AGGREGATE_TYPE_P (type))
>>>>>>>         return NULL_TREE
>>>>>>>
>>>>>>> because G is not complete (and rightly so, we didn't instantiate it).  So
>>>>>>> we aren't able to deduce the template parameters.  I'm not sure if I should
>>>>>>> pursue this direction further.  :(
>>>>>>
>>>>>> I think so; we just need to test CP_AGGREGATE_TYPE_P on the original
>>>>>> template pattern instead of the instantiation E<1>::G.
>>>>>
>>>>> I'm sorry, I've got stuck again.
>>>>>
>>>>> Yes, using the original template pattern helps us get past the
>>>>> CP_AGGREGATE_TYPE_P check.
>>>>>
>>>>> However, using TREE_TYPE (DECL_TI_TEMPLATE (tmpl)) as the type of the deduction guide
>>>>> means the guide will be "template<class T> G(T)-> E<<anonymous> >::G<T>" which
>>>>> results in
>>>>>
>>>>>      class-deduction-aggr8.C:11:15: error: invalid use of dependent type 'typename E<<anonymous> >::G<N::S<char, int> >'
>>>>>
>>>>> which makes sense I guess: when we defer building up the guide until
>>>>> we've instantiated E<1>, finding the dependent type E<> is not expected.
>>>>
>>>> Yeah, I was only thinking to use the pattern for the aggregate check.
>>>
>>> Ack.  Though I think I also have to use the pattern here:
>>>
>>>     init = reshape_init (type, init, complain);
>>>
>>> otherwise reshape_init returns a TARGET_EXPR and we immediately
>>> crash in collect_ctor_idx_types because that only expects a CONSTRUCTOR.
>>> And what we need to get is the type T -- of the constructor's index.
>>>>> But creating the guide with "struct E<1>::G<T>" as its type seems
>>>>> wrong; I'm not even sure if a guide like
>>>>>
>>>>>      template<class T> G(T)-> E<1>::G<T>
>>>>>
>>>>> makes sense.
>>>>
>>>> It looks fine to me.
>>>>
>>>>> In any case the deduction fails (when we call
>>>>> build_new_function_call in do_class_deduction), because we've got
>>>>> a mismatch: the template parameter T has level 1, but the template
>>>>> function parameter has level 2.
>>>>
>>>> Sure, because E<1>::G<T> has been partially instantiated, so the T has been
>>>> reduced from level 2 to 1.
>>>
>>> Right.
>>>> You'll need to do a similar partial instantiation for building the deduction
>>>> guide, either as part of the deduction guide rewriting or on the constructor
>>>> before rewriting.
>>>
>>> So I've tried.  I can't actually tsubst the constructor itself, because it
>>> at this point contains an AGGR_INIT_EXPR, which tsubst* can't handle.  But
>>> what I could do is
>>>
>>>     parms = tsubst (parms, DECL_TI_ARGS (tmpl), complain, init);
>>>
>>> just after the call to collect_ctor_idx_types.  After all, this is what
>>> we care about and create the function template parameters from.  So now
>>> T's level is reduced to 1, and the guide we create is
>>>
>>>     template<class T> G(T)-> E<1>::G<T>
>>>
>>> This guide is then chosen in do_class_deduction -> build_new_function_call,
>>> but we crash in fn_type_unification -> instantiate_template (after we've
>>> deduced T to N::S<char, int>) in retrieve_specialization:
>>>
>>>     gcc_assert (TMPL_ARGS_DEPTH (args)
>>>                 == (TREE_CODE (tmpl) == TEMPLATE_DECL
>>>                     ? TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (tmpl))
>>>                     : template_class_depth (DECL_CONTEXT (tmpl))));
>>>
>>> args is <1, S> (depth 2), tmpl is our deduction guide, and
>>> DECL_TEMPLATE_PARMS (tmpl) is [1 T] (depth 1).
>>
>> I'd think args should only be S (depth 1).
> 
> Ah!  I think I finally got a working patch.  Thanks for all the help!
> 
> Added class-deduction-aggr10.C to test the deduction in more nested classes.
> 
> Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
> Additionally, I've built cmcstl2 and Boost 1.75.

OK, thanks.

> -- >8 --
> We represent deduction guides with FUNCTION_DECLs, but they are built
> without DECL_CONTEXT, leading to an ICE in type_dependent_expression_p
> on the assert that the type of a function template with no dependent
> (innermost!) template arguments must be non-dependent.  Consider the
> attached class-deduction79.C: we create a deduction guide:
> 
>    template<class T> G(T)-> E<Z>::G<T>
> 
> we deduce T and create a partial instantiation:
> 
>    G(T) -> E<Z>::G<T> [with T = int]
> 
> And then do_class_deduction wants to create a CALL_EXPR from the above
> using build_new_function_call -> build_over_call which calls mark_used
> -> maybe_instantiate_noexcept -> type_dependent_expression_p.
> 
> There, the innermost template arguments are non-dependent (<int>), but
> the fntype is dependent -- the return type is a TYPENAME_TYPE, and
> since we have no DECL_CONTEXT, this check holds:
> 
>    /* Otherwise, if the function decl isn't from a dependent scope, it can't be
>       type-dependent.  Checking this is important for functions with auto return
>       type, which looks like a dependent type.  */
>    if (TREE_CODE (expression) == FUNCTION_DECL
>        && !(DECL_CLASS_SCOPE_P (expression)
>             && dependent_type_p (DECL_CONTEXT (expression)))
> 
> whereupon we ICE.
> 
> This patch fixes it by deferring the class deduction until the
> enclosing scope is non-dependent.  build_deduction_guide and maybe_aggr_guide
> needed a little tweaking to make the deduction work in a member
> template.
> 
> Co-Authored-By: Jason Merrill <jason@redhat.com>
> 
> gcc/cp/ChangeLog:
> 
> 	PR c++/97034
> 	PR c++/99009
> 	* pt.c (build_deduction_guide): Use INNERMOST_TEMPLATE_ARGS.
> 	(maybe_aggr_guide): Use the original template type where needed.  In
> 	a class member template, partially instantiate the result of
> 	collect_ctor_idx_types.
> 	(do_class_deduction): Defer the deduction until the enclosing
> 	scope is non-dependent.
> 
> gcc/testsuite/ChangeLog:
> 
> 	PR c++/97034
> 	PR c++/99009
> 	* g++.dg/cpp1z/class-deduction81.C: New test.
> 	* g++.dg/cpp1z/class-deduction82.C: New test.
> 	* g++.dg/cpp2a/class-deduction-aggr8.C: New test.
> 	* g++.dg/cpp2a/class-deduction-aggr9.C: New test.
> 	* g++.dg/cpp2a/class-deduction-aggr10.C: New test.
> ---
>   gcc/cp/pt.c                                   | 36 +++++++++++++++++--
>   .../g++.dg/cpp1z/class-deduction81.C          | 20 +++++++++++
>   .../g++.dg/cpp1z/class-deduction82.C          | 12 +++++++
>   .../g++.dg/cpp2a/class-deduction-aggr10.C     | 21 +++++++++++
>   .../g++.dg/cpp2a/class-deduction-aggr8.C      | 19 ++++++++++
>   .../g++.dg/cpp2a/class-deduction-aggr9.C      | 18 ++++++++++
>   6 files changed, 123 insertions(+), 3 deletions(-)
>   create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction81.C
>   create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction82.C
>   create mode 100644 gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr10.C
>   create mode 100644 gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr8.C
>   create mode 100644 gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr9.C
> 
> diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
> index 8d65a6e5bd2..a4686e0affb 100644
> --- a/gcc/cp/pt.c
> +++ b/gcc/cp/pt.c
> @@ -28643,7 +28643,7 @@ build_deduction_guide (tree type, tree ctor, tree outer_args, tsubst_flags_t com
>   
>         tree ctmpl = CLASSTYPE_TI_TEMPLATE (type);
>         tparms = DECL_TEMPLATE_PARMS (ctmpl);
> -      targs = CLASSTYPE_TI_ARGS (type);
> +      targs = INNERMOST_TEMPLATE_ARGS (CLASSTYPE_TI_ARGS (type));
>         ci = NULL_TREE;
>         fargs = NULL_TREE;
>         loc = DECL_SOURCE_LOCATION (ctmpl);
> @@ -28866,8 +28866,22 @@ maybe_aggr_guide (tree tmpl, tree init, vec<tree,va_gc> *args)
>     if (init == NULL_TREE)
>       return NULL_TREE;
>   
> +  /* We might be creating a guide for a class member template, e.g.,
> +
> +       template<typename U> struct A {
> +	 template<typename T> struct B { T t; };
> +       };
> +
> +     At this point, A will have been instantiated.  Below, we need to
> +     use both A<U>::B<T> (TEMPLATE_TYPE) and A<int>::B<T> (TYPE) types.  */
> +  const bool member_template_p
> +    = (DECL_TEMPLATE_INFO (tmpl)
> +       && DECL_MEMBER_TEMPLATE_P (DECL_TI_TEMPLATE (tmpl)));
>     tree type = TREE_TYPE (tmpl);
> -  if (!CP_AGGREGATE_TYPE_P (type))
> +  tree template_type = (member_template_p
> +			? TREE_TYPE (DECL_TI_TEMPLATE (tmpl))
> +			: type);
> +  if (!CP_AGGREGATE_TYPE_P (template_type))
>       return NULL_TREE;
>   
>     /* No aggregate candidate for copy-initialization.  */
> @@ -28884,10 +28898,21 @@ maybe_aggr_guide (tree tmpl, tree init, vec<tree,va_gc> *args)
>     tree parms = NULL_TREE;
>     if (BRACE_ENCLOSED_INITIALIZER_P (init))
>       {
> -      init = reshape_init (type, init, complain);
> +      init = reshape_init (template_type, init, complain);
>         if (init == error_mark_node)
>   	return NULL_TREE;
>         parms = collect_ctor_idx_types (init, parms);
> +      /* If we're creating a deduction guide for a member class template,
> +	 we've used the original template pattern type for the reshape_init
> +	 above; this is done because we want PARMS to be a template parameter
> +	 type, something that can be deduced when used as a function template
> +	 parameter.  At this point the outer class template has already been
> +	 partially instantiated (we deferred the deduction until the enclosing
> +	 scope is non-dependent).  Therefore we have to partially instantiate
> +	 PARMS, so that its template level is properly reduced and we don't get
> +	 mismatches when deducing types using the guide with PARMS.  */
> +      if (member_template_p)
> +	parms = tsubst (parms, DECL_TI_ARGS (tmpl), complain, init);
>       }
>     else if (TREE_CODE (init) == TREE_LIST)
>       {
> @@ -29225,6 +29250,11 @@ do_class_deduction (tree ptype, tree tmpl, tree init,
>     if (DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl))
>       return ptype;
>   
> +  /* Wait until the enclosing scope is non-dependent.  */
> +  if (DECL_CLASS_SCOPE_P (tmpl)
> +      && dependent_type_p (DECL_CONTEXT (tmpl)))
> +    return ptype;
> +
>     /* Initializing one placeholder from another.  */
>     if (init && TREE_CODE (init) == TEMPLATE_PARM_INDEX
>         && is_auto (TREE_TYPE (init))
> diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction81.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction81.C
> new file mode 100644
> index 00000000000..86a68248157
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction81.C
> @@ -0,0 +1,20 @@
> +// PR c++/97034
> +// { dg-do compile { target c++17 } }
> +
> +template <typename Z>
> +struct E {
> +  template <typename T>
> +  struct G {
> +    T t;
> +    G(T) { }
> +  };
> +
> +  void fn() { G{1}; }
> +};
> +
> +void
> +g ()
> +{
> +  E<int> e;
> +  e.fn ();
> +}
> diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction82.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction82.C
> new file mode 100644
> index 00000000000..238024c508f
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction82.C
> @@ -0,0 +1,12 @@
> +// PR c++/99009
> +// { dg-do compile { target c++17 } }
> +
> +template<typename> struct B {
> +  B(int = A()) {}
> +  template <typename ...> struct A;
> +};
> +
> +template<typename T> struct X {
> +  template <T...> struct Y;
> +  X() { Y y; };
> +};
> diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr10.C b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr10.C
> new file mode 100644
> index 00000000000..be922bbfb73
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr10.C
> @@ -0,0 +1,21 @@
> +// PR c++/97034
> +// { dg-do compile { target c++20 } }
> +
> +namespace N {
> +template <typename, typename> struct S {
> +  template <typename T, typename U> S(T, U);
> +};
> +} // namespace N
> +template <int I> struct E {
> +  template<typename U> struct M {
> +    template <typename T> struct G { T t; };
> +    void fn() { G{N::S<char, int>{'a', 1}}; }
> +  };
> +};
> +
> +void
> +g ()
> +{
> +  E<1>::M<int> m;
> +  m.fn ();
> +}
> diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr8.C b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr8.C
> new file mode 100644
> index 00000000000..399061100ae
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr8.C
> @@ -0,0 +1,19 @@
> +// PR c++/97034
> +// { dg-do compile { target c++20 } }
> +
> +namespace N {
> +template <typename, typename> struct S {
> +  template <typename T, typename U> S(T, U);
> +};
> +} // namespace N
> +template <int> struct E {
> +  template <typename T> struct G { T t; };
> +  void fn() { G{N::S<char, int>{'a', 1}}; }
> +};
> +
> +void
> +g ()
> +{
> +  E<1> e;
> +  e.fn ();
> +}
> diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr9.C b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr9.C
> new file mode 100644
> index 00000000000..245a04cd5f9
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr9.C
> @@ -0,0 +1,18 @@
> +// PR c++/97034
> +// { dg-do compile { target c++20 } }
> +
> +template<typename>
> +struct E {
> +  template <typename T>
> +  struct G {
> +    T t;
> +  };
> +
> +  void fn() { G{1}; }
> +};
> +
> +void
> +g () {
> +  E<int> e;
> +  e.fn ();
> +}
> 
> base-commit: 41fbacdd10305654b1d10f887fa3f4677f9b8f34
>
diff mbox series

Patch

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 60de8e93ff7..3e6f3407d40 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -27282,7 +27282,10 @@  type_dependent_expression_p (tree expression)
 	   && DECL_UNIQUE_FRIEND_P (expression)
 	   && (!DECL_FRIEND_CONTEXT (expression)
 	       || dependent_type_p (DECL_FRIEND_CONTEXT (expression))))
-      && !DECL_LOCAL_DECL_P (expression))
+      && !DECL_LOCAL_DECL_P (expression)
+      /* We build deduction guides without any DECL_CONTEXT, but they can
+	 be type-dependent.  */
+      && !deduction_guide_p (expression))
     {
       gcc_assert (!dependent_type_p (TREE_TYPE (expression))
 		  || undeduced_auto_decl (expression));
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction79.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction79.C
new file mode 100644
index 00000000000..86a68248157
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction79.C
@@ -0,0 +1,20 @@ 
+// PR c++/97034
+// { dg-do compile { target c++17 } }
+
+template <typename Z>
+struct E {
+  template <typename T>
+  struct G {
+    T t;
+    G(T) { }
+  };
+
+  void fn() { G{1}; }
+};
+
+void
+g ()
+{
+  E<int> e;
+  e.fn ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction80.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction80.C
new file mode 100644
index 00000000000..238024c508f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction80.C
@@ -0,0 +1,12 @@ 
+// PR c++/99009
+// { dg-do compile { target c++17 } }
+
+template<typename> struct B {
+  B(int = A()) {}
+  template <typename ...> struct A;
+};
+
+template<typename T> struct X {
+  template <T...> struct Y;
+  X() { Y y; };
+};
diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr8.C b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr8.C
new file mode 100644
index 00000000000..399061100ae
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr8.C
@@ -0,0 +1,19 @@ 
+// PR c++/97034
+// { dg-do compile { target c++20 } }
+
+namespace N {
+template <typename, typename> struct S {
+  template <typename T, typename U> S(T, U);
+};
+} // namespace N
+template <int> struct E {
+  template <typename T> struct G { T t; };
+  void fn() { G{N::S<char, int>{'a', 1}}; }
+};
+
+void
+g ()
+{
+  E<1> e;
+  e.fn ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr9.C b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr9.C
new file mode 100644
index 00000000000..245a04cd5f9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr9.C
@@ -0,0 +1,18 @@ 
+// PR c++/97034
+// { dg-do compile { target c++20 } }
+
+template<typename>
+struct E {
+  template <typename T>
+  struct G {
+    T t;
+  };
+
+  void fn() { G{1}; }
+};
+
+void
+g () {
+  E<int> e;
+  e.fn ();
+}