c++: alias template and empty parameter packs [PR104008]
authorMarek Polacek <polacek@redhat.com>
Wed, 16 Mar 2022 13:34:34 +0000 (09:34 -0400)
committerMarek Polacek <polacek@redhat.com>
Fri, 18 Mar 2022 16:50:18 +0000 (12:50 -0400)
commitc7a6a32739d62deab03266e2b5449fce261b1ecb
tree643f699758d2d3aa7a5bce4395da9105f3076788
parentc133bdfa9e7d9225510d00dbb7270cc052e4e4ee
c++: alias template and empty parameter packs [PR104008]

Zero-length pack expansions are treated as if no list were provided
at all, that is, with

  template<typename...> struct S { };
  template<typename T, typename... Ts>
  void g() {
    S<std::is_same<T, Ts>...>;
  }

g<int> will result in S<>.  In the following test we have something
similar:

  template <typename T, typename... Ts>
  using IsOneOf = disjunction<is_same<T, Ts>...>;

and then we have "IsOneOf<OtherHolders>..." where OtherHolders is an
empty pack.  Since r11-7931, we strip_typedefs in TYPE_PACK_EXPANSION.
In this test that results in "IsOneOf<OtherHolders>" being turned into
"disjunction<>".  So the whole expansion is now "disjunction<>...".  But
then we error in make_pack_expansion because find_parameter_packs_r won't
find the pack OtherHolders.

We strip the alias template because dependent_alias_template_spec_p says
it's not dependent.  It it not dependent because this alias is not
TEMPLATE_DECL_COMPLEX_ALIAS_P.  My understanding is that currently we
consider an alias complex if it

1) expands a pack from the enclosing class, as in

    template<template<typename... U> typename... TT>
    struct S {
      template<typename... Args>
      using X = P<TT<Args...>...>;
    };

   where the alias expands TT; or

2) the expansion does *not* name all the template parameters, as in

    template<typename...> struct R;
    template<typename T, typename... Ts>
    using U = R<X<Ts>...>;

   where T is not named in the expansion.

But IsOneOf is neither.  And it can't know how it's going to be used.
Therefore I think we cannot make it complex (and in turn dependent) to fix
this bug.

After much gnashing of teeth, I think we simply want to avoid stripping
the alias if the new pattern doesn't have any parameter packs to expand.

PR c++/104008

gcc/cp/ChangeLog:

* tree.cc (strip_typedefs): Don't strip an alias template when
doing so would result in losing a parameter pack.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/variadic-alias3.C: New test.
* g++.dg/cpp0x/variadic-alias4.C: New test.
gcc/cp/tree.cc
gcc/testsuite/g++.dg/cpp0x/variadic-alias3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/variadic-alias4.C [new file with mode: 0644]