r209786 - PR19878: If a pack expansion appears within another pack expansion, correctly
Richard Smith
richard-llvm at metafoo.co.uk
Wed May 28 18:12:14 PDT 2014
Author: rsmith
Date: Wed May 28 20:12:14 2014
New Revision: 209786
URL: http://llvm.org/viewvc/llvm-project?rev=209786&view=rev
Log:
PR19878: If a pack expansion appears within another pack expansion, correctly
deduce any packs that are expanded by both expansions.
Added:
cfe/trunk/test/SemaTemplate/pack-deduction.cpp
Modified:
cfe/trunk/include/clang/Sema/TemplateDeduction.h
cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
Modified: cfe/trunk/include/clang/Sema/TemplateDeduction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/TemplateDeduction.h?rev=209786&r1=209785&r2=209786&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/TemplateDeduction.h (original)
+++ cfe/trunk/include/clang/Sema/TemplateDeduction.h Wed May 28 20:12:14 2014
@@ -19,6 +19,7 @@
namespace clang {
+struct DeducedPack;
class TemplateArgumentList;
class Sema;
@@ -162,6 +163,11 @@ public:
/// an overloaded function which could not be resolved to a specific
/// function.
Expr *Expression;
+
+ /// \brief Information on packs that we're currently expanding.
+ ///
+ /// FIXME: This should be kept internal to SemaTemplateDeduction.
+ SmallVector<DeducedPack *, 8> PendingDeducedPacks;
};
} // end namespace sema
Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=209786&r1=209785&r2=209786&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Wed May 28 20:12:14 2014
@@ -297,6 +297,7 @@ checkDeducedTemplateArguments(ASTContext
XAEnd = X.pack_end(),
YA = Y.pack_begin();
XA != XAEnd; ++XA, ++YA) {
+ // FIXME: Do we need to merge the results together here?
if (checkDeducedTemplateArguments(Context,
DeducedTemplateArgument(*XA, X.wasDeducedFromArrayBound()),
DeducedTemplateArgument(*YA, Y.wasDeducedFromArrayBound()))
@@ -581,96 +582,181 @@ static TemplateParameter makeTemplatePar
return TemplateParameter(cast<TemplateTemplateParmDecl>(D));
}
-typedef SmallVector<SmallVector<DeducedTemplateArgument, 4>, 2>
- NewlyDeducedPacksType;
+/// A pack that we're currently deducing.
+struct clang::DeducedPack {
+ DeducedPack(unsigned Index) : Index(Index), Outer(nullptr) {}
+
+ // The index of the pack.
+ unsigned Index;
+
+ // The old value of the pack before we started deducing it.
+ DeducedTemplateArgument Saved;
+
+ // A deferred value of this pack from an inner deduction, that couldn't be
+ // deduced because this deduction hadn't happened yet.
+ DeducedTemplateArgument DeferredDeduction;
+
+ // The new value of the pack.
+ SmallVector<DeducedTemplateArgument, 4> New;
+
+ // The outer deduction for this pack, if any.
+ DeducedPack *Outer;
+};
+
+/// A scope in which we're performing pack deduction.
+class PackDeductionScope {
+public:
+ PackDeductionScope(Sema &S, TemplateParameterList *TemplateParams,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ TemplateDeductionInfo &Info, TemplateArgument Pattern)
+ : S(S), TemplateParams(TemplateParams), Deduced(Deduced), Info(Info) {
+ // Compute the set of template parameter indices that correspond to
+ // parameter packs expanded by the pack expansion.
+ {
+ llvm::SmallBitVector SawIndices(TemplateParams->size());
+ SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+ S.collectUnexpandedParameterPacks(Pattern, Unexpanded);
+ for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) {
+ unsigned Depth, Index;
+ std::tie(Depth, Index) = getDepthAndIndex(Unexpanded[I]);
+ if (Depth == 0 && !SawIndices[Index]) {
+ SawIndices[Index] = true;
-/// \brief Prepare to perform template argument deduction for all of the
-/// arguments in a set of argument packs.
-static void
-PrepareArgumentPackDeduction(Sema &S,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced,
- ArrayRef<unsigned> PackIndices,
- SmallVectorImpl<DeducedTemplateArgument> &SavedPacks,
- NewlyDeducedPacksType &NewlyDeducedPacks) {
- // Save the deduced template arguments for each parameter pack expanded
- // by this pack expansion, then clear out the deduction.
- for (unsigned I = 0, N = PackIndices.size(); I != N; ++I) {
- // Save the previously-deduced argument pack, then clear it out so that we
- // can deduce a new argument pack.
- SavedPacks[I] = Deduced[PackIndices[I]];
- Deduced[PackIndices[I]] = TemplateArgument();
+ // Save the deduced template argument for the parameter pack expanded
+ // by this pack expansion, then clear out the deduction.
+ DeducedPack Pack(Index);
+ Pack.Saved = Deduced[Index];
+ Deduced[Index] = TemplateArgument();
- if (!S.CurrentInstantiationScope)
- continue;
+ Packs.push_back(Pack);
+ }
+ }
+ }
+ assert(!Packs.empty() && "Pack expansion without unexpanded packs?");
+
+ for (auto &Pack : Packs) {
+ if (Info.PendingDeducedPacks.size() > Pack.Index)
+ Pack.Outer = Info.PendingDeducedPacks[Pack.Index];
+ else
+ Info.PendingDeducedPacks.resize(Pack.Index + 1);
+ Info.PendingDeducedPacks[Pack.Index] = &Pack;
- // If the template argument pack was explicitly specified, add that to
- // the set of deduced arguments.
- const TemplateArgument *ExplicitArgs;
- unsigned NumExplicitArgs;
- if (NamedDecl *PartiallySubstitutedPack
- = S.CurrentInstantiationScope->getPartiallySubstitutedPack(
- &ExplicitArgs,
- &NumExplicitArgs)) {
- if (getDepthAndIndex(PartiallySubstitutedPack).second == PackIndices[I])
- NewlyDeducedPacks[I].append(ExplicitArgs,
- ExplicitArgs + NumExplicitArgs);
+ if (S.CurrentInstantiationScope) {
+ // If the template argument pack was explicitly specified, add that to
+ // the set of deduced arguments.
+ const TemplateArgument *ExplicitArgs;
+ unsigned NumExplicitArgs;
+ NamedDecl *PartiallySubstitutedPack =
+ S.CurrentInstantiationScope->getPartiallySubstitutedPack(
+ &ExplicitArgs, &NumExplicitArgs);
+ if (PartiallySubstitutedPack &&
+ getDepthAndIndex(PartiallySubstitutedPack).second == Pack.Index)
+ Pack.New.append(ExplicitArgs, ExplicitArgs + NumExplicitArgs);
+ }
}
}
-}
-/// \brief Finish template argument deduction for a set of argument packs,
-/// producing the argument packs and checking for consistency with prior
-/// deductions.
-static Sema::TemplateDeductionResult
-FinishArgumentPackDeduction(Sema &S,
- TemplateParameterList *TemplateParams,
- bool HasAnyArguments,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced,
- ArrayRef<unsigned> PackIndices,
- SmallVectorImpl<DeducedTemplateArgument> &SavedPacks,
- NewlyDeducedPacksType &NewlyDeducedPacks,
- TemplateDeductionInfo &Info) {
- // Build argument packs for each of the parameter packs expanded by this
- // pack expansion.
- for (unsigned I = 0, N = PackIndices.size(); I != N; ++I) {
- if (HasAnyArguments && NewlyDeducedPacks[I].empty()) {
- // We were not able to deduce anything for this parameter pack,
- // so just restore the saved argument pack.
- Deduced[PackIndices[I]] = SavedPacks[I];
- continue;
+ ~PackDeductionScope() {
+ for (auto &Pack : Packs)
+ Info.PendingDeducedPacks[Pack.Index] = Pack.Outer;
+ }
+
+ /// Move to deducing the next element in each pack that is being deduced.
+ void nextPackElement() {
+ // Capture the deduced template arguments for each parameter pack expanded
+ // by this pack expansion, add them to the list of arguments we've deduced
+ // for that pack, then clear out the deduced argument.
+ for (auto &Pack : Packs) {
+ DeducedTemplateArgument &DeducedArg = Deduced[Pack.Index];
+ if (!DeducedArg.isNull()) {
+ Pack.New.push_back(DeducedArg);
+ DeducedArg = DeducedTemplateArgument();
+ }
}
+ }
+
+ /// \brief Finish template argument deduction for a set of argument packs,
+ /// producing the argument packs and checking for consistency with prior
+ /// deductions.
+ Sema::TemplateDeductionResult finish(bool HasAnyArguments) {
+ // Build argument packs for each of the parameter packs expanded by this
+ // pack expansion.
+ for (auto &Pack : Packs) {
+ // Put back the old value for this pack.
+ Deduced[Pack.Index] = Pack.Saved;
+
+ // Build or find a new value for this pack.
+ DeducedTemplateArgument NewPack;
+ if (HasAnyArguments && Pack.New.empty()) {
+ if (Pack.DeferredDeduction.isNull()) {
+ // We were not able to deduce anything for this parameter pack
+ // (because it only appeared in non-deduced contexts), so just
+ // restore the saved argument pack.
+ continue;
+ }
- DeducedTemplateArgument NewPack;
+ NewPack = Pack.DeferredDeduction;
+ Pack.DeferredDeduction = TemplateArgument();
+ } else if (Pack.New.empty()) {
+ // If we deduced an empty argument pack, create it now.
+ NewPack = DeducedTemplateArgument(TemplateArgument::getEmptyPack());
+ } else {
+ TemplateArgument *ArgumentPack =
+ new (S.Context) TemplateArgument[Pack.New.size()];
+ std::copy(Pack.New.begin(), Pack.New.end(), ArgumentPack);
+ NewPack = DeducedTemplateArgument(
+ TemplateArgument(ArgumentPack, Pack.New.size()),
+ Pack.New[0].wasDeducedFromArrayBound());
+ }
- if (NewlyDeducedPacks[I].empty()) {
- // If we deduced an empty argument pack, create it now.
- NewPack = DeducedTemplateArgument(TemplateArgument::getEmptyPack());
- } else {
- TemplateArgument *ArgumentPack
- = new (S.Context) TemplateArgument [NewlyDeducedPacks[I].size()];
- std::copy(NewlyDeducedPacks[I].begin(), NewlyDeducedPacks[I].end(),
- ArgumentPack);
- NewPack
- = DeducedTemplateArgument(TemplateArgument(ArgumentPack,
- NewlyDeducedPacks[I].size()),
- NewlyDeducedPacks[I][0].wasDeducedFromArrayBound());
- }
+ // Pick where we're going to put the merged pack.
+ DeducedTemplateArgument *Loc;
+ if (Pack.Outer) {
+ if (Pack.Outer->DeferredDeduction.isNull()) {
+ // Defer checking this pack until we have a complete pack to compare
+ // it against.
+ Pack.Outer->DeferredDeduction = NewPack;
+ continue;
+ }
+ Loc = &Pack.Outer->DeferredDeduction;
+ } else {
+ Loc = &Deduced[Pack.Index];
+ }
- DeducedTemplateArgument Result
- = checkDeducedTemplateArguments(S.Context, SavedPacks[I], NewPack);
- if (Result.isNull()) {
- Info.Param
- = makeTemplateParameter(TemplateParams->getParam(PackIndices[I]));
- Info.FirstArg = SavedPacks[I];
- Info.SecondArg = NewPack;
- return Sema::TDK_Inconsistent;
+ // Check the new pack matches any previous value.
+ DeducedTemplateArgument OldPack = *Loc;
+ DeducedTemplateArgument Result =
+ checkDeducedTemplateArguments(S.Context, OldPack, NewPack);
+
+ // If we deferred a deduction of this pack, check that one now too.
+ if (!Result.isNull() && !Pack.DeferredDeduction.isNull()) {
+ OldPack = Result;
+ NewPack = Pack.DeferredDeduction;
+ Result = checkDeducedTemplateArguments(S.Context, OldPack, NewPack);
+ }
+
+ if (Result.isNull()) {
+ Info.Param =
+ makeTemplateParameter(TemplateParams->getParam(Pack.Index));
+ Info.FirstArg = OldPack;
+ Info.SecondArg = NewPack;
+ return Sema::TDK_Inconsistent;
+ }
+
+ *Loc = Result;
}
- Deduced[PackIndices[I]] = Result;
+ return Sema::TDK_Success;
}
- return Sema::TDK_Success;
-}
+private:
+ Sema &S;
+ TemplateParameterList *TemplateParams;
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced;
+ TemplateDeductionInfo &Info;
+
+ SmallVector<DeducedPack, 2> Packs;
+};
/// \brief Deduce the template arguments by comparing the list of parameter
/// types to the list of argument types, as in the parameter-type-lists of
@@ -773,33 +859,8 @@ DeduceTemplateArguments(Sema &S,
// comparison deduces template arguments for subsequent positions in the
// template parameter packs expanded by the function parameter pack.
- // Compute the set of template parameter indices that correspond to
- // parameter packs expanded by the pack expansion.
- SmallVector<unsigned, 2> PackIndices;
QualType Pattern = Expansion->getPattern();
- {
- llvm::SmallBitVector SawIndices(TemplateParams->size());
- SmallVector<UnexpandedParameterPack, 2> Unexpanded;
- S.collectUnexpandedParameterPacks(Pattern, Unexpanded);
- for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) {
- unsigned Depth, Index;
- std::tie(Depth, Index) = getDepthAndIndex(Unexpanded[I]);
- if (Depth == 0 && !SawIndices[Index]) {
- SawIndices[Index] = true;
- PackIndices.push_back(Index);
- }
- }
- }
- assert(!PackIndices.empty() && "Pack expansion without unexpanded packs?");
-
- // Keep track of the deduced template arguments for each parameter pack
- // expanded by this pack expansion (the outer index) and for each
- // template argument (the inner SmallVectors).
- NewlyDeducedPacksType NewlyDeducedPacks(PackIndices.size());
- SmallVector<DeducedTemplateArgument, 2>
- SavedPacks(PackIndices.size());
- PrepareArgumentPackDeduction(S, Deduced, PackIndices, SavedPacks,
- NewlyDeducedPacks);
+ PackDeductionScope PackScope(S, TemplateParams, Deduced, Info, Pattern);
bool HasAnyArguments = false;
for (; ArgIdx < NumArgs; ++ArgIdx) {
@@ -813,24 +874,12 @@ DeduceTemplateArguments(Sema &S,
RefParamComparisons))
return Result;
- // Capture the deduced template arguments for each parameter pack expanded
- // by this pack expansion, add them to the list of arguments we've deduced
- // for that pack, then clear out the deduced argument.
- for (unsigned I = 0, N = PackIndices.size(); I != N; ++I) {
- DeducedTemplateArgument &DeducedArg = Deduced[PackIndices[I]];
- if (!DeducedArg.isNull()) {
- NewlyDeducedPacks[I].push_back(DeducedArg);
- DeducedArg = DeducedTemplateArgument();
- }
- }
+ PackScope.nextPackElement();
}
// Build argument packs for each of the parameter packs expanded by this
// pack expansion.
- if (Sema::TemplateDeductionResult Result
- = FinishArgumentPackDeduction(S, TemplateParams, HasAnyArguments,
- Deduced, PackIndices, SavedPacks,
- NewlyDeducedPacks, Info))
+ if (auto Result = PackScope.finish(HasAnyArguments))
return Result;
}
@@ -1852,41 +1901,18 @@ DeduceTemplateArguments(Sema &S,
// template parameter packs expanded by Pi.
TemplateArgument Pattern = Params[ParamIdx].getPackExpansionPattern();
- // Compute the set of template parameter indices that correspond to
- // parameter packs expanded by the pack expansion.
- SmallVector<unsigned, 2> PackIndices;
- {
- llvm::SmallBitVector SawIndices(TemplateParams->size());
- SmallVector<UnexpandedParameterPack, 2> Unexpanded;
- S.collectUnexpandedParameterPacks(Pattern, Unexpanded);
- for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) {
- unsigned Depth, Index;
- std::tie(Depth, Index) = getDepthAndIndex(Unexpanded[I]);
- if (Depth == 0 && !SawIndices[Index]) {
- SawIndices[Index] = true;
- PackIndices.push_back(Index);
- }
- }
- }
- assert(!PackIndices.empty() && "Pack expansion without unexpanded packs?");
-
// FIXME: If there are no remaining arguments, we can bail out early
// and set any deduced parameter packs to an empty argument pack.
// The latter part of this is a (minor) correctness issue.
- // Save the deduced template arguments for each parameter pack expanded
- // by this pack expansion, then clear out the deduction.
- SmallVector<DeducedTemplateArgument, 2>
- SavedPacks(PackIndices.size());
- NewlyDeducedPacksType NewlyDeducedPacks(PackIndices.size());
- PrepareArgumentPackDeduction(S, Deduced, PackIndices, SavedPacks,
- NewlyDeducedPacks);
+ // Prepare to deduce the packs within the pattern.
+ PackDeductionScope PackScope(S, TemplateParams, Deduced, Info, Pattern);
// Keep track of the deduced template arguments for each parameter pack
// expanded by this pack expansion (the outer index) and for each
// template argument (the inner SmallVectors).
bool HasAnyArguments = false;
- while (hasTemplateArgumentForDeduction(Args, ArgIdx, NumArgs)) {
+ for (; hasTemplateArgumentForDeduction(Args, ArgIdx, NumArgs); ++ArgIdx) {
HasAnyArguments = true;
// Deduce template arguments from the pattern.
@@ -1895,26 +1921,12 @@ DeduceTemplateArguments(Sema &S,
Info, Deduced))
return Result;
- // Capture the deduced template arguments for each parameter pack expanded
- // by this pack expansion, add them to the list of arguments we've deduced
- // for that pack, then clear out the deduced argument.
- for (unsigned I = 0, N = PackIndices.size(); I != N; ++I) {
- DeducedTemplateArgument &DeducedArg = Deduced[PackIndices[I]];
- if (!DeducedArg.isNull()) {
- NewlyDeducedPacks[I].push_back(DeducedArg);
- DeducedArg = DeducedTemplateArgument();
- }
- }
-
- ++ArgIdx;
+ PackScope.nextPackElement();
}
// Build argument packs for each of the parameter packs expanded by this
// pack expansion.
- if (Sema::TemplateDeductionResult Result
- = FinishArgumentPackDeduction(S, TemplateParams, HasAnyArguments,
- Deduced, PackIndices, SavedPacks,
- NewlyDeducedPacks, Info))
+ if (auto Result = PackScope.finish(HasAnyArguments))
return Result;
}
@@ -3403,30 +3415,9 @@ Sema::TemplateDeductionResult Sema::Dedu
break;
QualType ParamPattern = ParamExpansion->getPattern();
- SmallVector<unsigned, 2> PackIndices;
- {
- llvm::SmallBitVector SawIndices(TemplateParams->size());
- SmallVector<UnexpandedParameterPack, 2> Unexpanded;
- collectUnexpandedParameterPacks(ParamPattern, Unexpanded);
- for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) {
- unsigned Depth, Index;
- std::tie(Depth, Index) = getDepthAndIndex(Unexpanded[I]);
- if (Depth == 0 && !SawIndices[Index]) {
- SawIndices[Index] = true;
- PackIndices.push_back(Index);
- }
- }
- }
- assert(!PackIndices.empty() && "Pack expansion without unexpanded packs?");
+ PackDeductionScope PackScope(*this, TemplateParams, Deduced, Info,
+ ParamPattern);
- // Keep track of the deduced template arguments for each parameter pack
- // expanded by this pack expansion (the outer index) and for each
- // template argument (the inner SmallVectors).
- NewlyDeducedPacksType NewlyDeducedPacks(PackIndices.size());
- SmallVector<DeducedTemplateArgument, 2>
- SavedPacks(PackIndices.size());
- PrepareArgumentPackDeduction(*this, Deduced, PackIndices, SavedPacks,
- NewlyDeducedPacks);
bool HasAnyArguments = false;
for (; ArgIdx < Args.size(); ++ArgIdx) {
HasAnyArguments = true;
@@ -3435,7 +3426,7 @@ Sema::TemplateDeductionResult Sema::Dedu
ParamType = OrigParamType;
Expr *Arg = Args[ArgIdx];
QualType ArgType = Arg->getType();
-
+
unsigned TDF = 0;
if (AdjustFunctionParmAndArgTypesForDeduction(*this, TemplateParams,
ParamType, ArgType, Arg,
@@ -3476,24 +3467,12 @@ Sema::TemplateDeductionResult Sema::Dedu
return Result;
}
- // Capture the deduced template arguments for each parameter pack expanded
- // by this pack expansion, add them to the list of arguments we've deduced
- // for that pack, then clear out the deduced argument.
- for (unsigned I = 0, N = PackIndices.size(); I != N; ++I) {
- DeducedTemplateArgument &DeducedArg = Deduced[PackIndices[I]];
- if (!DeducedArg.isNull()) {
- NewlyDeducedPacks[I].push_back(DeducedArg);
- DeducedArg = DeducedTemplateArgument();
- }
- }
+ PackScope.nextPackElement();
}
// Build argument packs for each of the parameter packs expanded by this
// pack expansion.
- if (Sema::TemplateDeductionResult Result
- = FinishArgumentPackDeduction(*this, TemplateParams, HasAnyArguments,
- Deduced, PackIndices, SavedPacks,
- NewlyDeducedPacks, Info))
+ if (auto Result = PackScope.finish(HasAnyArguments))
return Result;
// After we've matching against a parameter pack, we're done.
@@ -4240,7 +4219,7 @@ static bool isAtLeastAsSpecializedAs(Sem
Args1.data(), Args1.size(), Info, Deduced,
TDF_None, /*PartialOrdering=*/true,
RefParamComparisons))
- return false;
+ return false;
break;
}
Added: cfe/trunk/test/SemaTemplate/pack-deduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/pack-deduction.cpp?rev=209786&view=auto
==============================================================================
--- cfe/trunk/test/SemaTemplate/pack-deduction.cpp (added)
+++ cfe/trunk/test/SemaTemplate/pack-deduction.cpp Wed May 28 20:12:14 2014
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+
+template<typename ...T> struct X {};
+
+template<typename T, typename U> struct P {};
+
+namespace Nested {
+ template<typename ...T> int f1(X<T, T...>... a); // expected-note +{{conflicting types for parameter 'T'}}
+ template<typename ...T> int f2(P<X<T...>, T> ...a); // expected-note +{{conflicting types for parameter 'T'}}
+
+ int a1 = f1(X<int, int, double>(), X<double, int, double>());
+ int a2 = f1(X<int, int>());
+ int a3 = f1(X<int>(), X<double>()); // expected-error {{no matching}}
+ int a4 = f1(X<int, int>(), X<int>()); // expected-error {{no matching}}
+ int a5 = f1(X<int>(), X<int, int>()); // expected-error {{no matching}}
+ int a6 = f1(X<int, int, int>(), X<int, int, int>(), X<int, int, int, int>()); // expected-error {{no matching}}
+
+ int b1 = f2(P<X<int, double>, int>(), P<X<int, double>, double>());
+ int b2 = f2(P<X<int, double>, int>(), P<X<int, double>, double>(), P<X<int, double>, char>()); // expected-error {{no matching}}
+}
More information about the cfe-commits
mailing list