]> granicus.if.org Git - clang/commitdiff
When forming the injected-class-name of a variadic template, the
authorDouglas Gregor <dgregor@apple.com>
Thu, 23 Dec 2010 16:00:30 +0000 (16:00 +0000)
committerDouglas Gregor <dgregor@apple.com>
Thu, 23 Dec 2010 16:00:30 +0000 (16:00 +0000)
template argument corresponding to a template parameter pack is an
argument pack of a pack expansion of that template parameter
pack. Implements C++0x [temp.dep.type]p2 (at least, as much of it as
we can).

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

lib/AST/DeclTemplate.cpp
test/CXX/temp/temp.decls/temp.variadic/injected-class-name.cpp [new file with mode: 0644]

index f21c9a3af32fab595899fc4d698213e4acdc504b..422e5e30f8bf259f4a3d545caa71c36f8512cad5 100644 (file)
@@ -300,10 +300,13 @@ ClassTemplateDecl::getInjectedClassNameSpecialization() {
   if (!CommonPtr->InjectedClassNameType.isNull())
     return CommonPtr->InjectedClassNameType;
 
-  // FIXME: n2800 14.6.1p1 should say how the template arguments
-  // corresponding to template parameter packs should be pack
-  // expansions. We already say that in 14.6.2.1p2, so it would be
-  // better to fix that redundancy.
+  // C++0x [temp.dep.type]p2:
+  //  The template argument list of a primary template is a template argument 
+  //  list in which the nth template argument has the value of the nth template
+  //  parameter of the class template. If the nth template parameter is a 
+  //  template parameter pack (14.5.3), the nth template argument is a pack 
+  //  expansion (14.5.3) whose pattern is the name of the template parameter 
+  //  pack.
   ASTContext &Context = getASTContext();
   TemplateParameterList *Params = getTemplateParameters();
   llvm::SmallVector<TemplateArgument, 16> TemplateArgs;
@@ -311,20 +314,34 @@ ClassTemplateDecl::getInjectedClassNameSpecialization() {
   for (TemplateParameterList::iterator Param = Params->begin(),
                                     ParamEnd = Params->end();
        Param != ParamEnd; ++Param) {
-    if (isa<TemplateTypeParmDecl>(*Param)) {
-      QualType ParamType = Context.getTypeDeclType(cast<TypeDecl>(*Param));
-      TemplateArgs.push_back(TemplateArgument(ParamType));
+    TemplateArgument Arg;
+    if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) {
+      QualType ArgType = Context.getTypeDeclType(TTP);
+      if (TTP->isParameterPack())
+        ArgType = Context.getPackExpansionType(ArgType);
+      
+      Arg = TemplateArgument(ArgType);
     } else if (NonTypeTemplateParmDecl *NTTP =
                  dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
       Expr *E = new (Context) DeclRefExpr(NTTP,
                                   NTTP->getType().getNonLValueExprType(Context),
                                   Expr::getValueKindForType(NTTP->getType()),
                                           NTTP->getLocation());
-      TemplateArgs.push_back(TemplateArgument(E));
+      // FIXME: Variadic templates.
+      Arg = TemplateArgument(E);
     } else {
       TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*Param);
-      TemplateArgs.push_back(TemplateArgument(TemplateName(TTP)));
+      // FIXME: Variadic templates.
+      Arg = TemplateArgument(TemplateName(TTP));
     }
+    
+    if ((*Param)->isTemplateParameterPack()) {
+      TemplateArgument *Pack = new (Context) TemplateArgument [1];
+      *Pack = Arg;
+      Arg = TemplateArgument(Pack, 1);
+    }
+    
+    TemplateArgs.push_back(Arg);
   }
 
   CommonPtr->InjectedClassNameType
diff --git a/test/CXX/temp/temp.decls/temp.variadic/injected-class-name.cpp b/test/CXX/temp/temp.decls/temp.variadic/injected-class-name.cpp
new file mode 100644 (file)
index 0000000..bcdbe53
--- /dev/null
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+// Check for declaration matching with out-of-line declarations and
+// variadic templates, which involves proper computation of the
+// injected-class-name.
+template<typename T, typename ...Types>
+struct X0 {
+  typedef T type;
+
+  void f0(T);
+  type f1(T);
+};
+
+template<typename T, typename ...Types>
+void X0<T, Types...>::f0(T) { }
+
+template<typename T, typename ...Types>
+typename X0<T, Types...>::type X0<T, Types...>::f1(T) { }
+
+template<typename T, typename ...Types>
+struct X0<T, T, Types...> {
+  typedef T* result;
+  result f3();
+
+  template<typename... InnerTypes>
+  struct Inner;
+};
+
+template<typename T, typename ...Types>
+typename X0<T, T, Types...>::result X0<T, T, Types...>::f3() { return 0; }
+
+template<typename T, typename ...Types>
+template<typename ...InnerTypes>
+struct X0<T, T, Types...>::Inner {
+  template<typename ...ReallyInner> void f4();
+};
+
+template<typename T, typename ...Types>
+template<typename ...InnerTypes>
+template<typename ...ReallyInner>
+void X0<T, T, Types...>::Inner<InnerTypes...>::f4() { }