aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Sema/SemaTemplateVariadic.cpp
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2018-07-19 19:00:37 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2018-07-19 19:00:37 +0000
commit4a8f3518cb1444f7041ecb36fceb49d59f08b4b1 (patch)
tree993ad7351ac668d1ff6fdefcfd17c49bdfc5d408 /clang/lib/Sema/SemaTemplateVariadic.cpp
parentf29044536d7a77cac152948a066c44e7cb010627 (diff)
downloadllvm-4a8f3518cb1444f7041ecb36fceb49d59f08b4b1.zip
llvm-4a8f3518cb1444f7041ecb36fceb49d59f08b4b1.tar.gz
llvm-4a8f3518cb1444f7041ecb36fceb49d59f08b4b1.tar.bz2
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
Diffstat (limited to 'clang/lib/Sema/SemaTemplateVariadic.cpp')
-rw-r--r--clang/lib/Sema/SemaTemplateVariadic.cpp33
1 files changed, 31 insertions, 2 deletions
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 @@ bool Sema::CheckParameterPacksForExpansion(
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 @@ bool Sema::CheckParameterPacksForExpansion(
= 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 @@ bool Sema::CheckParameterPacksForExpansion(
}
}
+ // 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;
}