On Wed, 1 Jan 2025, A J Ryan Solutions Ltd wrote:

> Hi and happy new year, this patch is to fix a compiler seg-fault as 
> encountered in the following example:

Hi, thanks for the patch!  Your fix makes sense to me, and I believe it
also fixes the testcases from PR102626 and at least some of its related
PRs.

> 
> template<class> struct Class1{};
> 
> template<auto...Tn> class Class2;
> template<typename...V,Class1<V>...Un> class Class2<Un...>
> {
>     public: void apply(){}
> };
> 
> Class1<bool> class1_bool;
> Class1<char> class1_char;
> 
> int main()
> {
>     Class2<class1_bool,class1_char> class2;
>     class2.apply();
> }

> where it ends up populating the V argument in the instantiated template at 
> the class2 declaration with the unknown placeholder and the segfault is when 
> it later tries to get the name for an incompletely
> resolved type.

Here's a more reduced example that's fixed by your patch:

  template<auto> struct A { };

  template<class... Ts, Ts... Vs>
  void f(A<Vs>...);

  int main() {
    f(A<0>{}, A<1u>{}, A<2l>{}); // OK, Ts deduced to {int,unsigned,long}
  }

A related PR that isn't and shouldn't be fixed by this patch is PR84796
where the type parameter pack is declared at a different level than
the non-type parameter pack, e.g.:

  template<auto...>
  struct A { };

  template<class... Ts>
  struct B {
    template<Ts... Vs>
    static void f(A<Vs...>);
  };

  int main() {
    A<1, true, 'c'> a;
    B<int, bool, char>::f(a);
  }

Before your patch we would ICE on this valid testcase, after we now reject it
with a bogus error:

<stdin>: In function ‘int main()’:
<stdin>:12:24: error: no matching function for call to ‘B<int, bool, 
char>::f(A<1, true, 'c'>&)’
<stdin>:12:24: note: there is 1 candidate
<stdin>:7:15: note: candidate 1: ‘template<Ts ...Vs> static void B<Ts>::f(A<Vs 
...>) [with Ts ...Vs = {Vs ...}; Ts = {int, bool, char}]’
<stdin>:7:15: note: template argument deduction/substitution failed:
<stdin>:12:24: note:   ‘Vs’ is not equivalent to ‘1’

Which is no worse than ICEing, I suppose :)

> 
> The incorrect processing happens in unify_pack_expansion where it is calling 
> unify_one_argument
> here(https://gcc.gnu.org/git?p=gcc.git;a=blob;f=gcc/cp/pt.cc;h=0ffa0b53e26a87df3ed2c7202446c68d2800db64;hb=HEAD#l24718)
>  for each argument of the argument pack and recursively unifying the inner 
> arguments. In
> this example the inner argument against V (bool/char) is set in targs however 
> it is not seen as a pack argument in unify_pack_expansion because in the 
> unfixed code it does not reach and link this associated
> pack and later on when processing the collected arguments to substitute it in 
> in instantiate_class_template the argument has not been set as an argument 
> pack in targs and it doesn't match the the template
> specialisation parameter which is a parameter pack and it falls back to the 
> unknown placeholder.
> The parameter packs are originally linked in make_pack_expansion 
> here(https://gcc.gnu.org/git?p=gcc.git;a=blob;f=gcc/cp/pt.cc;h=0ffa0b53e26a87df3ed2c7202446c68d2800db64;hb=HEAD#l4246)
>  and the change is in
> this tree walk so that in the example above V is chained to Un and after 
> calling unify_one_argument it loops over both packs and extracts their 
> associated value set in targs and puts it into it's pack
> argument collection.
> 
> Regards
> Adam Ryan

> 
> 
> Subject: [PATCH] Add tree walk case to obtain A pack in
>  <typename...A,Class<A>...B>.
> 
> For non-type parameter packs when unifying the arguments in 
> unify_pack_expansion
> it iterates over the associated packs of a param so that when it recursivly
> unifies the param with the arguments it knows which targs have been populated
> with parameter pack arguments that it can then collect up. This change adds a
> tree walk so that in the example above it reaches ...A and adds it to the
> associated packs for ...B and therefore knows it will have been set in targs
> in unify_pack_expansion and processes it as per other pack arguments.
> 
> PR gcc/118265

PR c++/118265 rather

A ChangeLog entry is missing from the commit message as per
https://gcc.gnu.org/contribute.html#patches

Here's an example ChangeLog we can use for this patch:

gcc/cp/ChangeLog:

        * pt.cc (find_parameter_packs_r) <case TEMPLATE_PARM_INDEX>:
        Walk into the type of a parameter pack.

> 
> Signed-off-by: Adam J Ryan <gcc.gnu....@ajryansolutions.co.uk>
> ---
>  gcc/cp/pt.cc                    |  5 +++++
>  gcc/testsuite/g++.dg/pr118265.C | 17 +++++++++++++++++
>  2 files changed, 22 insertions(+)
>  create mode 100644 gcc/testsuite/g++.dg/pr118265.C
> 
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 0ffa0b53e26..22f5d4b1875 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -4012,6 +4012,11 @@ find_parameter_packs_r (tree *tp, int *walk_subtrees, 
> void* data)
>                   &find_parameter_packs_r, ppd, ppd->visited);
>        return NULL_TREE;
>  
> +    case TEMPLATE_PARM_INDEX:
> +      if (parameter_pack_p)
> +        WALK_SUBTREE ( TREE_TYPE(t) );

There should be a space before the ( starting a function call not
after (as per the GNU coding style), so this should be
"WALK_SUBTREE (TREE_TYPE (t));"

> +      return NULL_TREE;
> +
>      case DECL_EXPR:
>        {
>       tree decl = DECL_EXPR_DECL (t);
> diff --git a/gcc/testsuite/g++.dg/pr118265.C b/gcc/testsuite/g++.dg/pr118265.C
> new file mode 100644
> index 00000000000..00bda1b5b48
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/pr118265.C
> @@ -0,0 +1,17 @@
> +// { dg-do compile { target c++20 } }
> +template<class> struct Class1{};
> +
> +template<auto...Tn> class Class2;
> +template<typename...V,Class1<V>...Un> class Class2<Un...>
> +{
> +    public: void apply(){}
> +};
> +
> +Class1<bool> class1_bool;
> +Class1<char> class1_char;
> +
> +int main()
> +{
> +    Class2<class1_bool,class1_char> class2;
> +    class2.apply();
> +}
> \ No newline at end of file
> -- 
> 2.43.0
> 

Reply via email to