[cfe-commits] r123000 - in /cfe/trunk: include/clang/Sema/Sema.h include/clang/Sema/Template.h lib/Sema/SemaTemplateDeduction.cpp lib/Sema/SemaTemplateInstantiate.cpp lib/Sema/SemaTemplateInstantiateDecl.cpp lib/Sema/SemaTemplateVariadic.cpp lib/Sema/TreeTransform.h test/CXX/expr/expr.unary/expr.sizeof/p5-0x.cpp test/CXX/temp/temp.decls/temp.variadic/p2.cpp test/CXX/temp/temp.decls/temp.variadic/p5.cpp

Douglas Gregor dgregor at apple.com
Fri Jan 7 08:43:16 PST 2011


Author: dgregor
Date: Fri Jan  7 10:43:16 2011
New Revision: 123000

URL: http://llvm.org/viewvc/llvm-project?rev=123000&view=rev
Log:
Implement substitution of a function parameter pack for its set of
instantiated function parameters, enabling instantiation of arbitrary
pack expansions involving function parameter packs. At this point, we
can now correctly compile a simple, variadic print() example:

  #include <iostream>
  #include <string>

  void print() {}

  template<typename Head, typename ...Tail>
  void print(const Head &head, const Tail &...tail) {
    std::cout << head;
    print(tail...);
  }

  int main() {
    std::string hello = "Hello";
    print(hello, ", world!", " ", 2011, '\n');
  }


Added:
    cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/p2.cpp
Modified:
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/include/clang/Sema/Template.h
    cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
    cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp
    cfe/trunk/lib/Sema/TreeTransform.h
    cfe/trunk/test/CXX/expr/expr.unary/expr.sizeof/p5-0x.cpp
    cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/p5.cpp

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=123000&r1=122999&r2=123000&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Fri Jan  7 10:43:16 2011
@@ -3893,7 +3893,8 @@
   bool SubstParmTypes(SourceLocation Loc, 
                       ParmVarDecl **Params, unsigned NumParams,
                       const MultiLevelTemplateArgumentList &TemplateArgs,
-                      llvm::SmallVectorImpl<QualType> &ParamTypes);
+                      llvm::SmallVectorImpl<QualType> &ParamTypes,
+                      llvm::SmallVectorImpl<ParmVarDecl *> *OutParams = 0);
   ExprResult SubstExpr(Expr *E,
                        const MultiLevelTemplateArgumentList &TemplateArgs);
 

Modified: cfe/trunk/include/clang/Sema/Template.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Template.h?rev=123000&r1=122999&r2=123000&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Template.h (original)
+++ cfe/trunk/include/clang/Sema/Template.h Fri Jan  7 10:43:16 2011
@@ -166,10 +166,19 @@
   /// instantiate a new function declaration, which will have its own
   /// set of parameter declarations.
   class LocalInstantiationScope {
+  public:
+    /// \brief A set of declarations.
+    typedef llvm::SmallVector<Decl *, 4> DeclArgumentPack;
+    
+  private:
     /// \brief Reference to the semantic analysis that is performing
     /// this template instantiation.
     Sema &SemaRef;
 
+    typedef llvm::DenseMap<const Decl *, 
+                           llvm::PointerUnion<Decl *, DeclArgumentPack *> >
+      LocalDeclsMap;
+    
     /// \brief A mapping from local declarations that occur
     /// within a template to their instantiations.
     ///
@@ -184,8 +193,15 @@
     /// when we instantiate add<int>, we will introduce a mapping from
     /// the ParmVarDecl for 'x' that occurs in the template to the
     /// instantiated ParmVarDecl for 'x'.
-    llvm::DenseMap<const Decl *, Decl *> LocalDecls;
+    ///
+    /// For a parameter pack, the local instantiation scope may contain a
+    /// set of instantiated parameters. This is stored as a DeclArgumentPack
+    /// pointer.
+    LocalDeclsMap LocalDecls;
 
+    /// \brief The set of argument packs we've allocated.
+    llvm::SmallVector<DeclArgumentPack *, 1> ArgumentPacks;
+    
     /// \brief The outer scope, which contains local variable
     /// definitions from some other instantiation (that may not be
     /// relevant to this particular scope).
@@ -219,12 +235,26 @@
       if (Exited)
         return;
       
+      for (unsigned I = 0, N = ArgumentPacks.size(); I != N; ++I)
+        delete ArgumentPacks[I];
+        
       SemaRef.CurrentInstantiationScope = Outer;
       Exited = true;
     }
 
     Decl *getInstantiationOf(const Decl *D);
 
+    /// \brief Find the instantiation of the declaration D within the current
+    /// instantiation scope.
+    ///
+    /// \param D The declaration whose instantiation we are searching for.
+    ///
+    /// \returns A pointer to the declaration or argument pack of declarations
+    /// to which the declaration \c D is instantiataed, if found. Otherwise,
+    /// returns NULL.
+    llvm::PointerUnion<Decl *, DeclArgumentPack *> *
+    findInstantiationOf(const Decl *D);
+                              
     VarDecl *getInstantiationOf(const VarDecl *Var) {
       return cast<VarDecl>(getInstantiationOf(cast<Decl>(Var)));
     }
@@ -239,6 +269,8 @@
     }
 
     void InstantiatedLocal(const Decl *D, Decl *Inst);
+    void InstantiatedLocalPackArg(const Decl *D, Decl *Inst);
+    void MakeInstantiatedLocalArgPack(const Decl *D);
   };
 
   class TemplateDeclInstantiator

Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=123000&r1=122999&r2=123000&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Fri Jan  7 10:43:16 2011
@@ -542,7 +542,6 @@
                       llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced,
                         unsigned TDF) {
   // Fast-path check to see if we have too many/too few arguments.
-  // FIXME: Variadic templates broken!
   if (NumParams != NumArgs &&
       !(NumParams && isa<PackExpansionType>(Params[NumParams - 1])) &&
       !(NumArgs && isa<PackExpansionType>(Args[NumArgs - 1])))

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=123000&r1=122999&r2=123000&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Fri Jan  7 10:43:16 2011
@@ -617,6 +617,10 @@
                                                        NumExpansions);
     }
 
+    void ExpandingFunctionParameterPack(ParmVarDecl *Pack) { 
+      SemaRef.CurrentInstantiationScope->MakeInstantiatedLocalArgPack(Pack);
+    }
+    
     /// \brief Transform the given declaration by instantiating a reference to
     /// this declaration.
     Decl *TransformDecl(SourceLocation Loc, Decl *D);
@@ -1154,12 +1158,9 @@
   TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo();
   TypeSourceInfo *NewDI = 0;
   
-  bool WasParameterPack = false;
-  bool IsParameterPack = false;
   TypeLoc OldTL = OldDI->getTypeLoc();
   if (isa<PackExpansionTypeLoc>(OldTL)) {    
     PackExpansionTypeLoc ExpansionTL = cast<PackExpansionTypeLoc>(OldTL);
-    WasParameterPack = true;
     
     // We have a function parameter pack. Substitute into the pattern of the 
     // expansion.
@@ -1173,7 +1174,6 @@
       // our function parameter is still a function parameter pack.
       // Therefore, make its type a pack expansion type.
       NewDI = CheckPackExpansion(NewDI, ExpansionTL.getEllipsisLoc());
-      IsParameterPack = true;
     }
   } else {
     NewDI = SubstType(OldDI, TemplateArgs, OldParm->getLocation(), 
@@ -1211,8 +1211,13 @@
 
   // FIXME: When OldParm is a parameter pack and NewParm is not a parameter
   // pack, we actually have a set of instantiated locations. Maintain this set!
-  if (!WasParameterPack || IsParameterPack)
+  if (OldParm->isParameterPack() && !NewParm->isParameterPack()) {
+    // Add the new parameter to 
+    CurrentInstantiationScope->InstantiatedLocalPackArg(OldParm, NewParm);
+  } else {
+    // Introduce an Old -> New mapping
     CurrentInstantiationScope->InstantiatedLocal(OldParm, NewParm);  
+  }
   
   // FIXME: OldParm may come from a FunctionProtoType, in which case CurContext
   // can be anything, is this right ?
@@ -1227,7 +1232,8 @@
 bool Sema::SubstParmTypes(SourceLocation Loc, 
                           ParmVarDecl **Params, unsigned NumParams,
                           const MultiLevelTemplateArgumentList &TemplateArgs,
-                          llvm::SmallVectorImpl<QualType> &ParamTypes) {
+                          llvm::SmallVectorImpl<QualType> &ParamTypes,
+                          llvm::SmallVectorImpl<ParmVarDecl *> *OutParams) {
   assert(!ActiveTemplateInstantiations.empty() &&
          "Cannot perform an instantiation without some context on the "
          "instantiation stack");
@@ -1235,7 +1241,7 @@
   TemplateInstantiator Instantiator(*this, TemplateArgs, Loc, 
                                     DeclarationName());
   return Instantiator.TransformFunctionTypeParams(Loc, Params, NumParams, 0,
-                                                  ParamTypes, 0);
+                                                  ParamTypes, OutParams);
 }
 
 /// \brief Perform substitution on the base class specifiers of the
@@ -1899,15 +1905,27 @@
 }
 
 Decl *LocalInstantiationScope::getInstantiationOf(const Decl *D) {
+  llvm::PointerUnion<Decl *, DeclArgumentPack *> *Found= findInstantiationOf(D);
+  if (!Found)
+    return 0;
+  
+  if (Found->is<Decl *>())
+    return Found->get<Decl *>();
+  
+  return (*Found->get<DeclArgumentPack *>())[
+                                        SemaRef.ArgumentPackSubstitutionIndex];
+}
+
+llvm::PointerUnion<Decl *, LocalInstantiationScope::DeclArgumentPack *> *
+LocalInstantiationScope::findInstantiationOf(const Decl *D) {
   for (LocalInstantiationScope *Current = this; Current; 
        Current = Current->Outer) {
     // Check if we found something within this scope.
     const Decl *CheckD = D;
     do {
-      llvm::DenseMap<const Decl *, Decl *>::iterator Found
-        = Current->LocalDecls.find(CheckD);
+      LocalDeclsMap::iterator Found = Current->LocalDecls.find(CheckD);
       if (Found != Current->LocalDecls.end())
-        return Found->second;
+        return &Found->second;
       
       // If this is a tag declaration, it's possible that we need to look for
       // a previous declaration.
@@ -1928,7 +1946,23 @@
 }
 
 void LocalInstantiationScope::InstantiatedLocal(const Decl *D, Decl *Inst) {
-  Decl *&Stored = LocalDecls[D];
-  assert((!Stored || Stored == Inst)&& "Already instantiated this local");
+  llvm::PointerUnion<Decl *, DeclArgumentPack *> &Stored = LocalDecls[D];
+  assert((Stored.isNull() || 
+          (Stored.get<Decl *>() == Inst)) && "Already instantiated this local");
   Stored = Inst;
 }
+
+void LocalInstantiationScope::InstantiatedLocalPackArg(const Decl *D, 
+                                                       Decl *Inst) {
+  DeclArgumentPack *Pack = LocalDecls[D].get<DeclArgumentPack *>();
+  Pack->push_back(Inst);
+}
+
+void LocalInstantiationScope::MakeInstantiatedLocalArgPack(const Decl *D) {
+  llvm::PointerUnion<Decl *, DeclArgumentPack *> &Stored = LocalDecls[D];
+  assert(Stored.isNull() && "Already instantiated this local");
+  DeclArgumentPack *Pack = new DeclArgumentPack;
+  Stored = Pack;
+  ArgumentPacks.push_back(Pack);
+}
+

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=123000&r1=122999&r2=123000&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Fri Jan  7 10:43:16 2011
@@ -1271,14 +1271,11 @@
   // synthesized in the method declaration.
   if (!isa<FunctionProtoType>(T.IgnoreParens())) {
     assert(!Params.size() && "Instantiating type could not yield parameters");
-    for (unsigned I = 0, N = D->getNumParams(); I != N; ++I) {
-      ParmVarDecl *P = SemaRef.SubstParmVarDecl(D->getParamDecl(I), 
-                                                TemplateArgs);
-      if (!P)
-        return 0;
-
-      Params.push_back(P);
-    }
+    llvm::SmallVector<QualType, 4> ParamTypes;
+    if (SemaRef.SubstParmTypes(D->getLocation(), D->param_begin(), 
+                               D->getNumParams(), TemplateArgs, ParamTypes, 
+                               &Params))
+      return 0;    
   }
 
   NestedNameSpecifier *Qualifier = D->getQualifier();
@@ -1904,12 +1901,31 @@
       TypeLoc NewTL = NewTInfo->getTypeLoc().IgnoreParens();
       FunctionProtoTypeLoc *NewProtoLoc = cast<FunctionProtoTypeLoc>(&NewTL);
       assert(NewProtoLoc && "Missing prototype?");
-      for (unsigned i = 0, i_end = NewProtoLoc->getNumArgs(); i != i_end; ++i) {
-        // FIXME: Variadic templates will break this.
-        Params.push_back(NewProtoLoc->getArg(i));
-        SemaRef.CurrentInstantiationScope->InstantiatedLocal(
-                                                        OldProtoLoc->getArg(i),
-                                                        NewProtoLoc->getArg(i));
+      unsigned NewIdx = 0, NumNewParams = NewProtoLoc->getNumArgs();
+      for (unsigned OldIdx = 0, NumOldParams = OldProtoLoc->getNumArgs();
+           OldIdx != NumOldParams; ++OldIdx) {
+        ParmVarDecl *OldParam = OldProtoLoc->getArg(OldIdx);
+        if (!OldParam->isParameterPack() ||
+            (NewIdx < NumNewParams &&
+             NewProtoLoc->getArg(NewIdx)->isParameterPack())) {
+          // Simple case: normal parameter, or a parameter pack that's 
+          // instantiated to a (still-dependent) parameter pack.
+          ParmVarDecl *NewParam = NewProtoLoc->getArg(NewIdx++);
+          Params.push_back(NewParam);
+          SemaRef.CurrentInstantiationScope->InstantiatedLocal(OldParam,
+                                                               NewParam);
+          continue;
+        }
+        
+        // Parameter pack: make the instantiation an argument pack.
+        SemaRef.CurrentInstantiationScope->MakeInstantiatedLocalArgPack(
+                                                                      OldParam);
+        while (NewIdx < NumNewParams) {
+          ParmVarDecl *NewParam = NewProtoLoc->getArg(NewIdx++);
+          Params.push_back(NewParam);
+          SemaRef.CurrentInstantiationScope->InstantiatedLocalPackArg(OldParam,
+                                                                      NewParam);
+        }
       }
     }
   } else {
@@ -2179,11 +2195,28 @@
   // Introduce the instantiated function parameters into the local
   // instantiation scope, and set the parameter names to those used
   // in the template.
+  unsigned FParamIdx = 0;
   for (unsigned I = 0, N = PatternDecl->getNumParams(); I != N; ++I) {
     const ParmVarDecl *PatternParam = PatternDecl->getParamDecl(I);
-    ParmVarDecl *FunctionParam = Function->getParamDecl(I);
-    FunctionParam->setDeclName(PatternParam->getDeclName());
-    Scope.InstantiatedLocal(PatternParam, FunctionParam);
+    if (!PatternParam->isParameterPack()) {
+      // Simple case: not a parameter pack.
+      assert(FParamIdx < Function->getNumParams());
+      ParmVarDecl *FunctionParam = Function->getParamDecl(I);
+      FunctionParam->setDeclName(PatternParam->getDeclName());
+      Scope.InstantiatedLocal(PatternParam, FunctionParam);
+      ++FParamIdx;
+      continue;
+    }
+    
+    // Expand the parameter pack.
+    Scope.MakeInstantiatedLocalArgPack(PatternParam);
+    for (unsigned NumFParams = Function->getNumParams(); 
+         FParamIdx < NumFParams; 
+         ++FParamIdx) {
+      ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx);
+      FunctionParam->setDeclName(PatternParam->getDeclName());
+      Scope.InstantiatedLocalPackArg(PatternParam, FunctionParam);
+    }
   }
 
   // Enter the scope of this instantiation. We don't use

Modified: cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp?rev=123000&r1=122999&r2=123000&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp Fri Jan  7 10:43:16 2011
@@ -67,13 +67,8 @@
     /// \brief Record occurrences of (FIXME: function and) non-type template
     /// parameter packs in an expression.
     bool VisitDeclRefExpr(DeclRefExpr *E) {
-      if (NonTypeTemplateParmDecl *NTTP 
-                            = dyn_cast<NonTypeTemplateParmDecl>(E->getDecl())) {
-        if (NTTP->isParameterPack())
-          Unexpanded.push_back(std::make_pair(NTTP, E->getLocation()));
-      }
-      
-      // FIXME: Function parameter packs.
+      if (E->getDecl()->isParameterPack())
+        Unexpanded.push_back(std::make_pair(E->getDecl(), E->getLocation()));
       
       return true;
     }
@@ -440,6 +435,7 @@
     unsigned Depth;
     unsigned Index;
     IdentifierInfo *Name;
+    bool IsFunctionParameterPack = false;
     
     if (const TemplateTypeParmType *TTP
         = Unexpanded[I].first.dyn_cast<const TemplateTypeParmType *>()) {
@@ -455,26 +451,50 @@
                  = dyn_cast<NonTypeTemplateParmDecl>(ND)) {        
         Depth = NTTP->getDepth();
         Index = NTTP->getIndex();
-      } else {
-        TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(ND);
+      } else if (TemplateTemplateParmDecl *TTP
+                                    = dyn_cast<TemplateTemplateParmDecl>(ND)) {
         Depth = TTP->getDepth();
         Index = TTP->getIndex();
+      } else {
+        assert(cast<ParmVarDecl>(ND)->isParameterPack());
+        IsFunctionParameterPack = true;
       }
-      // FIXME: Variadic templates function parameter packs?
       Name = ND->getIdentifier();
     }
     
-    // If we don't have a template argument at this depth/index, then we 
-    // cannot expand the pack expansion. Make a note of this, but we still 
-    // want to check any parameter packs we *do* have arguments for.
-    if (Depth >= TemplateArgs.getNumLevels() ||
-        !TemplateArgs.hasTemplateArgument(Depth, Index)) {
-      ShouldExpand = false;
-      continue;
+    // Determine the size of this argument pack.
+    unsigned NewPackSize;    
+    if (IsFunctionParameterPack) {
+      // Figure out whether we're instantiating to an argument pack or not.
+      typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack;
+      
+      llvm::PointerUnion<Decl *, DeclArgumentPack *> *Instantiation
+        = CurrentInstantiationScope->findInstantiationOf(
+                                        Unexpanded[I].first.get<NamedDecl *>());
+      if (Instantiation &&
+          Instantiation->is<DeclArgumentPack *>()) {
+        // We could expand this function parameter pack.
+        NewPackSize = Instantiation->get<DeclArgumentPack *>()->size();
+      } else {
+        // We can't expand this function parameter pack, so we can't expand
+        // the pack expansion.
+        ShouldExpand = false;
+        continue;
+      }
+    } else {
+      // If we don't have a template argument at this depth/index, then we 
+      // cannot expand the pack expansion. Make a note of this, but we still 
+      // want to check any parameter packs we *do* have arguments for.
+      if (Depth >= TemplateArgs.getNumLevels() ||
+          !TemplateArgs.hasTemplateArgument(Depth, Index)) {
+        ShouldExpand = false;
+        continue;
+      }
+      
+      // Determine the size of the argument pack.
+      NewPackSize = TemplateArgs(Depth, Index).pack_size();
     }
     
-    // Determine the size of the argument pack.
-    unsigned NewPackSize = TemplateArgs(Depth, Index).pack_size();
     if (!HaveFirstPack) {
       // The is the first pack we've seen for which we have an argument. 
       // Record it.

Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=123000&r1=122999&r2=123000&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Fri Jan  7 10:43:16 2011
@@ -222,6 +222,10 @@
     return false;
   }
   
+  /// \brief Note to the derived class when a function parameter pack is
+  /// being expanded.
+  void ExpandingFunctionParameterPack(ParmVarDecl *Pack) { }
+                                      
   /// \brief Transforms the given type into another type.
   ///
   /// By default, this routine transforms a type by creating a
@@ -3423,6 +3427,7 @@
         if (ShouldExpand) {
           // Expand the function parameter pack into multiple, separate
           // parameters.
+          getDerived().ExpandingFunctionParameterPack(OldParm);
           for (unsigned I = 0; I != NumExpansions; ++I) {
             Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I);
             ParmVarDecl *NewParm 
@@ -6875,6 +6880,7 @@
   llvm::SmallVector<QualType, 4> ParamTypes;
   
   // Parameter substitution.
+  // FIXME: Variadic templates
   const BlockDecl *BD = E->getBlockDecl();
   for (BlockDecl::param_const_iterator P = BD->param_begin(),
        EN = BD->param_end(); P != EN; ++P) {

Modified: cfe/trunk/test/CXX/expr/expr.unary/expr.sizeof/p5-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.unary/expr.sizeof/p5-0x.cpp?rev=123000&r1=122999&r2=123000&view=diff
==============================================================================
--- cfe/trunk/test/CXX/expr/expr.unary/expr.sizeof/p5-0x.cpp (original)
+++ cfe/trunk/test/CXX/expr/expr.unary/expr.sizeof/p5-0x.cpp Fri Jan  7 10:43:16 2011
@@ -13,6 +13,18 @@
 int check_types[count_types<short, int, long>::value == 3? 1 : -1];
 int check_ints[count_ints<1, 2, 3, 4, 5>::value == 5? 1 : -1];
 
+// Test instantiation involving function parameter packs.
+struct any {
+  template<typename T> any(T);
+};
+
+template<typename ...Inits>
+void init_me(Inits ...inits) {
+  any array[sizeof...(inits)] = { inits... };
+}
+
+template void init_me<int, float, double*>(int, float, double*);
+
 // Test parser and semantic recovery.
 template<int Value> struct count_ints_2 {
   static const unsigned value = sizeof...(Value); // expected-error{{'Value' does not refer to the name of a parameter pack}}

Added: cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/p2.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/p2.cpp?rev=123000&view=auto
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/p2.cpp (added)
+++ cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/p2.cpp Fri Jan  7 10:43:16 2011
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+template<class ... Types> void f(Types ... args);
+
+void test() {
+  f(); 
+  f(1); 
+  f(2, 1.0);
+}
+
+// Test simple recursive variadic function template
+template<typename Head, typename ...Tail>
+void recurse_until_fail(const Head &, const Tail &...tail) { // expected-note{{candidate function template not viable: requires at least 1 argument, but 0 were provided}}
+  recurse_until_fail(tail...); // expected-error{{no matching function for call to 'recurse_until_fail'}} \
+  // expected-note{{in instantiation of function template specialization 'recurse_until_fail<char [7], >' requested here}} \
+  // expected-note{{in instantiation of function template specialization 'recurse_until_fail<double, char [7]>' requested here}}
+}
+
+void test_recurse_until_fail() {
+  recurse_until_fail(1, 3.14159, "string");   // expected-note{{in instantiation of function template specialization 'recurse_until_fail<int, double, char [7]>' requested here}}
+
+}

Modified: cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/p5.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/p5.cpp?rev=123000&r1=122999&r2=123000&view=diff
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/p5.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/p5.cpp Fri Jan  7 10:43:16 2011
@@ -237,3 +237,30 @@
   };
 };
 
+// Example from working paper
+namespace WorkingPaperExample {
+  template<typename...> struct Tuple {}; 
+  template<typename T1, typename T2> struct Pair {};
+  
+  template<class ... Args1> struct zip { 
+    template<class ... Args2> struct with {
+      typedef Tuple<Pair<Args1, Args2> ... > type; // expected-error{{pack expansion contains parameter packs 'Args1' and 'Args2' that have different lengths (1 vs. 2)}}
+    }; 
+  };
+
+  typedef zip<short, int>::with<unsigned short, unsigned>::type T1; // T1 is Tuple<Pair<short, unsigned short>, Pair<int, unsigned>>
+  typedef Tuple<Pair<short, unsigned short>, Pair<int, unsigned>> T1;
+
+  typedef zip<short>::with<unsigned short, unsigned>::type T2; // expected-note{{in instantiation of template class}}
+
+  template<class ... Args> void f(Args...);
+  template<class ... Args> void h(Args...);
+
+  template<class ... Args> 
+  void g(Args ... args) {
+    f(const_cast<const Args*>(&args)...); // OK: "Args" and "args" are expanded within f 
+    f(5 ...); // expected-error{{pack expansion does not contain any unexpanded parameter packs}}
+    f(args); // expected-error{{expression contains unexpanded parameter pack 'args'}}
+    f(h(args ...) + args ...);
+  }
+}





More information about the cfe-commits mailing list