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