Fix template argument deduction when a parameter pack has a value
provided by an outer template.
We made the incorrect assumption in various places that the only way we
can have any arguments already provided for a pack during template
argument deduction was from a partially-specified pack. That's not true;
we can also have arguments from an enclosing already-instantiated
template, and that can even result in the function template's own pack
parameters having a fixed length and not being packs for the purposes of
template argument deduction.
llvm-svn: 337481
diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp
index 71c5833..9dfdd05 100644
--- a/clang/lib/Sema/SemaTemplateVariadic.cpp
+++ b/clang/lib/Sema/SemaTemplateVariadic.cpp
@@ -646,7 +646,9 @@
RetainExpansion = false;
std::pair<IdentifierInfo *, SourceLocation> FirstPack;
bool HaveFirstPack = false;
-
+ Optional<unsigned> NumPartialExpansions;
+ SourceLocation PartiallySubstitutedPackLoc;
+
for (ArrayRef<UnexpandedParameterPack>::iterator i = Unexpanded.begin(),
end = Unexpanded.end();
i != end; ++i) {
@@ -711,8 +713,13 @@
= CurrentInstantiationScope->getPartiallySubstitutedPack()){
unsigned PartialDepth, PartialIndex;
std::tie(PartialDepth, PartialIndex) = getDepthAndIndex(PartialPack);
- if (PartialDepth == Depth && PartialIndex == Index)
+ if (PartialDepth == Depth && PartialIndex == Index) {
RetainExpansion = true;
+ // We don't actually know the new pack size yet.
+ NumPartialExpansions = NewPackSize;
+ PartiallySubstitutedPackLoc = i->second;
+ continue;
+ }
}
}
@@ -742,6 +749,28 @@
}
}
+ // If we're performing a partial expansion but we also have a full expansion,
+ // expand to the number of common arguments. For example, given:
+ //
+ // template<typename ...T> struct A {
+ // template<typename ...U> void f(pair<T, U>...);
+ // };
+ //
+ // ... a call to 'A<int, int>().f<int>' should expand the pack once and
+ // retain an expansion.
+ if (NumPartialExpansions) {
+ if (NumExpansions && *NumExpansions < *NumPartialExpansions) {
+ NamedDecl *PartialPack =
+ CurrentInstantiationScope->getPartiallySubstitutedPack();
+ Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict_partial)
+ << PartialPack << *NumPartialExpansions << *NumExpansions
+ << SourceRange(PartiallySubstitutedPackLoc);
+ return true;
+ }
+
+ NumExpansions = NumPartialExpansions;
+ }
+
return false;
}