]> granicus.if.org Git - clang/commitdiff
More work on type parameter packs.
authorAnders Carlsson <andersca@mac.com>
Sat, 13 Jun 2009 02:08:00 +0000 (02:08 +0000)
committerAnders Carlsson <andersca@mac.com>
Sat, 13 Jun 2009 02:08:00 +0000 (02:08 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@73281 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/DeclTemplate.h
lib/AST/DeclTemplate.cpp
lib/Sema/SemaTemplate.cpp
test/SemaTemplate/variadic-class-template-2.cpp [new file with mode: 0644]

index ca4758031df3bcd9dc979c93a7477d10a2247dda..4363dda5c2dfb516cb7efbdcd3df86d081bd5c65 100644 (file)
@@ -87,7 +87,7 @@ public:
   /// \btief Returns the minimum number of arguments needed to form a
   /// template specialization. This may be fewer than the number of
   /// template parameters, if some of the parameters have default
-  /// arguments.
+  /// arguments or if there is a parameter pack.
   unsigned getMinRequiredArguments() const;
 
   SourceLocation getTemplateLoc() const { return TemplateLoc; }
@@ -610,7 +610,7 @@ public:
     assert(!isAddingFromParameterPack() && 
            "Size is not valid when adding from a parameter pack");
     
-    return Args.size(); 
+    return Indices.size() / 2;
   }
   
   size_t flatSize() const { return Args.size(); }
@@ -770,6 +770,7 @@ public:
   static void 
   Profile(llvm::FoldingSetNodeID &ID, const TemplateArgument *TemplateArgs, 
           unsigned NumTemplateArgs) {
+    ID.AddInteger(NumTemplateArgs);
     for (unsigned Arg = 0; Arg != NumTemplateArgs; ++Arg)
       TemplateArgs[Arg].Profile(ID);
   }
index 9526b48468c7bf20920bb3b56ddba1d72793a88d..5b1bf9b3afc52e5b7ad0ee3ec6046df6f1bbb321 100644 (file)
@@ -50,7 +50,9 @@ unsigned TemplateParameterList::getMinRequiredArguments() const {
       ParamBegin = const_cast<TemplateParameterList *>(this)->begin();
   while (Param != ParamBegin) {
     --Param;
-    if (!(isa<TemplateTypeParmDecl>(*Param) && 
+    
+    if (!(*Param)->isTemplateParameterPack() &&
+        !(isa<TemplateTypeParmDecl>(*Param) && 
           cast<TemplateTypeParmDecl>(*Param)->hasDefaultArgument()) &&
         !(isa<NonTypeTemplateParmDecl>(*Param) &&
           cast<NonTypeTemplateParmDecl>(*Param)->hasDefaultArgument()) &&
index f20bcd95ca14eca522feba3146ff35b5fc87b30d..00d8c769bd22f2824481abbcf23921a02ee86ffc 100644 (file)
@@ -1016,7 +1016,10 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
   unsigned NumArgs = NumTemplateArgs;
   bool Invalid = false;
 
-  if (NumArgs > NumParams ||
+  bool HasParameterPack = 
+    NumParams > 0 && Params->getParam(NumParams - 1)->isTemplateParameterPack();
+  
+  if ((NumArgs > NumParams && !HasParameterPack) ||
       NumArgs < Params->getMinRequiredArguments()) {
     // FIXME: point at either the first arg beyond what we can handle,
     // or the '>', depending on whether we have too many or too few
@@ -1050,6 +1053,13 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
       // Retrieve the default template argument from the template
       // parameter.
       if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) {
+        if (TTP->isParameterPack()) {
+          // We have an empty parameter pack.
+          Converted.BeginParameterPack();
+          Converted.EndParameterPack();
+          break;
+        }
+        
         if (!TTP->hasDefaultArgument())
           break;
 
@@ -1112,8 +1122,19 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
 
 
     if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) {
-      if (CheckTemplateTypeArgument(TTP, Arg, Converted))
-        Invalid = true;
+      if (TTP->isParameterPack()) {
+        Converted.BeginParameterPack();
+        // Check all the remaining arguments (if any).
+        for (; ArgIdx < NumArgs; ++ArgIdx) {
+          if (CheckTemplateTypeArgument(TTP, TemplateArgs[ArgIdx], Converted))
+            Invalid = true;
+        }
+        
+        Converted.EndParameterPack();
+      } else {
+        if (CheckTemplateTypeArgument(TTP, Arg, Converted))
+          Invalid = true;
+      }
     } else if (NonTypeTemplateParmDecl *NTTP 
                  = dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
       // Check non-type template parameters.
diff --git a/test/SemaTemplate/variadic-class-template-2.cpp b/test/SemaTemplate/variadic-class-template-2.cpp
new file mode 100644 (file)
index 0000000..eadea90
--- /dev/null
@@ -0,0 +1,19 @@
+// RUN: clang-cc -fsyntax-only -verify %s -std=c++0x
+
+// Type parameters packs
+template <typename ...> struct TS1 {}; // expected-note{{template parameter is declared here}}
+template struct TS1<>;
+template struct TS1<int>;
+template struct TS1<int, int>;
+template struct TS1<int, 10>; // expected-error{{template argument for template type parameter must be a type}}
+
+template <typename, typename ...> struct TS2 {}; // expected-note{{template is declared here}}
+template struct TS2<>; // expected-error{{too few template arguments for class template 'TS2'}}
+template struct TS2<int>;
+template struct TS2<int, int>;
+
+template <typename = int, typename ...> struct TS3 {}; // expected-note{{template parameter is declared here}}
+template struct TS3<>; // expected-note{{previous explicit instantiation is here}}
+template struct TS3<int>; // expected-error{{duplicate explicit instantiation of 'TS3<>'}}
+template struct TS3<int, int>;
+template struct TS3<10>; // expected-error{{template argument for template type parameter must be a type}}