]> granicus.if.org Git - clang/commitdiff
PR9023: A template template parameter whose template parameter list contains an
authorRichard Smith <richard-llvm@metafoo.co.uk>
Fri, 7 Sep 2012 02:06:42 +0000 (02:06 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Fri, 7 Sep 2012 02:06:42 +0000 (02:06 +0000)
unexpanded parameter pack is a pack expansion. Thus, as with a non-type template
parameter which is a pack expansion, it needs to be expanded early into a fixed
list of template parameters.

Since the expanded list of template parameters is not itself a parameter pack,
it is permitted to appear before the end of the template parameter list, so also
remove that restriction (for both template template parameter pack expansions and
non-type template parameter pack expansions).

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@163369 91177308-0d34-0410-b5e6-96231b3b80d8

12 files changed:
include/clang/AST/DeclTemplate.h
include/clang/Sema/Sema.h
include/clang/Serialization/ASTBitCodes.h
lib/AST/DeclTemplate.cpp
lib/Sema/SemaTemplate.cpp
lib/Sema/SemaTemplateDeduction.cpp
lib/Sema/SemaTemplateInstantiateDecl.cpp
lib/Serialization/ASTReaderDecl.cpp
lib/Serialization/ASTWriterDecl.cpp
test/CXX/temp/temp.param/p15-cxx0x.cpp
test/PCH/cxx-variadic-templates.cpp
test/PCH/cxx-variadic-templates.h

index 7affc7e15f27152fa7ab618dbc9731782beb9cac..3cff5b07c4a87e0217f5a90bc64c0fa38d74fd1e 100644 (file)
@@ -50,7 +50,11 @@ class TemplateParameterList {
 
   /// The number of template parameters in this template
   /// parameter list.
-  unsigned NumParams;
+  unsigned NumParams : 31;
+
+  /// Whether this template parameter list contains an unexpanded parameter
+  /// pack.
+  unsigned ContainsUnexpandedParameterPack : 1;
 
 protected:
   TemplateParameterList(SourceLocation TemplateLoc, SourceLocation LAngleLoc,
@@ -104,6 +108,12 @@ public:
   /// the second template parameter list will have depth 1, etc.
   unsigned getDepth() const;
 
+  /// \brief Determine whether this template parameter list contains an
+  /// unexpanded parameter pack.
+  bool containsUnexpandedParameterPack() const {
+    return ContainsUnexpandedParameterPack;
+  }
+
   SourceLocation getTemplateLoc() const { return TemplateLoc; }
   SourceLocation getLAngleLoc() const { return LAngleLoc; }
   SourceLocation getRAngleLoc() const { return RAngleLoc; }
@@ -1090,8 +1100,17 @@ public:
   /// \endcode
   bool isParameterPack() const { return ParameterPack; }
 
+  /// \brief Whether this parameter pack is a pack expansion.
+  ///
+  /// A non-type template parameter pack is a pack expansion if its type
+  /// contains an unexpanded parameter pack. In this case, we will have
+  /// built a PackExpansionType wrapping the type.
+  bool isPackExpansion() const {
+    return ParameterPack && getType()->getAs<PackExpansionType>();
+  }
+
   /// \brief Whether this parameter is a non-type template parameter pack
-  /// that has different types at different positions.
+  /// that has a known list of different types at different positions.
   ///
   /// A parameter pack is an expanded parameter pack when the original
   /// parameter pack's type was itself a pack expansion, and that expansion
@@ -1165,23 +1184,47 @@ class TemplateTemplateParmDecl : public TemplateDecl,
   /// \brief Whether this parameter is a parameter pack.
   bool ParameterPack;
 
+  /// \brief Whether this template template parameter is an "expanded"
+  /// parameter pack, meaning that it is a pack expansion and we
+  /// already know the set of template parameters that expansion expands to.
+  bool ExpandedParameterPack;
+
+  /// \brief The number of parameters in an expanded parameter pack.
+  unsigned NumExpandedParams;
+
   TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L,
                            unsigned D, unsigned P, bool ParameterPack,
                            IdentifierInfo *Id, TemplateParameterList *Params)
     : TemplateDecl(TemplateTemplateParm, DC, L, Id, Params),
       TemplateParmPosition(D, P), DefaultArgument(),
-      DefaultArgumentWasInherited(false), ParameterPack(ParameterPack)
+      DefaultArgumentWasInherited(false), ParameterPack(ParameterPack),
+      ExpandedParameterPack(false), NumExpandedParams(0)
     { }
 
+  TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L,
+                           unsigned D, unsigned P,
+                           IdentifierInfo *Id, TemplateParameterList *Params,
+                           unsigned NumExpansions,
+                           TemplateParameterList * const *Expansions);
+
 public:
   static TemplateTemplateParmDecl *Create(const ASTContext &C, DeclContext *DC,
                                           SourceLocation L, unsigned D,
                                           unsigned P, bool ParameterPack,
                                           IdentifierInfo *Id,
                                           TemplateParameterList *Params);
+  static TemplateTemplateParmDecl *Create(const ASTContext &C, DeclContext *DC,
+                                          SourceLocation L, unsigned D,
+                                          unsigned P,
+                                          IdentifierInfo *Id,
+                                          TemplateParameterList *Params,
+                             llvm::ArrayRef<TemplateParameterList*> Expansions);
 
-  static TemplateTemplateParmDecl *CreateDeserialized(ASTContext &C, 
+  static TemplateTemplateParmDecl *CreateDeserialized(ASTContext &C,
                                                       unsigned ID);
+  static TemplateTemplateParmDecl *CreateDeserialized(ASTContext &C,
+                                                      unsigned ID,
+                                                      unsigned NumExpansions);
   
   using TemplateParmPosition::getDepth;
   using TemplateParmPosition::getPosition;
@@ -1195,6 +1238,49 @@ public:
   /// \endcode
   bool isParameterPack() const { return ParameterPack; }
 
+  /// \brief Whether this parameter pack is a pack expansion.
+  ///
+  /// A template template parameter pack is a pack expansion if its template
+  /// parameter list contains an unexpanded parameter pack.
+  bool isPackExpansion() const {
+    return ParameterPack &&
+           getTemplateParameters()->containsUnexpandedParameterPack();
+  }
+
+  /// \brief Whether this parameter is a template template parameter pack that
+  /// has a known list of different template parameter lists at different
+  /// positions.
+  ///
+  /// A parameter pack is an expanded parameter pack when the original parameter
+  /// pack's template parameter list was itself a pack expansion, and that
+  /// expansion has already been expanded. For exampe, given:
+  ///
+  /// \code
+  /// template<typename...Types> struct Outer {
+  ///   template<template<Types> class...Templates> struct Inner;
+  /// };
+  /// \endcode
+  ///
+  /// The parameter pack \c Templates is a pack expansion, which expands the
+  /// pack \c Types. When \c Types is supplied with template arguments by
+  /// instantiating \c Outer, the instantiation of \c Templates is an expanded
+  /// parameter pack.
+  bool isExpandedParameterPack() const { return ExpandedParameterPack; }
+
+  /// \brief Retrieves the number of expansion template parameters in
+  /// an expanded parameter pack.
+  unsigned getNumExpansionTemplateParameters() const {
+    assert(ExpandedParameterPack && "Not an expansion parameter pack");
+    return NumExpandedParams;
+  }
+
+  /// \brief Retrieve a particular expansion type within an expanded parameter
+  /// pack.
+  TemplateParameterList *getExpansionTemplateParameters(unsigned I) const {
+    assert(I < NumExpandedParams && "Out-of-range expansion type index");
+    return reinterpret_cast<TemplateParameterList *const *>(this + 1)[I];
+  }
+
   /// \brief Determine whether this template parameter has a default
   /// argument.
   bool hasDefaultArgument() const {
index 919bd6883eeefddcd1f3e03b77f4198c3a99df4b..97733d37e37f934af17b673e0dd3213dc2185e65 100644 (file)
@@ -4832,7 +4832,8 @@ public:
                                    TemplateArgument &Converted,
                                CheckTemplateArgumentKind CTAK = CTAK_Specified);
   bool CheckTemplateArgument(TemplateTemplateParmDecl *Param,
-                             const TemplateArgumentLoc &Arg);
+                             const TemplateArgumentLoc &Arg,
+                             unsigned ArgumentPackIndex);
 
   ExprResult
   BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg,
index f2134134ae8d972f338fea78815c8d84b2f7e773..e714da771bf09796e21c644b6da53bb7c9b7bbe9 100644 (file)
@@ -945,6 +945,9 @@ namespace clang {
       /// \brief A NonTypeTemplateParmDecl record that stores an expanded
       /// non-type template parameter pack.
       DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK,
+      /// \brief A TemplateTemplateParmDecl record that stores an expanded
+      /// template template parameter pack.
+      DECL_EXPANDED_TEMPLATE_TEMPLATE_PARM_PACK,
       /// \brief A ClassScopeFunctionSpecializationDecl record a class scope
       /// function specialization. (Microsoft extension).
       DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION,
index a7e89994afe847caeb87b1d0cf2884b2c5f99796..fc31d2f55bed9acc88d4218e02d181b6ae23938f 100644 (file)
@@ -32,9 +32,25 @@ TemplateParameterList::TemplateParameterList(SourceLocation TemplateLoc,
                                              NamedDecl **Params, unsigned NumParams,
                                              SourceLocation RAngleLoc)
   : TemplateLoc(TemplateLoc), LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc),
-    NumParams(NumParams) {
-  for (unsigned Idx = 0; Idx < NumParams; ++Idx)
-    begin()[Idx] = Params[Idx];
+    NumParams(NumParams), ContainsUnexpandedParameterPack(false) {
+  assert(this->NumParams == NumParams && "Too many template parameters");
+  for (unsigned Idx = 0; Idx < NumParams; ++Idx) {
+    NamedDecl *P = Params[Idx];
+    begin()[Idx] = P;
+
+    if (!P->isTemplateParameterPack()) {
+      if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(P))
+        if (NTTP->getType()->containsUnexpandedParameterPack())
+          ContainsUnexpandedParameterPack = true;
+
+      if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(P))
+        if (TTP->getTemplateParameters()->containsUnexpandedParameterPack())
+          ContainsUnexpandedParameterPack = true;
+
+      // FIXME: If a default argument contains an unexpanded parameter pack, the
+      // template parameter list does too.
+    }
+  }
 }
 
 TemplateParameterList *
@@ -577,6 +593,19 @@ SourceLocation NonTypeTemplateParmDecl::getDefaultArgumentLoc() const {
 
 void TemplateTemplateParmDecl::anchor() { }
 
+TemplateTemplateParmDecl::TemplateTemplateParmDecl(
+    DeclContext *DC, SourceLocation L, unsigned D, unsigned P,
+    IdentifierInfo *Id, TemplateParameterList *Params,
+    unsigned NumExpansions, TemplateParameterList * const *Expansions)
+  : TemplateDecl(TemplateTemplateParm, DC, L, Id, Params),
+    TemplateParmPosition(D, P), DefaultArgument(),
+    DefaultArgumentWasInherited(false), ParameterPack(true),
+    ExpandedParameterPack(true), NumExpandedParams(NumExpansions) {
+  if (Expansions)
+    std::memcpy(reinterpret_cast<void*>(this + 1), Expansions,
+                sizeof(TemplateParameterList*) * NumExpandedParams);
+}
+
 TemplateTemplateParmDecl *
 TemplateTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC,
                                  SourceLocation L, unsigned D, unsigned P,
@@ -586,6 +615,19 @@ TemplateTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC,
                                           Params);
 }
 
+TemplateTemplateParmDecl *
+TemplateTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC,
+                                 SourceLocation L, unsigned D, unsigned P,
+                                 IdentifierInfo *Id,
+                                 TemplateParameterList *Params,
+                            llvm::ArrayRef<TemplateParameterList*> Expansions) {
+  void *Mem = C.Allocate(sizeof(TemplateTemplateParmDecl) +
+                         sizeof(TemplateParameterList*) * Expansions.size());
+  return new (Mem) TemplateTemplateParmDecl(DC, L, D, P, Id, Params,
+                                            Expansions.size(),
+                                            Expansions.data());
+}
+
 TemplateTemplateParmDecl *
 TemplateTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
   void *Mem = AllocateDeserializedDecl(C, ID, sizeof(TemplateTemplateParmDecl));
@@ -593,6 +635,16 @@ TemplateTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
                                             0, 0);
 }
 
+TemplateTemplateParmDecl *
+TemplateTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID,
+                                             unsigned NumExpansions) {
+  unsigned Size = sizeof(TemplateTemplateParmDecl) +
+                  sizeof(TemplateParameterList*) * NumExpansions;
+  void *Mem = AllocateDeserializedDecl(C, ID, Size);
+  return new (Mem) TemplateTemplateParmDecl(0, SourceLocation(), 0, 0, 0, 0,
+                                            NumExpansions, 0);
+}
+
 //===----------------------------------------------------------------------===//
 // TemplateArgumentList Implementation
 //===----------------------------------------------------------------------===//
index d6ad8ebf53506c10b4a50799be7f0dab5bd208fe..1e81f0d2996ae63cc0b08e7c632c5f3f2fc5f819 100644 (file)
@@ -1205,11 +1205,17 @@ static bool DiagnoseDefaultTemplateArgument(Sema &S,
 /// of a template template parameter, recursively.
 static bool DiagnoseUnexpandedParameterPacks(Sema &S,
                                              TemplateTemplateParmDecl *TTP) {
+  // A template template parameter which is a parameter pack is also a pack
+  // expansion.
+  if (TTP->isParameterPack())
+    return false;
+
   TemplateParameterList *Params = TTP->getTemplateParameters();
   for (unsigned I = 0, N = Params->size(); I != N; ++I) {
     NamedDecl *P = Params->getParam(I);
     if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(P)) {
-      if (S.DiagnoseUnexpandedParameterPack(NTTP->getLocation(),
+      if (!NTTP->isParameterPack() &&
+          S.DiagnoseUnexpandedParameterPack(NTTP->getLocation(),
                                             NTTP->getTypeSourceInfo(),
                                       Sema::UPPC_NonTypeTemplateParameterType))
         return true;
@@ -1322,7 +1328,8 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
     } else if (NonTypeTemplateParmDecl *NewNonTypeParm
                = dyn_cast<NonTypeTemplateParmDecl>(*NewParam)) {
       // Check for unexpanded parameter packs.
-      if (DiagnoseUnexpandedParameterPack(NewNonTypeParm->getLocation(),
+      if (!NewNonTypeParm->isParameterPack() &&
+          DiagnoseUnexpandedParameterPack(NewNonTypeParm->getLocation(),
                                           NewNonTypeParm->getTypeSourceInfo(),
                                           UPPC_NonTypeTemplateParameterType)) {
         Invalid = true;
@@ -1343,7 +1350,8 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
       if (NewNonTypeParm->isParameterPack()) {
         assert(!NewNonTypeParm->hasDefaultArgument() &&
                "Parameter packs can't have a default argument!");
-        SawParameterPack = true;
+        if (!NewNonTypeParm->isPackExpansion())
+          SawParameterPack = true;
       } else if (OldNonTypeParm && OldNonTypeParm->hasDefaultArgument() &&
           NewNonTypeParm->hasDefaultArgument()) {
         OldDefaultLoc = OldNonTypeParm->getDefaultArgumentLoc();
@@ -1390,7 +1398,8 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
       if (NewTemplateParm->isParameterPack()) {
         assert(!NewTemplateParm->hasDefaultArgument() &&
                "Parameter packs can't have a default argument!");
-        SawParameterPack = true;
+        if (!NewTemplateParm->isPackExpansion())
+          SawParameterPack = true;
       } else if (OldTemplateParm && OldTemplateParm->hasDefaultArgument() &&
           NewTemplateParm->hasDefaultArgument()) {
         OldDefaultLoc = OldTemplateParm->getDefaultArgument().getLocation();
@@ -1417,10 +1426,10 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
         MissingDefaultArg = true;
     }
 
-    // C++0x [temp.param]p11:
+    // C++11 [temp.param]p11:
     //   If a template parameter of a primary class template or alias template
     //   is a template parameter pack, it shall be the last template parameter.
-    if (SawParameterPack && (NewParam + 1) != NewParamEnd && 
+    if (SawParameterPack && (NewParam + 1) != NewParamEnd &&
         (TPC == TPC_ClassTemplate || TPC == TPC_TypeAliasTemplate)) {
       Diag((*NewParam)->getLocation(),
            diag::err_template_param_pack_must_be_last_template_parameter);
@@ -2950,7 +2959,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
 
   case TemplateArgument::Template:
   case TemplateArgument::TemplateExpansion:
-    if (CheckTemplateArgument(TempParm, Arg))
+    if (CheckTemplateArgument(TempParm, Arg, ArgumentPackIndex))
       return true;
 
     Converted.push_back(Arg.getArgument());
@@ -2999,6 +3008,33 @@ static bool diagnoseArityMismatch(Sema &S, TemplateDecl *Template,
   return true;
 }
 
+/// \brief Check whether the template parameter is a pack expansion, and if so,
+/// determine the number of parameters produced by that expansion. For instance:
+///
+/// \code
+/// template<typename ...Ts> struct A {
+///   template<Ts ...NTs, template<Ts> class ...TTs, typename ...Us> struct B;
+/// };
+/// \endcode
+///
+/// In \c A<int,int>::B, \c NTs and \c TTs have expanded pack size 2, and \c Us
+/// is not a pack expansion, so returns an empty Optional.
+static llvm::Optional<unsigned> getExpandedPackSize(NamedDecl *Param) {
+  if (NonTypeTemplateParmDecl *NTTP
+        = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
+    if (NTTP->isExpandedParameterPack())
+      return NTTP->getNumExpansionTypes();
+  }
+
+  if (TemplateTemplateParmDecl *TTP
+        = dyn_cast<TemplateTemplateParmDecl>(Param)) {
+    if (TTP->isExpandedParameterPack())
+      return TTP->getNumExpansionTemplateParameters();
+  }
+
+  return llvm::Optional<unsigned>();
+}
+
 /// \brief Check that the given template argument list is well-formed
 /// for specializing the given template.
 bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
@@ -3011,15 +3047,9 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
     *ExpansionIntoFixedList = false;
 
   TemplateParameterList *Params = Template->getTemplateParameters();
-  unsigned NumParams = Params->size();
-  unsigned NumArgs = TemplateArgs.size();
-  bool Invalid = false;
 
   SourceLocation RAngleLoc = TemplateArgs.getRAngleLoc();
 
-  bool HasParameterPack =
-    NumParams > 0 && Params->getParam(NumParams - 1)->isTemplateParameterPack();
-  
   // C++ [temp.arg]p1:
   //   [...] The type and form of each template-argument specified in
   //   a template-id shall match the type and form specified for the
@@ -3027,38 +3057,53 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
   //   template-parameter-list.
   bool isTemplateTemplateParameter = isa<TemplateTemplateParmDecl>(Template);
   SmallVector<TemplateArgument, 2> ArgumentPack;
-  TemplateParameterList::iterator Param = Params->begin(),
-                               ParamEnd = Params->end();
-  unsigned ArgIdx = 0;
+  unsigned ArgIdx = 0, NumArgs = TemplateArgs.size();
   LocalInstantiationScope InstScope(*this, true);
-  bool SawPackExpansion = false;
-  while (Param != ParamEnd) {
-    if (ArgIdx < NumArgs) {
-      // If we have an expanded parameter pack, make sure we don't have too
-      // many arguments.
-      // FIXME: This really should fall out from the normal arity checking.
-      if (NonTypeTemplateParmDecl *NTTP
-                                = dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
-        if (NTTP->isExpandedParameterPack() &&
-            ArgumentPack.size() >= NTTP->getNumExpansionTypes()) {
-          Diag(TemplateLoc, diag::err_template_arg_list_different_arity)
-            << true
-            << (isa<ClassTemplateDecl>(Template)? 0 :
-                isa<FunctionTemplateDecl>(Template)? 1 :
-                isa<TemplateTemplateParmDecl>(Template)? 2 : 3)
-            << Template;
-          Diag(Template->getLocation(), diag::note_template_decl_here)
-            << Params->getSourceRange();
-          return true;
+  for (TemplateParameterList::iterator Param = Params->begin(),
+                                       ParamEnd = Params->end();
+       Param != ParamEnd; /* increment in loop */) {
+    // If we have an expanded parameter pack, make sure we don't have too
+    // many arguments.
+    if (llvm::Optional<unsigned> Expansions = getExpandedPackSize(*Param)) {
+      if (*Expansions == ArgumentPack.size()) {
+        // We're done with this parameter pack. Pack up its arguments and add
+        // them to the list.
+        if (ArgumentPack.empty())
+          Converted.push_back(TemplateArgument(0, 0));
+        else {
+          Converted.push_back(
+            TemplateArgument::CreatePackCopy(Context,
+                                             ArgumentPack.data(),
+                                             ArgumentPack.size()));
+          ArgumentPack.clear();
         }
+        // This argument is assigned to the next parameter.
+        ++Param;
+        continue;
+      } else if (ArgIdx == NumArgs && !PartialTemplateArgs) {
+        // Not enough arguments for this parameter pack.
+        Diag(TemplateLoc, diag::err_template_arg_list_different_arity)
+          << false
+          << (isa<ClassTemplateDecl>(Template)? 0 :
+              isa<FunctionTemplateDecl>(Template)? 1 :
+              isa<TemplateTemplateParmDecl>(Template)? 2 : 3)
+          << Template;
+        Diag(Template->getLocation(), diag::note_template_decl_here)
+          << Params->getSourceRange();
+        return true;
       }
+    }
 
+    if (ArgIdx < NumArgs) {
       // Check the template argument we were given.
       if (CheckTemplateArgument(*Param, TemplateArgs[ArgIdx], Template,
                                 TemplateLoc, RAngleLoc,
                                 ArgumentPack.size(), Converted))
         return true;
 
+      // We're now done with this argument.
+      ++ArgIdx;
+
       if ((*Param)->isTemplateParameterPack()) {
         // The template parameter was a template parameter pack, so take the
         // deduced argument and place it on the argument pack. Note that we
@@ -3070,16 +3115,51 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
         // Move to the next template parameter.
         ++Param;
       }
-      
-      // If this template argument is a pack expansion, record that fact
-      // and break out; we can't actually check any more.
-      if (TemplateArgs[ArgIdx].getArgument().isPackExpansion()) {
-        SawPackExpansion = true;
-        ++ArgIdx;
-        break;
+
+      // If we just saw a pack expansion, then directly convert the remaining
+      // arguments, because we don't know what parameters they'll match up
+      // with.
+      if (TemplateArgs[ArgIdx-1].getArgument().isPackExpansion()) {
+        bool InFinalParameterPack = Param != ParamEnd &&
+                                    Param + 1 == ParamEnd &&
+                                    (*Param)->isTemplateParameterPack() &&
+                                    !getExpandedPackSize(*Param);
+
+        if (!InFinalParameterPack && !ArgumentPack.empty()) {
+          // If we were part way through filling in an expanded parameter pack,
+          // fall back to just producing individual arguments.
+          Converted.insert(Converted.end(),
+                           ArgumentPack.begin(), ArgumentPack.end());
+          ArgumentPack.clear();
+        }
+
+        while (ArgIdx < NumArgs) {
+          if (InFinalParameterPack)
+            ArgumentPack.push_back(TemplateArgs[ArgIdx].getArgument());
+          else
+            Converted.push_back(TemplateArgs[ArgIdx].getArgument());
+          ++ArgIdx;
+        }
+
+        // Push the argument pack onto the list of converted arguments.
+        if (InFinalParameterPack) {
+          if (ArgumentPack.empty())
+            Converted.push_back(TemplateArgument(0, 0));
+          else {
+            Converted.push_back(
+              TemplateArgument::CreatePackCopy(Context,
+                                               ArgumentPack.data(),
+                                               ArgumentPack.size()));
+            ArgumentPack.clear();
+          }
+        } else if (ExpansionIntoFixedList) {
+          // We have expanded a pack into a fixed list.
+          *ExpansionIntoFixedList = true;
+        }
+
+        return false;
       }
-      
-      ++ArgIdx;
+
       continue;
     }
 
@@ -3090,14 +3170,34 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
                                                          ArgumentPack.data(),
                                                          ArgumentPack.size()));
         
-      return Invalid;
+      return false;
     }
 
     // If we have a template parameter pack with no more corresponding
     // arguments, just break out now and we'll fill in the argument pack below.
-    if ((*Param)->isTemplateParameterPack())
-      break;
-    
+    if ((*Param)->isTemplateParameterPack()) {
+      assert(!getExpandedPackSize(*Param) &&
+             "Should have dealt with this already");
+
+      // A non-expanded parameter pack before the end of the parameter list
+      // only occurs for an ill-formed template parameter list, unless we've
+      // got a partial argument list for a function template, so just bail out.
+      if (Param + 1 != ParamEnd)
+        return true;
+
+      if (ArgumentPack.empty())
+        Converted.push_back(TemplateArgument(0, 0));
+      else {
+        Converted.push_back(TemplateArgument::CreatePackCopy(Context,
+                                                         ArgumentPack.data(),
+                                                         ArgumentPack.size()));
+        ArgumentPack.clear();
+      }
+
+      ++Param;
+      continue;
+    }
+
     // Check whether we have a default argument.
     TemplateArgumentLoc Arg;
 
@@ -3184,86 +3284,12 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
     ++ArgIdx;
   }
 
-  // If we saw a pack expansion, then directly convert the remaining arguments,
-  // because we don't know what parameters they'll match up with.
-  if (SawPackExpansion) {
-    bool AddToArgumentPack
-      = Param != ParamEnd && (*Param)->isTemplateParameterPack();
-    while (ArgIdx < NumArgs) {
-      if (AddToArgumentPack)
-        ArgumentPack.push_back(TemplateArgs[ArgIdx].getArgument());
-      else
-        Converted.push_back(TemplateArgs[ArgIdx].getArgument());
-      ++ArgIdx;
-    }
-
-    // Push the argument pack onto the list of converted arguments.
-    if (AddToArgumentPack) {
-      if (ArgumentPack.empty())
-        Converted.push_back(TemplateArgument(0, 0));
-      else {
-        Converted.push_back(
-          TemplateArgument::CreatePackCopy(Context,
-                                           ArgumentPack.data(),
-                                           ArgumentPack.size()));
-        ArgumentPack.clear();
-      }      
-    } else if (ExpansionIntoFixedList) {
-      // We have expanded a pack into a fixed list.
-      *ExpansionIntoFixedList = true;
-    }
-
-    return Invalid;
-  }
-
   // If we have any leftover arguments, then there were too many arguments.
   // Complain and fail.
   if (ArgIdx < NumArgs)
     return diagnoseArityMismatch(*this, Template, TemplateLoc, TemplateArgs);
-  
-  // If we have an expanded parameter pack, make sure we don't have too
-  // many arguments.
-  // FIXME: This really should fall out from the normal arity checking.
-  if (Param != ParamEnd) {
-    if (NonTypeTemplateParmDecl *NTTP
-          = dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
-      if (NTTP->isExpandedParameterPack() &&
-          ArgumentPack.size() < NTTP->getNumExpansionTypes()) {
-        Diag(TemplateLoc, diag::err_template_arg_list_different_arity)
-          << false
-          << (isa<ClassTemplateDecl>(Template)? 0 :
-              isa<FunctionTemplateDecl>(Template)? 1 :
-              isa<TemplateTemplateParmDecl>(Template)? 2 : 3)
-          << Template;
-        Diag(Template->getLocation(), diag::note_template_decl_here)
-          << Params->getSourceRange();
-        return true;
-      }
-    }
-  }
-  
-  // Form argument packs for each of the parameter packs remaining.
-  while (Param != ParamEnd) {
-    // If we're checking a partial list of template arguments, don't fill
-    // in arguments for non-template parameter packs.
-    if ((*Param)->isTemplateParameterPack()) {
-      if (!HasParameterPack)
-        return true;
-      if (ArgumentPack.empty())
-        Converted.push_back(TemplateArgument(0, 0));
-      else {
-        Converted.push_back(TemplateArgument::CreatePackCopy(Context,
-                                                          ArgumentPack.data(),
-                                                         ArgumentPack.size()));
-        ArgumentPack.clear();
-      }
-    } else if (!PartialTemplateArgs)
-      return diagnoseArityMismatch(*this, Template, TemplateLoc, TemplateArgs);
 
-    ++Param;
-  }
-
-  return Invalid;
+  return false;
 }
 
 namespace {
@@ -4420,7 +4446,8 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
 /// This routine implements the semantics of C++ [temp.arg.template].
 /// It returns true if an error occurred, and false otherwise.
 bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param,
-                                 const TemplateArgumentLoc &Arg) {
+                                 const TemplateArgumentLoc &Arg,
+                                 unsigned ArgumentPackIndex) {
   TemplateName Name = Arg.getArgument().getAsTemplate();
   TemplateDecl *Template = Name.getAsTemplateDecl();
   if (!Template) {
@@ -4451,8 +4478,12 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param,
       << Template;
   }
 
+  TemplateParameterList *Params = Param->getTemplateParameters();
+  if (Param->isExpandedParameterPack())
+    Params = Param->getExpansionTemplateParameters(ArgumentPackIndex);
+
   return !TemplateParameterListsAreEqual(Template->getTemplateParameters(),
-                                         Param->getTemplateParameters(),
+                                         Params,
                                          true,
                                          TPL_TemplateTemplateArgumentMatch,
                                          Arg.getLocation());
index b8f0bca2969ebe71eb566d5fe94f81ce745dc2e2..b236f2861e088900652dc3f31b3fe881bd33e281 100644 (file)
@@ -573,7 +573,7 @@ static void PrepareArgumentPackDeduction(Sema &S,
     if (!S.CurrentInstantiationScope)
       continue;
 
-    // If the template arugment pack was explicitly specified, add that to
+    // If the template argument pack was explicitly specified, add that to
     // the set of deduced arguments.
     const TemplateArgument *ExplicitArgs;
     unsigned NumExplicitArgs;
index 28e411653405820e951619fda3e65c398efb60f2..55462ff09b8642650bfd462c2d9656170b582137 100644 (file)
@@ -1657,7 +1657,7 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
     IsExpandedParameterPack = true;
     DI = D->getTypeSourceInfo();
     T = DI->getType();
-  } else if (isa<PackExpansionTypeLoc>(TL)) {
+  } else if (D->isPackExpansion()) {
     // The non-type template parameter pack's type is a pack expansion of types.
     // Determine whether we need to expand this parameter pack into separate
     // types.
@@ -1771,27 +1771,121 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
   return Param;
 }
 
+static void collectUnexpandedParameterPacks(
+    Sema &S,
+    TemplateParameterList *Params,
+    SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) {
+  for (TemplateParameterList::const_iterator I = Params->begin(),
+                                             E = Params->end(); I != E; ++I) {
+    if ((*I)->isTemplateParameterPack())
+      continue;
+    if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*I))
+      S.collectUnexpandedParameterPacks(NTTP->getTypeSourceInfo()->getTypeLoc(),
+                                        Unexpanded);
+    if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(*I))
+      collectUnexpandedParameterPacks(S, TTP->getTemplateParameters(),
+                                      Unexpanded);
+  }
+}
+
 Decl *
 TemplateDeclInstantiator::VisitTemplateTemplateParmDecl(
                                                   TemplateTemplateParmDecl *D) {
   // Instantiate the template parameter list of the template template parameter.
   TemplateParameterList *TempParams = D->getTemplateParameters();
   TemplateParameterList *InstParams;
-  {
+  SmallVector<TemplateParameterList*, 8> ExpandedParams;
+
+  bool IsExpandedParameterPack = false;
+
+  if (D->isExpandedParameterPack()) {
+    // The template template parameter pack is an already-expanded pack
+    // expansion of template parameters. Substitute into each of the expanded
+    // parameters.
+    ExpandedParams.reserve(D->getNumExpansionTemplateParameters());
+    for (unsigned I = 0, N = D->getNumExpansionTemplateParameters();
+         I != N; ++I) {
+      LocalInstantiationScope Scope(SemaRef);
+      TemplateParameterList *Expansion =
+        SubstTemplateParams(D->getExpansionTemplateParameters(I));
+      if (!Expansion)
+        return 0;
+      ExpandedParams.push_back(Expansion);
+    }
+
+    IsExpandedParameterPack = true;
+    InstParams = TempParams;
+  } else if (D->isPackExpansion()) {
+    // The template template parameter pack expands to a pack of template
+    // template parameters. Determine whether we need to expand this parameter
+    // pack into separate parameters.
+    SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+    collectUnexpandedParameterPacks(SemaRef, D->getTemplateParameters(),
+                                    Unexpanded);
+
+    // Determine whether the set of unexpanded parameter packs can and should
+    // be expanded.
+    bool Expand = true;
+    bool RetainExpansion = false;
+    llvm::Optional<unsigned> NumExpansions;
+    if (SemaRef.CheckParameterPacksForExpansion(D->getLocation(),
+                                                TempParams->getSourceRange(),
+                                                Unexpanded,
+                                                TemplateArgs,
+                                                Expand, RetainExpansion,
+                                                NumExpansions))
+      return 0;
+
+    if (Expand) {
+      for (unsigned I = 0; I != *NumExpansions; ++I) {
+        Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, I);
+        LocalInstantiationScope Scope(SemaRef);
+        TemplateParameterList *Expansion = SubstTemplateParams(TempParams);
+        if (!Expansion)
+          return 0;
+        ExpandedParams.push_back(Expansion);
+      }
+
+      // Note that we have an expanded parameter pack. The "type" of this
+      // expanded parameter pack is the original expansion type, but callers
+      // will end up using the expanded parameter pack types for type-checking.
+      IsExpandedParameterPack = true;
+      InstParams = TempParams;
+    } else {
+      // We cannot fully expand the pack expansion now, so just substitute
+      // into the pattern.
+      Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, -1);
+
+      LocalInstantiationScope Scope(SemaRef);
+      InstParams = SubstTemplateParams(TempParams);
+      if (!InstParams)
+        return 0;
+    }
+  } else {
     // Perform the actual substitution of template parameters within a new,
     // local instantiation scope.
     LocalInstantiationScope Scope(SemaRef);
     InstParams = SubstTemplateParams(TempParams);
     if (!InstParams)
-      return NULL;
+      return 0;
   }
 
   // Build the template template parameter.
-  TemplateTemplateParmDecl *Param
-    = TemplateTemplateParmDecl::Create(SemaRef.Context, Owner, D->getLocation(),
+  TemplateTemplateParmDecl *Param;
+  if (IsExpandedParameterPack)
+    Param = TemplateTemplateParmDecl::Create(SemaRef.Context, Owner,
+                                             D->getLocation(),
+                                   D->getDepth() - TemplateArgs.getNumLevels(),
+                                             D->getPosition(),
+                                             D->getIdentifier(), InstParams,
+                                             ExpandedParams);
+  else
+    Param = TemplateTemplateParmDecl::Create(SemaRef.Context, Owner,
+                                             D->getLocation(),
                                    D->getDepth() - TemplateArgs.getNumLevels(),
-                                       D->getPosition(), D->isParameterPack(),
-                                       D->getIdentifier(), InstParams);
+                                             D->getPosition(),
+                                             D->isParameterPack(),
+                                             D->getIdentifier(), InstParams);
   Param->setDefaultArgument(D->getDefaultArgument(), false);
   Param->setAccess(AS_public);
 
index 2418f3a1674b3722c35888023a1d6bb0a8eaf2d2..ba830d172cc06c660f74351095ef4a62d6978eef 100644 (file)
@@ -1486,11 +1486,18 @@ void ASTDeclReader::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
   // TemplateParmPosition.
   D->setDepth(Record[Idx++]);
   D->setPosition(Record[Idx++]);
-  // Rest of TemplateTemplateParmDecl.
-  TemplateArgumentLoc Arg = Reader.ReadTemplateArgumentLoc(F, Record, Idx);
-  bool IsInherited = Record[Idx++];
-  D->setDefaultArgument(Arg, IsInherited);
-  D->ParameterPack = Record[Idx++];
+  if (D->isExpandedParameterPack()) {
+    void **Data = reinterpret_cast<void **>(D + 1);
+    for (unsigned I = 0, N = D->getNumExpansionTemplateParameters();
+         I != N; ++I)
+      Data[I] = Reader.ReadTemplateParameterList(F, Record, Idx);
+  } else {
+    // Rest of TemplateTemplateParmDecl.
+    TemplateArgumentLoc Arg = Reader.ReadTemplateArgumentLoc(F, Record, Idx);
+    bool IsInherited = Record[Idx++];
+    D->setDefaultArgument(Arg, IsInherited);
+    D->ParameterPack = Record[Idx++];
+  }
 }
 
 void ASTDeclReader::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
@@ -2004,6 +2011,10 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
   case DECL_TEMPLATE_TEMPLATE_PARM:
     D = TemplateTemplateParmDecl::CreateDeserialized(Context, ID);
     break;
+  case DECL_EXPANDED_TEMPLATE_TEMPLATE_PARM_PACK:
+    D = TemplateTemplateParmDecl::CreateDeserialized(Context, ID,
+                                                     Record[Idx++]);
+    break;
   case DECL_TYPE_ALIAS_TEMPLATE:
     D = TypeAliasTemplateDecl::CreateDeserialized(Context, ID);
     break;
index 602943b9ba58236ee7ad6a3d8585d07f726575e1..baa8a0e4cd48492cf693378162ad7689751a27e8 100644 (file)
@@ -1172,7 +1172,8 @@ void ASTDeclWriter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
 
 void ASTDeclWriter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
   // For an expanded parameter pack, record the number of expansion types here
-  // so that it's easier for 
+  // so that it's easier for deserialization to allocate the right amount of
+  // memory.
   if (D->isExpandedParameterPack())
     Record.push_back(D->getNumExpansionTypes());
   
@@ -1201,15 +1202,30 @@ void ASTDeclWriter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
 }
 
 void ASTDeclWriter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
+  // For an expanded parameter pack, record the number of expansion types here
+  // so that it's easier for deserialization to allocate the right amount of
+  // memory.
+  if (D->isExpandedParameterPack())
+    Record.push_back(D->getNumExpansionTemplateParameters());
+
   VisitTemplateDecl(D);
   // TemplateParmPosition.
   Record.push_back(D->getDepth());
   Record.push_back(D->getPosition());
-  // Rest of TemplateTemplateParmDecl.
-  Writer.AddTemplateArgumentLoc(D->getDefaultArgument(), Record);
-  Record.push_back(D->defaultArgumentWasInherited());
-  Record.push_back(D->isParameterPack());
-  Code = serialization::DECL_TEMPLATE_TEMPLATE_PARM;
+
+  if (D->isExpandedParameterPack()) {
+    for (unsigned I = 0, N = D->getNumExpansionTemplateParameters();
+         I != N; ++I)
+      Writer.AddTemplateParameterList(D->getExpansionTemplateParameters(I),
+                                      Record);
+    Code = serialization::DECL_EXPANDED_TEMPLATE_TEMPLATE_PARM_PACK;
+  } else {
+    // Rest of TemplateTemplateParmDecl.
+    Writer.AddTemplateArgumentLoc(D->getDefaultArgument(), Record);
+    Record.push_back(D->defaultArgumentWasInherited());
+    Record.push_back(D->isParameterPack());
+    Code = serialization::DECL_TEMPLATE_TEMPLATE_PARM;
+  }
 }
 
 void ASTDeclWriter::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
index 5fc57a43f5417207711a59be770638eaecb9b5bd..4cc1f17a11e9458748e9e12334c6aad33213d5ae 100644 (file)
@@ -22,3 +22,153 @@ void f(const X<int> x) {
 
 template<typename T = void> struct X1 { };
 X1<X1<>> x1a;
+
+
+namespace ParameterPackExpansions {
+
+// A template parameter pack that [contains an unexpanded parameter pack] is a
+// pack expansion.
+
+template<typename...Ts> struct Outer {
+  // From [temp.variadic]p4:
+  //   In a template parameter pack that is a pack expansion, the pattern is
+  //   [...the template-parameter...] without the ellipsis.
+  // Therefore the resulting sequence of parameters is not a parameter pack,
+  // so is not required to be the last template parameter.
+  template<Ts ...As, template<Ts> class ...Bs, typename ...Cs> struct Inner {
+    struct Check : Bs<As>... {
+      Check(Cs...);
+    };
+  };
+};
+
+template<int> struct TemplateInt {};
+template<char> struct TemplateChar {};
+template<int*> struct TemplateIntPtr {};
+int x;
+
+Outer<int, char, int*>::
+Inner<12345, 'x', &x,
+      TemplateInt, TemplateChar, TemplateIntPtr,
+      int*>::
+Check check(&x);
+
+
+template<typename...Ts> struct types;
+
+enum place { _ };
+template<place...> struct places {};
+
+template<typename P1, typename P2> struct append_places;
+template<place...X1, place...X2>
+struct append_places<places<X1...>, places<X2...>> {
+  typedef places<X1...,X2...> type;
+};
+
+template<unsigned N>
+struct make_places : append_places<typename make_places<N/2>::type,
+                                   typename make_places<N-N/2>::type> {};
+template<> struct make_places<0> { typedef places<> type; };
+template<> struct make_places<1> { typedef places<_> type; };
+
+template<typename T> struct wrap {
+  template<place> struct inner { typedef T type; };
+};
+
+template<typename T> struct takedrop_impl;
+template<place...X> struct takedrop_impl<places<X...>> {
+  template<template<decltype(X)> class ...Take,
+           template<place      > class ...Drop>
+  struct inner { // expected-note 2{{declared}}
+    typedef types<typename Take<_>::type...> take;
+    typedef types<typename Drop<_>::type...> drop;
+  };
+};
+
+template<unsigned N, typename...Ts> struct take {
+  using type = typename takedrop_impl<typename make_places<N>::type>::
+    template inner<wrap<Ts>::template inner...>::take; // expected-error {{too few template arguments}}
+};
+template<unsigned N, typename...Ts> struct drop {
+  using type = typename takedrop_impl<typename make_places<N>::type>::
+    template inner<wrap<Ts>::template inner...>::drop; // expected-error {{too few template arguments}}
+};
+
+using T1 = take<3, int, char, double, long>::type; // expected-note {{previous}}
+using T1 = types<void, void, void, void>; // expected-error {{'types<void, void, void, void>' vs 'types<int, char, double, (no argument)>'}}
+using D1 = drop<3, int, char, double, long>::type;
+using D1 = types<long>;
+
+using T2 = take<4, int, char, double, long>::type; // expected-note {{previous}}
+using T2 = types<int, char, double, long>;
+using T2 = types<void, void, void, void>; // expected-error {{'types<void, void, void, void>' vs 'types<int, char, double, long>'}}
+using D2 = drop<4, int, char, double, long>::type;
+using D2 = types<>;
+
+using T3 = take<5, int, char, double, long>::type; // expected-note {{in instantiation of}}
+using D3 = drop<5, int, char, double, long>::type; // expected-note {{in instantiation of}}
+
+
+// FIXME: We should accept this code. A parameter pack within a default argument
+// in a template template parameter pack is expanded, because the pack is
+// implicitly a pack expansion.
+template<typename ...Default> struct DefArg {
+  template<template<typename T = Default> class ...Classes> struct Inner { // expected-error {{default argument contains unexpanded parameter pack}} expected-note {{here}}
+    Inner(Classes<>...); // expected-error {{too few}}
+  };
+};
+template<typename T> struct vector {};
+template<typename T> struct list {};
+vector<int> vi;
+list<char> lc;
+DefArg<int, char>::Inner<vector, list> defarg(vi, lc);
+
+
+// FIXME:
+// A template parameter pack that is a pack expansion shall not expand a
+// parameter pack declared in the same template-parameter-list.
+template<typename...Ts, Ts...Vs> void error(); // desired-error
+
+// This case should not produce an error, because in A's instantiation, Cs is
+// not a parameter pack.
+template<typename...Ts> void consume(Ts...);
+template<typename...Ts> struct A {
+  template<template<typename, Ts = 0> class ...Cs, Cs<Ts> ...Vs> struct B { // ok
+    B() {
+      consume([]{
+        int arr[Vs]; // expected-error {{negative size}}
+      }...);
+    }
+  };
+};
+template<typename, int> using Int = int;
+template<typename, short> using Char = char;
+A<int, short>::B<Int, Char, -1, 'x'> b; // expected-note {{here}}
+
+}
+
+namespace PR9023 {
+  template<typename ...T> struct A {
+    template<template<T> class ...> struct B {
+    };
+  };
+
+  template<int> struct C { };
+  template<long> struct D { };
+
+  int main() {
+    A<int, long>::B<C, D> e;
+  }
+}
+
+namespace std_examples {
+  template <class... Types> class Tuple;
+  template <class T, int... Dims> struct multi_array;
+  template <class... T> struct value_holder {
+    template<T... Values> struct apply { };
+  };
+  template <class... T, T... Values> struct static_array; // expected-error {{must be the last}}
+
+  int n;
+  value_holder<int, char, int*>::apply<12345, 'x', &n> test;
+}
index 5b586931d541ebfe680fa8fb5818ca3b85bf45cb..c78a1a57047c195b06c0cf36ecc8ec5c96e2e77d 100644 (file)
@@ -9,3 +9,7 @@
 
 // CHECK: allocate_shared
 shared_ptr<int> spi = shared_ptr<int>::allocate_shared(1, 2);
+
+template<int> struct A {};
+template<int> struct B {};
+outer<int, int>::inner<1, 2, A, B> i(A<1>{}, B<2>{});
index f6ee7876c2c2d539d840d6725b13c6aba50bbddc..50596cdf5dbf930d83aca81e91ef776d1bcd2b13 100644 (file)
@@ -16,3 +16,10 @@ shared_ptr<_Tp>::allocate_shared(const _Alloc& __a, _Args&& ...__args)
   shared_ptr<_Tp> __r;
   return __r;
 }
+
+template<typename...Ts> struct outer {
+  template<Ts...Vs, template<Ts> class ...Cs> struct inner {
+    inner(Cs<Vs>...);
+  };
+};
+template struct outer<int, int>;