Repro: https://godbolt.org/z/G6e3cK4W9
template <typename A, typename B>
using ConditionalRewrite = B;
template <typename T>
using SignatureType = int;
template <typename... Args>
struct Type1 {
template <typename... Params>
using Return = SignatureType<int(ConditionalRewrite<Args, Params>...)>;
};
template <typename... Args>
struct Type2 {
using T1 = Type1<Args...>;
template <typename... Params>
using Return = typename T1::template Return<Params...>;
};
template <typename T>
typename T::template Return<int, int> InvokeMethod() {
return 3;
}
int Function1() {
return InvokeMethod<Type2<int, int>>();
}
When compiling the above code, Clang reports below error:
<source>:10:3: error: pack expansion contains parameter packs 'Args' and 'Params' that have different lengths (2 vs. 1)
using Return = SignatureType<int(ConditionalRewrite<Args, Params>...)>;
^
However, the length of Args and Params are the same when instantiating Type2<int, int>::Return<int, int>.
The problem happens after https://reviews.llvm.org/D131802.
My understanding of the problem is below:
The error was reported in https://github.com/root-project/root/blob/master/interpreter/llvm/src/tools/clang/lib/Sema/SemaTemplateVariadic.cpp#L727 in function Sema::CheckParameterPacksForExpansion(). CheckParameterPacksForExpansion() checks if the lengths of all unexpanded
parameter packs are the same.
The expansion we care in the example is in L10 ConditionalRewrite<Args, Params>.... Since we instantiate Type1<int, int>,
Args is a pack TemplateArgument: <int, int>, which has pack length 2. But for Params, its content changes in multiple runs of
CheckParameterPacksForExpansion. It can be either <type-parameter-0-0...> or <int, int>. And when Params is <type-parameter-0-0...>, CheckParameterPacksForExpansion() thinks its length is 1 (which doesn't match the length of Args), and reports the error.
I experimented adding below lines in CheckParameterPacksForExpansion() to skip the length check when a template arg is expandable:
const TemplateArgument& Arg = TemplateArgs(Depth, Index);
if (Arg.pack_size() == 1 && Arg.pack_begin()->isPackExpansion()) {
ShouldExpand = false;
continue;
}
It can avoid the compile error. But I don't know if there are other cases to consider. So I'd like to leave it to maintainers for a proper fix.
Repro: https://godbolt.org/z/G6e3cK4W9
When compiling the above code, Clang reports below error:
However, the length of
ArgsandParamsare the same when instantiatingType2<int, int>::Return<int, int>.The problem happens after https://reviews.llvm.org/D131802.
My understanding of the problem is below:
The error was reported in https://github.com/root-project/root/blob/master/interpreter/llvm/src/tools/clang/lib/Sema/SemaTemplateVariadic.cpp#L727 in function
Sema::CheckParameterPacksForExpansion().CheckParameterPacksForExpansion()checks if the lengths of all unexpandedparameter packs are the same.
The expansion we care in the example is in L10
ConditionalRewrite<Args, Params>.... Since we instantiateType1<int, int>,Argsis a packTemplateArgument: <int, int>, which has pack length 2. But forParams, its content changes in multiple runs ofCheckParameterPacksForExpansion. It can be either<type-parameter-0-0...>or<int, int>. And whenParamsis<type-parameter-0-0...>,CheckParameterPacksForExpansion()thinks its length is 1 (which doesn't match the length ofArgs), and reports the error.I experimented adding below lines in
CheckParameterPacksForExpansion()to skip the length check when a template arg is expandable:It can avoid the compile error. But I don't know if there are other cases to consider. So I'd like to leave it to maintainers for a proper fix.