Pack expansion bug?

I think this is a Clang bug (seen at least with Clang 14.0.5 and recent Clang 16 trunk), but am not completely sure, so wanted to clarify here first:

$ cat test.cc
template<typename, typename> struct Pair;
template<typename...> struct Tuple;
template<typename... Ts> struct A {
    template<typename... Us> using B = Tuple<Pair<Ts, Us>...>;
};
template<typename... Ts> struct C {
    template<typename... Us> using D = typename A<Ts...>::template B<Us...>;
};
using E = C<int, int>::D<int, int>;
$ clang++ -fsyntax-only test.cc
test.cc:4:30: error: pack expansion contains parameter pack 'Us' that has a different length (2 vs. 1) from outer parameter packs
    template<typename... Us> using B = Tuple<Pair<Ts, Us>...>;
                             ^~~~~
test.cc:7:68: note: in instantiation of template type alias 'B' requested here
    template<typename... Us> using D = typename A<Ts...>::template B<Us...>;
                                                                   ^
test.cc:9:11: note: in instantiation of template class 'C<int, int>' requested here
using E = C<int, int>::D<int, int>;
          ^
1 error generated.

(This causes issues now with recent GCC 13 trunk libstdc++ since https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=72886fcc6269531bbf3d9a09b3d64644963bff0d “libstdc++: Implement std::pair/tuple/misc enhancements from P2321R2”,

$ cat test2.cc
#include <map>
#include <tuple>
std::map<std::tuple<int, int>, int> m;
int f(std::tuple<int, int> k) {
    return m[k];
}
$ clang++ --gcc-toolchain=gcc/trunk/inst -std=c++2b -fsyntax-only test2.cc
In file included from test2.cc:1:
In file included from gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/13.0.0/../../../../include/c++/13.0.0/map:61:
In file included from gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/13.0.0/../../../../include/c++/13.0.0/bits/stl_map.h:63:
gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/13.0.0/../../../../include/c++/13.0.0/tuple:690:2: error: pack expansion contains parameter pack '_UTypes' that has a different length (1 vs. 2) from outer parameter packs
        using __convertible = __and_<is_convertible<_UTypes, _Types>...>;
        ^~~~~
gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/13.0.0/../../../../include/c++/13.0.0/tuple:852:27: note: in instantiation of template type alias '__convertible' requested here
          = _TCC<true>::template __convertible<_Args...>::value;
                                 ^
gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/13.0.0/../../../../include/c++/13.0.0/tuple:947:12: note: in instantiation of static data member 'std::tuple<const std::tuple<int, int> &>::__convertible<int &, int &>' requested here
        explicit(!__convertible<_UElements&...>)
                  ^
gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/13.0.0/../../../../include/c++/13.0.0/bits/stl_map.h:512:38: note: while substituting deduced template arguments into function template 'tuple' [with _UElements = <int, int>]
                                            std::tuple<const key_type&>(__k),
                                                                        ^
test2.cc:5:13: note: in instantiation of member function 'std::map<std::tuple<int, int>, int>::operator[]' requested here
    return m[k];
            ^
In file included from test2.cc:1:
In file included from gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/13.0.0/../../../../include/c++/13.0.0/map:61:
In file included from gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/13.0.0/../../../../include/c++/13.0.0/bits/stl_map.h:63:
gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/13.0.0/../../../../include/c++/13.0.0/tuple:690:2: error: pack expansion contains parameter pack '_UTypes' that has a different length (1 vs. 2) from outer parameter packs
        using __convertible = __and_<is_convertible<_UTypes, _Types>...>;
        ^~~~~
gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/13.0.0/../../../../include/c++/13.0.0/tuple:852:27: note: in instantiation of template type alias '__convertible' requested here
          = _TCC<true>::template __convertible<_Args...>::value;
                                 ^
gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/13.0.0/../../../../include/c++/13.0.0/tuple:958:12: note: in instantiation of static data member 'std::tuple<const std::tuple<int, int> &>::__convertible<const int, const int>' requested here
        explicit(!__convertible<const _UElements...>)
                  ^
gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/13.0.0/../../../../include/c++/13.0.0/bits/stl_map.h:512:38: note: while substituting deduced template arguments into function template 'tuple' [with _UElements = <int, int>]
                                            std::tuple<const key_type&>(__k),
                                                                        ^
test2.cc:5:13: note: in instantiation of member function 'std::map<std::tuple<int, int>, int>::operator[]' requested here
    return m[k];
            ^
2 errors generated.

)

@mizvekov: Seeing that you recently did work on pack expansion, maybe you happen to have an idea about the above?

Does look like a bug to me :slight_smile:

I’ll try to have a look over the weekend.

I tentatively consider this a duplicate of https://github.com/llvm/llvm-project/issues/17042 “Rejects-valid with variadic alias template in variadic class template”.
(Similar to the reproducer of that issue, my reproducer here also still fails when rewinding back to before ⚙ D131802 [clang] fix missing initialization of original number of expansions, b8a1b69 “[clang] fix missing initialization of original number of expansions” (i.e., to b8ecf32 “DynamicMemRefType: iteration and access by indices”; see my comment at https://github.com/llvm/llvm-project/issues/58452#issuecomment-1431323997 " False positive compile error when expanding packs in function parameters".)