This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Variadic templates, fourth revision (1/2)


On 3/5/07, Jason Merrill <jason@redhat.com> wrote:
Doug Gregor wrote:
> On 2/28/07, Doug Gregor <doug.gregor@gmail.com> wrote:
>> Here is the (hopefully final) revision of the variadic templates
>> patch. I've addressed all of Jason's comments, with one exception (see
>> below), and extended the testsuite. I am not providing an updated
>> libstdc++-v3 patch: aside from some fuzz in the already-approved
>> December patch, there were no changes.
>
> Argh! The -cp patch got mangled. Attached yet again :(

It got mangled that time, too.

We'll try uncompressed, then. Sorry about the noise.


 Cheers,
 Doug
Index: typeck.c
===================================================================
--- typeck.c	(revision 122403)
+++ typeck.c	(working copy)
@@ -992,7 +992,9 @@ structural_comptypes (tree t1, tree t2, 
     case TEMPLATE_TEMPLATE_PARM:
     case BOUND_TEMPLATE_TEMPLATE_PARM:
       if (TEMPLATE_TYPE_IDX (t1) != TEMPLATE_TYPE_IDX (t2)
-	  || TEMPLATE_TYPE_LEVEL (t1) != TEMPLATE_TYPE_LEVEL (t2))
+	  || TEMPLATE_TYPE_LEVEL (t1) != TEMPLATE_TYPE_LEVEL (t2)
+          || (TEMPLATE_TYPE_PARAMETER_PACK (t1) 
+              != TEMPLATE_TYPE_PARAMETER_PACK (t2)))
 	return false;
       if (!comp_template_parms
 	  (DECL_TEMPLATE_PARMS (TEMPLATE_TEMPLATE_PTE_PARM_TEMPLATE_DECL (t1)),
@@ -1051,7 +1053,9 @@ structural_comptypes (tree t1, tree t2, 
 
     case TEMPLATE_TYPE_PARM:
       if (TEMPLATE_TYPE_IDX (t1) != TEMPLATE_TYPE_IDX (t2)
-	  || TEMPLATE_TYPE_LEVEL (t1) != TEMPLATE_TYPE_LEVEL (t2))
+	  || TEMPLATE_TYPE_LEVEL (t1) != TEMPLATE_TYPE_LEVEL (t2)
+          || (TEMPLATE_TYPE_PARAMETER_PACK (t1) 
+              != TEMPLATE_TYPE_PARAMETER_PACK (t2)))
 	return false;
       break;
 
@@ -1081,6 +1085,10 @@ structural_comptypes (tree t1, tree t2, 
 	return false;
       break;
 
+    case TYPE_PACK_EXPANSION:
+      return same_type_p (PACK_EXPANSION_PATTERN (t1), 
+                          PACK_EXPANSION_PATTERN (t2));
+
     default:
       return false;
     }
@@ -6589,6 +6597,7 @@ check_return_expr (tree retval, bool *no
   if (processing_template_decl)
     {
       current_function_returns_value = 1;
+      check_for_bare_parameter_packs (retval);
       return retval;
     }
 
Index: decl.c
===================================================================
--- decl.c	(revision 122403)
+++ decl.c	(working copy)
@@ -6966,6 +6966,7 @@ grokdeclarator (const cp_declarator *dec
   cp_storage_class storage_class;
   bool unsigned_p, signed_p, short_p, long_p, thread_p;
   bool type_was_error_mark_node = false;
+  bool parameter_pack_p = declarator? declarator->parameter_pack_p : false;
   bool set_no_warning = false;
 
   signed_p = declspecs->specs[(int)ds_signed];
@@ -7937,6 +7938,16 @@ grokdeclarator (const cp_declarator *dec
 	attrlist = &returned_attrs;
     }
 
+  /* Handle parameter packs. */
+  if (parameter_pack_p)
+    {
+      if (decl_context == PARM)
+        /* Turn the type into a pack expansion.*/
+        type = make_pack_expansion (type);
+      else
+        error ("non-parameter %qs cannot be a parameter pack", name);
+    }
+
   /* Did array size calculations overflow?  */
 
   if (TREE_CODE (type) == ARRAY_TYPE
@@ -8936,6 +8947,11 @@ grokparms (cp_parameter_declarator *firs
 	    init = check_default_argument (decl, init);
 	}
 
+      if (TREE_CODE (decl) == PARM_DECL
+          && FUNCTION_PARAMETER_PACK_P (decl)
+          && parm->next)
+        error ("parameter packs must be at the end of the parameter list");
+
       TREE_CHAIN (decl) = decls;
       decls = decl;
       result = tree_cons (init, type, result);
@@ -9937,6 +9953,8 @@ xref_basetypes (tree ref, tree base_list
       if (access == access_default_node)
 	access = default_access;
 
+      if (PACK_EXPANSION_P (basetype))
+        basetype = PACK_EXPANSION_PATTERN (basetype);
       if (TREE_CODE (basetype) == TYPE_DECL)
 	basetype = TREE_TYPE (basetype);
       if (TREE_CODE (basetype) != RECORD_TYPE
@@ -9982,6 +10000,11 @@ xref_basetypes (tree ref, tree base_list
 	    error ("duplicate base type %qT invalid", basetype);
 	  return false;
 	}
+
+      if (PACK_EXPANSION_P (TREE_VALUE (base_list)))
+        /* Regenerate the paxpansion for the bases. */
+        basetype = make_pack_expansion (basetype);
+
       TYPE_MARKED_P (basetype) = 1;
 
       base_binfo = copy_binfo (base_binfo, basetype, ref,
@@ -11691,6 +11714,7 @@ cp_tree_node_structure (union lang_tree_
     case PTRMEM_CST:		return TS_CP_PTRMEM;
     case BASELINK:		return TS_CP_BASELINK;
     case STATIC_ASSERT:		return TS_CP_STATIC_ASSERT;
+    case ARGUMENT_PACK_SELECT:  return TS_CP_ARGUMENT_PACK_SELECT;
     default:			return TS_CP_GENERIC;
     }
 }
Index: cp-tree.def
===================================================================
--- cp-tree.def	(revision 122403)
+++ cp-tree.def	(working copy)
@@ -352,6 +352,76 @@ DEFTREECODE (UNARY_PLUS_EXPR, "unary_plu
    literal) to be displayed if the condition fails to hold.  */
 DEFTREECODE (STATIC_ASSERT, "static_assert", tcc_exceptional, 0)
 
+/* Represents an argument pack of types (or templates). An argument
+   pack stores zero or more arguments that will be used to instantiate
+   a parameter pack. 
+
+   ARGUMENT_PACK_ARGS retrieves the arguments stored in the argument
+   pack.
+
+   Example:
+     template<typename... Values>
+     class tuple { ... };
+
+     tuple<int, float, double> t;
+
+   Values is a (template) parameter pack. When tuple<int, float,
+   double> is instantiated, the Values parameter pack is instantiated
+   with the argment pack <int, float, double>. ARGUMENT_PACK_ARGS will
+   be a TREE_VEC containing int, fl, fl and double.  */
+DEFTREECODE (TYPE_ARGUMENT_PACK, "type_argument_pack", tcc_type, 0)
+
+/* Represents an argument pack of values, which can be used either for
+   non-type template arguments or function call arguments. 
+
+   NONTYPE_ARGUMENT_PACK plays precisely the same role as
+   TYPE_ARGUMENT_PACK, but will be used for packing non-type template
+   arguments (e.g., "int... Dimensions") or function arguments ("const
+   Args&... args"). */
+DEFTREECODE (NONTYPE_ARGUMENT_PACK, "nontype_argument_pack", tcc_expression, 1)
+
+/* Represents a type expression that will be expanded into a list of
+   types when instantiated with one or more argument packs.
+
+   PACK_EXPANSION_PATTERN retrieves the expansion pattern. This is
+   the type or expression that we will substitute into with each
+   argument in an argument pack.
+
+   SET_PACK_EXPANSION_PATTERN sets the expansion pattern.
+
+   PACK_EXPANSION_PARAMETER_PACKS contains a TREE_LIST of the parameter
+   packs that are used in this pack expansion.
+
+   Example:
+     template<typename... Values>
+     struct tied : tuple<Values&...> { 
+       // ...
+     };
+
+   The derivation from tuple contains a TYPE_PACK_EXPANSION for the
+   template arguments. Its EXPR_PACK_EXPANSION is "Values&" and its
+   PACK_EXPANSION_PARAMETER_PACKS will contain "Values".  */
+DEFTREECODE (TYPE_PACK_EXPANSION, "type_pack_expansion", tcc_type, 0)
+
+/* Represents an expression that will be expandeanded into a list of
+   expressions when instantiated with one or more argument packs.
+
+   EXPR_PACK_EXPANSION plays precisely the same role as TYPE_PACK_EXPANSION,
+   but will be used for expressions.  */
+DEFTREECODE (EXPR_PACK_EXPANSION, "expr_pack_expansion", tcc_expression, 1)
+
+/* Selects the Ith parameter out of an argument pack. This node will
+   be used when instantiating pack expansions; see
+   tsubst_pack_expansion. 
+
+   ARGUMENT_PACK_SELECT_FROM_PACK contains the *_ARGUMENT_PACK node
+   from which the argument will be selected.
+
+   ARGUMENT_PACK_SELECT_INDEX contains the index into the argument
+   pack that will be returned by this ARGUMENT_PACK_SELECT node. The
+   index is a machine integer.  */
+DEFTREECODE (ARGUMENT_PACK_SELECT, "argument_pack_select", tcc_exceptional, 0)
+
 /*
 Local variables:
 mode:c
Index: cp-objcp-common.c
===================================================================
--- cp-objcp-common.c	(revision 122403)
+++ cp-objcp-common.c	(working copy)
@@ -124,6 +124,17 @@ cp_tree_size (enum tree_code code)
     case DEFAULT_ARG:		return sizeof (struct tree_default_arg);
     case OVERLOAD:		return sizeof (struct tree_overload);
     case STATIC_ASSERT:         return sizeof (struct tree_static_assert);
+    case TYPE_ARGUMENT_PACK:
+    case TYPE_PACK_EXPANSION:
+      return sizeof (struct tree_common);
+
+    case NONTYPE_ARGUMENT_PACK:
+    case EXPR_PACK_EXPANSION:
+      return sizeof (struct tree_exp);
+
+    case ARGUMENT_PACK_SELECT:
+      return sizeof (struct tree_argument_pack_select);
+
     default:
       gcc_unreachable ();
     }
Index: error.c
===================================================================
--- error.c	(revision 122403)
+++ error.c	(working copy)
@@ -138,7 +138,9 @@ dump_scope (tree scope, int flags)
 static void
 dump_template_argument (tree arg, int flags)
 {
-  if (TYPE_P (arg) || TREE_CODE (arg) == TEMPLATE_DECL)
+  if (ARGUMENT_PACK_P (arg))
+    dump_template_argument_list (ARGUMENT_PACK_ARGS (arg), flags);
+  else if (TYPE_P (arg) || TREE_CODE (arg) == TEMPLATE_DECL)
     dump_type (arg, flags & ~TFF_CLASS_KEY_OR_ENUM);
   else
     dump_expr (arg, (flags | TFF_EXPR_IN_PARENS) & ~TFF_CLASS_KEY_OR_ENUM);
@@ -156,9 +158,17 @@ dump_template_argument_list (tree args, 
 
   for (i = 0; i< n; ++i)
     {
-      if (need_comma)
+      tree arg = TREE_VEC_ELT (args, i);
+
+      /* Only print a comma if we know there is an argument coming. In
+         the case of an empty template argument pack, no actual
+         argument will be printed.  */
+      if (need_comma
+          && (!ARGUMENT_PACK_P (arg)
+              || TREE_VEC_LENGTH (ARGUMENT_PACK_ARGS (arg)) > 0))
 	pp_separate_with_comma (cxx_pp);
-      dump_template_argument (TREE_VEC_ELT (args, i), flags);
+
+      dump_template_argument (arg, flags);
       need_comma = 1;
     }
 }
@@ -182,6 +192,8 @@ dump_template_parameter (tree parm, int 
       if (flags & TFF_DECL_SPECIFIERS)
 	{
 	  pp_cxx_identifier (cxx_pp, "class");
+          if (TEMPLATE_TYPE_PARAMETER_PACK (TREE_TYPE (p)))
+            pp_cxx_identifier (cxx_pp, "...");
 	  if (DECL_NAME (p))
 	    pp_cxx_tree_identifier (cxx_pp, DECL_NAME (p));
 	}
@@ -378,6 +390,11 @@ dump_type (tree t, int flags)
       pp_cxx_right_paren (cxx_pp);
       break;
 
+    case TYPE_PACK_EXPANSION:
+      dump_type (PACK_EXPANSION_PATTERN (t), flags);
+      pp_cxx_identifier (cxx_pp, "...");
+      break;
+
     default:
       pp_unsupported_tree (cxx_pp, t);
       /* Fall through to error.  */
@@ -1102,8 +1119,8 @@ dump_function_decl (tree t, int flags)
 static void
 dump_parameters (tree parmtypes, int flags)
 {
-  int first;
-
+  int first = 1;
+  int was_first;
   pp_cxx_left_paren (cxx_pp);
 
   for (first = 1; parmtypes != void_list_node;
@@ -1111,13 +1128,34 @@ dump_parameters (tree parmtypes, int fla
     {
       if (!first)
 	pp_separate_with_comma (cxx_pp);
+      was_first = first;
       first = 0;
       if (!parmtypes)
 	{
 	  pp_cxx_identifier (cxx_pp, "...");
 	  break;
 	}
-      dump_type (TREE_VALUE (parmtypes), flags);
+      if (ARGUMENT_PACK_P (TREE_VALUE (parmtypes)))
+        {
+          tree types = ARGUMENT_PACK_ARGS (TREE_VALUE (parmtypes));
+          int i, len = TREE_VEC_LENGTH (types);
+          for (i = 0; i < len; ++i)
+            {
+              if (!first)
+                pp_separate_with_comma (cxx_pp);
+              first = 0;
+              
+              dump_type (TREE_VEC_ELT (types, i), flags);
+            }
+
+          if (len == 0 && was_first)
+            /* The argument pack came at the beginning, but it was
+               empty. We should not emit a comma before the next
+               parameter type.  */
+            first = 1;
+        }
+      else
+        dump_type (TREE_VALUE (parmtypes), flags);
 
       if ((flags & TFF_FUNCTION_DEFAULT_ARGUMENTS) && TREE_PURPOSE (parmtypes))
 	{
@@ -1240,14 +1278,19 @@ dump_template_parms (tree info, int prim
 	{
 	  tree arg = TREE_VEC_ELT (args, ix);
 
-	  if (ix)
-	    pp_separate_with_comma (cxx_pp);
-
-	  if (!arg)
-	    pp_identifier (cxx_pp, "<template parameter error>");
-	  else
-	    dump_template_argument (arg, flags);
-	}
+          /* Only print a comma if we know there is an argument coming. In
+             the case of an empty template argument pack, no actual
+             argument will be printed.  */
+          if (ix
+              && (!ARGUMENT_PACK_P (arg)
+                  || TREE_VEC_LENGTH (ARGUMENT_PACK_ARGS (arg)) > 0))
+            pp_separate_with_comma (cxx_pp);
+          
+          if (!arg)
+            pp_identifier (cxx_pp, "<template parameter error>");
+          else
+            dump_template_argument (arg, flags);
+        }
     }
   else if (primary)
     {
@@ -1946,6 +1989,11 @@ dump_expr (tree t, int flags)
       dump_expr (TREE_OPERAND (t, 0), flags);
       break;
 
+    case EXPR_PACK_EXPANSION:
+      dump_expr (PACK_EXPANSION_PATTERN (t), flags);
+      pp_cxx_identifier (cxx_pp, "...");
+      break;
+
       /*  This list is incomplete, but should suffice for now.
 	  It is very important that `sorry' does not call
 	  `report_error_function'.  That could cause an infinite loop.  */
@@ -2464,3 +2512,14 @@ cp_cpp_error (cpp_reader *pfile ATTRIBUT
 				  input_location, dlevel);
   report_diagnostic (&diagnostic);
 }
+
+/* Warn about the use of variadic templates when appropriate.  */
+void
+maybe_warn_variadic_templates (void)
+{
+  if ((!flag_cpp0x || flag_iso) && !in_system_header)
+    /* We really want to surpress this warning in system headers,
+       because libstdc++ uses variadic templates even when we aren't
+       in C++0x mode. */
+    pedwarn ("ISO C++ does not include variadic templates");
+}
Index: operators.def
===================================================================
--- operators.def	(revision 122403)
+++ operators.def	(working copy)
@@ -150,3 +150,6 @@ DEF_SIMPLE_OPERATOR ("?:", COND_EXPR, "q
 
 /* Miscellaneous.  */
 DEF_SIMPLE_OPERATOR ("()", CALL_EXPR, "cl", -1)
+
+/* Variadic templates extension. */
+DEF_SIMPLE_OPERATOR ("...", EXPR_PACK_EXPANSION, "pu", 1)
Index: tree.c
===================================================================
--- tree.c	(revision 122403)
+++ tree.c	(working copy)
@@ -2229,12 +2229,16 @@ cp_walk_subtrees (tree *tp, int *walk_su
     case TEMPLATE_TYPE_PARM:
     case TYPENAME_TYPE:
     case TYPEOF_TYPE:
-    case BASELINK:
       /* None of these have subtrees other than those already walked
 	 above.  */
       *walk_subtrees_p = 0;
       break;
 
+    case BASELINK:
+      WALK_SUBTREE (BASELINK_FUNCTIONS (*tp));
+      *walk_subtrees_p = 0;
+      break;
+
     case TINST_LEVEL:
       WALK_SUBTREE (TINST_DECL (*tp));
       *walk_subtrees_p = 0;
@@ -2260,6 +2264,38 @@ cp_walk_subtrees (tree *tp, int *walk_su
 	WALK_SUBTREE (TYPE_PTRMEMFUNC_FN_TYPE (*tp));
       break;
 
+    case TYPE_ARGUMENT_PACK:
+    case NONTYPE_ARGUMENT_PACK:
+      {
+        tree args = ARGUMENT_PACK_ARGS (*tp);
+        int i, len = TREE_VEC_LENGTH (args);
+        for (i = 0; i < len; i++)
+          WALK_SUBTREE (TREE_VEC_ELT (args, i));
+      }
+      break;
+
+    case TYPE_PACK_EXPANSION:
+      WALK_SUBTREE (TREE_TYPE (*tp));
+      *walk_subtrees_p = 0;
+      break;
+      
+    case EXPR_PACK_EXPANSION:
+      WALK_SUBTREE (TREE_OPERAND (*tp, 0));
+      *walk_subtrees_p = 0;
+      break;
+
+    case CAST_EXPR:
+      if (TREE_TYPE (*tp))
+	WALK_SUBTREE (TREE_TYPE (*tp));
+
+      {
+        int i;
+        for (i = 0; i < TREE_CODE_LENGTH (TREE_CODE (*tp)); ++i)
+	  WALK_SUBTREE (TREE_OPERAND (*tp, i));
+      }
+      *walk_subtrees_p = 0;
+      break;
+
     default:
       input_location = save_locus;
       return NULL_TREE;
Index: mangle.c
===================================================================
--- mangle.c	(revision 122403)
+++ mangle.c	(working copy)
@@ -1645,6 +1645,11 @@ write_type (tree type)
 	  write_type (TREE_TYPE (type));
 	  break;
 
+        case TYPE_PACK_EXPANSION:
+          write_string ("U10__variadic");
+          write_type (PACK_EXPANSION_PATTERN (type));
+          break;
+
 	default:
 	  gcc_unreachable ();
 	}
@@ -2302,7 +2307,15 @@ write_template_arg (tree node)
 	G.need_abi_warning = 1;
     }
 
-  if (TYPE_P (node))
+  if (ARGUMENT_PACK_P (node))
+    {
+      /* Expand the template argument pack. */
+      tree args = ARGUMENT_PACK_ARGS (node);
+      int i, length = TREE_VEC_LENGTH (args);
+      for (i = 0; i < length; ++i)
+        write_template_arg (TREE_VEC_ELT (args, i));
+    }
+  else if (TYPE_P (node))
     write_type (node);
   else if (code == TEMPLATE_DECL)
     /* A template appearing as a template arg is a template template arg.  */
Index: cp-tree.h
===================================================================
--- cp-tree.h	(revision 122403)
+++ cp-tree.h	(working copy)
@@ -103,6 +103,7 @@ struct diagnostic_context;
    1: C_TYPEDEF_EXPLICITLY_SIGNED (in TYPE_DECL).
       DECL_TEMPLATE_INSTANTIATED (in a VAR_DECL or a FUNCTION_DECL)
       DECL_MEMBER_TEMPLATE_P (in TEMPLATE_DECL)
+      FUNCTION_PARAMETER_PACK_P (in PARM_DECL)
    2: DECL_THIS_EXTERN (in VAR_DECL or FUNCTION_DECL).
       DECL_IMPLICIT_TYPEDEF_P (in a TYPE_DECL)
    3: DECL_IN_AGGR_P.
@@ -222,6 +223,10 @@ struct template_parm_index_s GTY(())
   HOST_WIDE_INT level;
   HOST_WIDE_INT orig_level;
   tree decl;
+
+  /* When true, indicates that this parameter is actually a parameter
+     pack, for variadic templates.  */
+  BOOL_BITFIELD parameter_pack;
 };
 typedef struct template_parm_index_s template_parm_index;
 
@@ -469,6 +474,13 @@ struct tree_static_assert GTY (())
   location_t location;
 };
 
+struct tree_argument_pack_select GTY (())
+{
+  struct tree_common common;
+  tree argument_pack;
+  int index;
+};
+
 enum cp_tree_node_structure_enum {
   TS_CP_GENERIC,
   TS_CP_IDENTIFIER,
@@ -481,6 +493,7 @@ enum cp_tree_node_structure_enum {
   TS_CP_WRAPPER,
   TS_CP_DEFAULT_ARG,
   TS_CP_STATIC_ASSERT,
+  TS_CP_ARGUMENT_PACK_SELECT,
   LAST_TS_CP_ENUM
 };
 
@@ -499,6 +512,8 @@ union lang_tree_node GTY((desc ("cp_tree
   struct lang_identifier GTY ((tag ("TS_CP_IDENTIFIER"))) identifier;
   struct tree_static_assert GTY ((tag ("TS_CP_STATIC_ASSERT"))) 
     static_assertion;
+  struct tree_argument_pack_select GTY ((tag ("TS_CP_ARGUMENT_PACK_SELECT")))
+    argument_pack_select;
 };
 
 
@@ -2188,7 +2203,7 @@ extern void decl_shadowed_for_var_insert
 /* Nonzero if the template arguments is actually a vector of vectors,
    rather than just a vector.  */
 #define TMPL_ARGS_HAVE_MULTIPLE_LEVELS(NODE)		\
-  (NODE && TREE_VEC_ELT (NODE, 0)			\
+  (NODE && TREE_VEC_ELT (NODE, 0)                       \
    && TREE_CODE (TREE_VEC_ELT (NODE, 0)) == TREE_VEC)
 
 /* The depth of a template argument vector.  When called directly by
@@ -2295,6 +2310,84 @@ extern void decl_shadowed_for_var_insert
    the class definition is complete.  */
 #define TEMPLATE_PARMS_FOR_INLINE(NODE) TREE_LANG_FLAG_1 (NODE)
 
+/* Determine if a parameter (i.e., a PARM_DECL) is a function
+   parameter pack.  */
+#define FUNCTION_PARAMETER_PACK_P(NODE) \
+  (DECL_LANG_FLAG_1 (PARM_DECL_CHECK (NODE)))
+
+/* Determines if NODE is an expansion of one or more parameter packs,
+   e.g., a TYPE_PACK_EXPANSION or EXPR_PACK_EXPANSION.  */
+#define PACK_EXPANSION_P(NODE)                 \
+  (TREE_CODE (NODE) == TYPE_PACK_EXPANSION     \
+   || TREE_CODE (NODE) == EXPR_PACK_EXPANSION)
+
+/* Extracts the type or expression pattern from a TYPE_PACK_EXPANSION or
+   EXPR_PACK_EXPANSION.  */
+#define PACK_EXPANSION_PATTERN(NODE)                            \
+  (TREE_CODE (NODE) == TYPE_PACK_EXPANSION? TREE_TYPE (NODE)    \
+   : TREE_OPERAND (NODE, 0))
+
+/* Sets the type or expion pattern for a TYPE_PACK_EXPANSION or
+   EXPR_PACK_EXPANSION.  */
+#define SET_PACK_EXPANSION_PATTERN(NODE,VALUE)  \
+  if (TREE_CODE (NODE) == TYPE_PACK_EXPANSION)  \
+    TREE_TYPE (NODE) = VALUE;                   \
+  else                                          \
+    TREE_OPERAND (NODE, 0) = VALUE
+
+/* The list of parameter packs used in the PACK_EXPANSION_* node. The
+   TREE_VALUE of each TREE_LIST contains the parameter packs.  */
+#define PACK_EXPANSION_PARAMETER_PACKS(NODE) TREE_CHAIN (NODE)
+
+/* Determine if this is an argument pack.  */
+#define ARGUMENT_PACK_P(NODE)                          \
+  (TREE_CODE (NODE) == TYPE_ARGUMENT_PACK              \
+   || TREE_CODE (NODE) == NONTYPE_ARGUMENT_PACK)
+
+/* The arguments stored in an argument pack. Arguments are stored in a
+   TREE_VEC, which may have length zero.  */
+#define ARGUMENT_PACK_ARGS(NODE)                               \
+  (TREE_CODE (NODE) == TYPE_ARGUMENT_PACK? TREE_TYPE (NODE)    \
+   : TREE_OPERAND (NODE, 0))
+
+/* Set the arguments stored in an argument pack. VALUE must be a
+   TREE_VEC.  */
+#define SET_ARGUMENT_PACK_ARGS(NODE,VALUE)     \
+  if (TREE_CODE (NODE) == TYPE_ARGUMENT_PACK)  \
+    TREE_TYPE (NODE) = VALUE;                           \
+  else                                                  \
+    TREE_OPERAND (NODE, 0) = VALUE
+
+/* Whether the argument pack is "incomplete", meaning that more
+   arguments can still be deduced. In. Incomplete argument packs are only
+   used when the user has provided an explicit template argument list
+   for a variadic function template. Some of the explicit template
+   arguments will be placed into the beginning of the argument pack,
+   but additional arguments might still be deduced.  */
+#define ARGUMENT_PACK_INCOMPLETE_P(NODE)        \
+  TREE_LANG_FLAG_0 (ARGUMENT_PACK_ARGS (NODE))
+
+/* When ARGUMENT_PACK_INCOMPLETE_P, stores the explicit template
+   arguments used to fill this pack.  */
+#define ARGUMENT_PACK_EXPLICIT_ARGS(NODE)       \
+  TREE_TYPE (ARGUMENT_PACK_ARGS (NODE))
+
+/* In an ARGUMENT_PACK_SELECT, the argument pack from which an
+   argument will be selected.  */
+#define ARGUMENT_PACK_SELECT_FROM_PACK(NODE)				\
+  (((struct tree_argument_pack_select *)ARGUMENT_PACK_SELECT_CHECK (NODE))->argument_pack)
+
+/* In an ARGUMENT_PACK_SELECT, the index of the argument we want to
+   select.  */
+#define ARGUMENT_PACK_SELECT_INDEX(NODE)				\
+  (((struct tree_argument_pack_select *)ARGUMENT_PACK_SELECT_CHECK (NODE))->index)
+  
+/* In an ARGUMENT_PACK_SELECT, the actual underlying argument that the
+   ARGUMENT_PACK_SELECT represents. */
+#define ARGUMENT_PACK_SELECT_ARG(NODE)					\
+  TREE_VEC_ELT (ARGUMENT_PACK_ARGS (ARGUMENT_PACK_SELECT_FROM_PACK (NODE)), \
+	        ARGUMENT_PACK_SELECT_INDEX (NODE));
+
 /* In a FUNCTION_DECL, the saved language-specific per-function data.  */
 #define DECL_SAVED_FUNCTION_DATA(NODE)			\
   (DECL_LANG_SPECIFIC (FUNCTION_DECL_CHECK (NODE))	\
@@ -3612,6 +3705,7 @@ enum overload_flags { NO_SPECIAL = 0, DT
 #define TEMPLATE_PARM_DESCENDANTS(NODE) (TREE_CHAIN (NODE))
 #define TEMPLATE_PARM_ORIG_LEVEL(NODE) (TEMPLATE_PARM_INDEX_CAST (NODE)->orig_level)
 #define TEMPLATE_PARM_DECL(NODE) (TEMPLATE_PARM_INDEX_CAST (NODE)->decl)
+#define TEMPLATE_PARM_PARAMETER_PACK(NODE) (TEMPLATE_PARM_INDEX_CAST (NODE)->parameter_pack)
 
 /* These macros are for accessing the fields of TEMPLATE_TYPE_PARM,
    TEMPLATE_TEMPLATE_PARM and BOUND_TEMPLATE_TEMPLATE_PARM nodes.  */
@@ -3626,6 +3720,8 @@ enum overload_flags { NO_SPECIAL = 0, DT
   (TEMPLATE_PARM_ORIG_LEVEL (TEMPLATE_TYPE_PARM_INDEX (NODE)))
 #define TEMPLATE_TYPE_DECL(NODE) \
   (TEMPLATE_PARM_DECL (TEMPLATE_TYPE_PARM_INDEX (NODE)))
+#define TEMPLATE_TYPE_PARAMETER_PACK(NODE) \
+  (TEMPLATE_PARM_PARAMETER_PACK (TEMPLATE_TYPE_PARM_INDEX (NODE)))
 
 /* These constants can used as bit flags in the process of tree formatting.
 
@@ -3812,6 +3908,9 @@ struct cp_declarator {
      cdk_id and cdk_error, guaranteed to be NULL.  */
   cp_declarator *declarator;
   location_t id_loc; /* Currently only set for cdk_id. */
+  /* Whether we parsed an ellipsis (`...') just before the declarator,
+     to indicate this is a parameter pack.  */
+  bool parameter_pack_p;
   union {
     /* For identifiers.  */
     struct {
@@ -4103,6 +4202,7 @@ extern const char *lang_decl_name		(tree
 extern t char *language_to_string		(enum languages);
 extern const char *class_key_or_enum_as_string	(tree);
 extern void print_instantiation_context		(void);
+extern void maybe_warn_variadic_templates       (void);
 
 /* in except.c */
 extern void init_exception_processing		(void);
@@ -4192,7 +4292,7 @@ extern void end_specialization			(void);
 extern void begin_explicit_instantiation	(void);
 extern void end_explicit_instantiation		(void);
 extern tree check_explicit_specialization	(tree, tree, int, int);
-extern tree process_template_parm		(tree, tree, bool);
+extern tree process_template_parm		(tree, tree, bool, bool);
 extern tree end_template_parm_list		(tree);
 extern void end_template_decl			(void);
 extern tree push_template_decl			(tree);
@@ -4213,6 +4313,11 @@ extern void do_decl_instantiation		(tree
 extern void do_type_instantiation		(tree, tree, tsubst_flags_t);
 extern tree instantiate_decl			(tree, int, bool);
 extern int comp_template_parms			(tree, tree);
+extern bool uses_parameter_packs                (tree);
+extern bool template_parameter_pack_p           (tree);
+extern bool template_parms_variadic_p           (tree);
+extern tree make_pack_expansion                 (tree);
+extern void check_for_bare_parameter_packs      (tree);
 extern int template_class_depth			(tree);
 extern int is_specialization_of			(tree, tree);
 extern bool is_specialization_of_friend		(tree, tree);
Index: cxx-pretty-print.c
===================================================================
--- cxx-pretty-print.c	(revision 122403)
+++ cxx-pretty-print.c	(working copy)
@@ -659,6 +659,7 @@ pp_cxx_delete_expression (cxx_pretty_pri
       unary-operator cast-expression
       sizeof unary-expression
       sizeof ( type-id )
+      sizeof ... ( identifier )
       new-expression
       delete-expression
 
@@ -686,6 +687,21 @@ pp_cxx_unary_expression (cxx_pretty_prin
       break;
 
     case SIZEOF_EXPR:
+      if (PACK_EXPANSION_P (TREE_OPERAND (t, 0)))
+	{
+	  pp_cxx_identifier (pp, "sizeof");
+	  pp_cxx_identifier (pp, "...");
+	  pp_cxx_whitespace (pp);
+	  pp_cxx_left_paren (pp);
+	  if (TYPE_P (TREE_OPERAND (t, 0)))
+	    pp_cxx_type_id (pp, TREE_OPERAND (t, 0));
+	  else
+	    pp_unary_expression (pp, TREE_OPERAND (t, 0));
+	  pp_cxx_right_paren (pp);
+	  break;
+	}
+      /* Fall through  */
+
     case ALIGNOF_EXPR:
       pp_cxx_identifier (pp, code == SIZEOF_EXPR ? "sizeof" : "__alignof__");
       pp_cxx_whitespace (pp);
@@ -1000,6 +1016,24 @@ pp_cxx_expression (cxx_pretty_printer *p
       pp_cxx_expression (pp, t);
       break;
 
+    case EXPR_PACK_EXPANSION:
+      pp_cxx_expression (pp, PACK_EXPANSION_PATTERN (t));
+      pp_cxx_identifier (pp, "...");
+      break;
+
+    case NONTYPE_ARGUMENT_PACK:
+      {
+	tree args = ARGUMENT_PACK_ARGS (t);
+	int i, len = TREE_VEC_LENGTH (args);
+	for (i = 0; i < len; ++i)
+	  {
+	    if (i > 0)
+	      pp_cxx_separatarate_with (pp, ',');
+	    pp_cxx_expression (pp, TREE_VEC_ELT (args, i));
+	  }
+      }
+      break;
+
     default:
       pp_c_expression (pp_c_base (pp), t);
       break;
@@ -1290,6 +1324,7 @@ static void
 pp_cxx_exception_specification (cxx_pretty_printer *pp, tree t)
 {
   tree ex_spec = TYPE_RAISES_EXCEPTIONS (t);
+  bool need_comma = false;
 
   if (!TYPE_NOTHROW_P (t) && ex_spec == NULL)
     return;
@@ -1297,9 +1332,28 @@ pp_cxx_exception_specification (cxx_pret
   pp_cxx_left_paren (pp);
   for (; ex_spec && TREE_VALUE (ex_spec); ex_spec = TREE_CHAIN (ex_spec))
     {
-      pp_cxx_type_id (pp, TREE_VALUE (ex_spec));
-      if (TREE_CHAIN (ex_spec))
-	pp_cxx_separate_with (pp, ',');
+      tree type = TREE_VALUE (ex_spec);
+      tree argpack = NULL_TREE;
+      int i, len = 1;
+
+      if (ARGUMENT_PACK_P (type))
+	{
+	  argpack = ARGUMENT_PACK_ARGS (type);
+	  len = TREE_VEC_LENGTH (argpack);
+	}
+
+      for (i = 0; i < len; ++i)
+	{
+	  if (argpack)
+	    type = TREE_VEC_ELT (argpack, i);
+
+	  if (need_comma)
+	    pp_cxx_separate_with (pp, ',');
+	  else
+	    need_comma = true;
+
+	  pp_cxx_type_id (pp, type);
+	}
     }
   pp_cxx_right_paren (pp);
 }
@@ -1323,6 +1377,13 @@ pp_cxx_direct_declarator (cxx_pretty_pri
       if (DECL_NAME (t))
 	{
 	  pp_cxx_space_for_pointer_operator (pp, TREE_TYPE (t));
+
+	  if ((TREE_CODE (t) == PARM_DECL && FUNCTION_PARAMETER_PACK_P (t))
+	      || template_parameter_pack_p (t))
+	    /* A function parameter pack or non-type template
+	       parameter pack.  */
+	    pp_cxx_identifier (pp, "...");
+		      
 	  pp_cxx_id_expression (pp, DECL_NAME (t));
 	}
       pp_cxx_abstract_declarator (pp, TREE_TYPE (t));
@@ -1388,8 +1449,16 @@ pp_cxx_ctor_initializer (cxx_pretty_prin
   pp_cxx_whitespace (pp);
   for (; t; t = TREE_CHAIN (t))
     {
-      pp_cxx_primary_expression (pp, TREE_PURPOSE (t));
+      tree purpose = TREE_PURPOSE (t);
+      bool is_pack = PACK_EXPANSION_P (purpose);
+
+      if (is_pack)
+	pp_cxx_primary_expression (pp, PACK_EXPANSION_PATTERN (purpose));
+      else
+	pp_cxx_primary_expression (pp, purpose);
       pp_cxx_call_argument_list (pp, TREE_VALUE (t));
+      if (is_pack)
+	pp_cxx_identifier (pp, "...");
       if (TREE_CHAIN (t))
 	pp_cxx_separate_with (pp, ',');
     }
@@ -1510,6 +1579,11 @@ pp_cxx_type_id (cxx_pretty_printer *pp, 
       pp_cxx_type_specifier_seq (pp, t);
       break;
 
+    case TYPE_PACK_EXPANSION:
+      pp_cxx_type_id (pp, PACK_EXPANSION_PATTERN (t));
+      pp_cxx_identifier (pp, "...");
+      break;
+
     default:
       pp_c_type_id (pp_c_base (pp), t);
       break;
@@ -1519,30 +1593,50 @@ pp_cxx_type_id (cxx_pretty_printer *pp, 
 }
 
 /* template-argument-list:
-      template-argument
-      template-argument-list, template-argument
+      template-argument ...(opt)
+      template-argument-list, template-argument ...(opt)
 
    template-argument:
       assignment-expression
       type-id
-      template-name   */
+      template-name  */
 
 static void
 pp_cxx_template_argument_list (cxx_pretty_printer *pp, tree t)
 {
   int i;
+  bool need_comma = false;
+
   if (t == NULL)
     return;
   for (i = 0; i < TREE_VEC_LENGTH (t); ++i)
     {
       tree arg = TREE_VEC_ELT (t, i);
-      if (i != 0)
-	pp_cxx_separate_with (pp, ',');
-      if (TYPE_P (arg) || (TREE_CODE (arg) == TEMPLATE_DECL
-			   && TYPE_P (DECL_TEMPLATE_RESULT (arg))))
-	pp_cxx_type_id (pp, arg);
-      else
-	pp_cxx_expression (pp, arg);
+      tree argpack = NULL_TREE;
+      int idx, len = 1;
+
+      if (ARGUMENT_PACK_P (arg))
+	{
+	  argpack = ARGUMENT_PACK_ARGS (arg);
+	  len = TREE_VEC_LENGTH (argpack);
+	}
+
+      for (idx = 0; idx < len; idx++)
+	{
+	  if (argpack)
+	    arg = TREE_VEC_ELT (argpack, idx);
+	  
+	  if (need_comma)
+	    pp_cxx_separate_with (pp, ',');
+	  else
+	    need_comma = true;
+
+	  if (TYPE_P (arg) || (TREE_CODE (arg) == TEMPLATE_DECL
+			       && TYPE_P (DECL_TEMPLATE_RESULT (arg))))
+	    pp_cxx_type_id (pp, arg);
+	  else
+	    pp_cxx_expression (pp, arg);
+	}
     }
 }
 
@@ -1837,11 +1931,11 @@ pp_cxx_template_parameter_list (cxx_pret
       parameter-declaration
 
    type-parameter:
-     class identifier(opt)
-     class identifier(op) = type-id
+     class ...(opt) identifier(opt)
+     class identifier(opt) = type-id
      typename identifier(opt)
-     typename identifier(opt) = type-id
-     template < template-parameter-list > class identifier(opt)
+     typename ...(opt) identifier(opt) = type-id
+     template < template-parameter-list > class ...(opt) identifier(opt)
      template < template-parameter-list > class identifier(opt) = template-name  */
 
 static void
@@ -1852,6 +1946,8 @@ pp_cxx_template_parameter (cxx_pretty_pr
     {
     case TYPE_DECL:
       pp_cxx_identifier (pp, "class");
+      if (TEMPLATE_TYPE_PARAMETER_PACK (TREE_TYPE (t)))
+	pp_cxx_identifier (pp, "...");
       if (DECL_NAME (parameter))
 	pp_cxx_tree_identifier (pp, DECL_NAME (parameter));
       /* FIXME: Chech if we should print also default argument.  */
Index: pt.c
===================================================================
--- pt.c	(revision 122403)
+++ pt.c	(working copy)
@@ -124,6 +124,7 @@ static tree convert_template_argument (t
 				       tsubst_flags_t, int, tree);
 static int for_each_template_parm (tree, tree_fn_t, void*,
 				   struct pointer_set_t*);
+static tree expand_template_argument_pack (tree);
 static tree build_template_parm_index (int, int, int, tree, tree);
 static int inline_needs_template_parms (tree);
 static void push_inline_template_parms_recursive (tree, int);
@@ -138,6 +139,8 @@ static int can_complete_type_without_cir
 static tree get_bindings (tree, tree, tree, bool);
 static int template_decl_level (tree);
 static int check_cv_quals_for_unify (int, tree, tree);
+static void template_parm_level_and_index (tree, int*, int*);
+static int unify_pack_expansion (tree, tree, tree, tree, int, bool, bool);
 static tree tsubst_template_arg (tree, tree, tsubst_flags_t, tree);
 static tree tsubst_template_args (tree, tree, tsubst_flags_t, tree);
 static tree tsubst_template_parms (tree, tree, tsubst_flags_t);
@@ -161,11 +164,13 @@ static tree copy_default_args_to_explici
 static void copy_default_args_to_explicit_spec (tree);
 static int invalid_nontype_parm_type_p (tree, tsubst_flags_t);
 static int eq_local_specializations (const void *, const void *);
+static bool dependent_template_arg_p (tree);
 static bool any_template_arguments_need_structural_equality_p (tree);
 static bool dependent_type_p_r (tree);
 static tree tsubst (tree, tree, tsubst_flags_t, tree);
 static tree tsubst_expr	(tree, tree, tsubst_flags_t, tree, bool);
 static tree tsubst_copy	(tree, tree, tsubst_flags_t, tree);
+static tree tsubst_pack_expansion (tree, tree, tsubst_flags_t, tree);
 
 /* Make the current scope suitable for access checking when we are
    processing T.  T can be FUNCTION_DECL for instantiated function
@@ -2262,7 +2267,9 @@ comp_template_parms (tree parms1, tree p
 	  if (TREE_CODE (parm1) != TREE_CODE (parm2))
 	    return 0;
 
-	  if (TREE_CODE (parm1) == TEMPLATE_TYPE_PARM)
+	  if (TREE_CODE (parm1) == TEMPLATE_TYPE_PARM
+              && (TEMPLATE_TYPE_PARAMETER_PACK (parm1)
+                  == TEMPLATE_TYPE_PARAMETER_PACK (parm2)))
 	    continue;
 	  else if (!same_type_p (TREE_TYPE (parm1), TREE_TYPE (parm2)))
 	    return 0;
@@ -2277,6 +2284,402 @@ comp_template_parms (tree parms1, tree p
   return 1;
 }
 
+/* Determine whether PARM is a parameter pack.  */
+bool 
+template_parameter_pack_p (tree parm)
+{
+  /* Determine if we have a non-type template parameter pack.  */
+  if (TREE_CODE (parm) == PARM_DECL)
+    return (DECL_TEMPLATE_PARM_P (parm) 
+            && TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (parm)));
+
+  /* If this is a list of template parameters, we could get a
+     TYPE_DECL or a TEMPLATE_DECL.  */ 
+  if (TREE_CODE (parm) == TYPE_DECL || TREE_CODE (parm) == TEMPLATE_DECL)
+    parm = TREE_TYPE (parm);
+
+  return ((TREE_CODE (parm) == TEMPLATE_TYPE_PARM
+	   || TREE_CODE (parm) == TEMPLATE_TEMPLATE_PARM)
+	  && TEMPLATE_TYPE_PARAMETER_PACK (parm));
+}
+
+/* Determine whether PARMS describes a variadic template parameter
+   list, i.e., one that is terminated by a template parameter pack.  */
+bool 
+template_parms_variadic_p (tree parms)
+{
+  int nparms = TREE_VEC_LENGTH (parms);
+  tree last_parm = TREE_VALUE (TREE_VEC_ELT (parms, nparms - 1));
+  
+  return template_parameter_pack_p (last_parm);
+}
+
+/* Determine whether ARGS describes a variadic template args list,
+   i.e., one that is terminated by a template argument pack.  */
+static bool 
+template_args_variadic_p (tree args)
+{
+  int nargs;
+  tree last_parm;
+
+  if (args == NULL_TREE)
+    return false;
+
+  args = INNERMOST_TEMPLATE_ARGS (args);
+  nargs = TREE_VEC_LENGTH (args);
+
+  if (nargs == 0)
+    return false;
+
+  last_parm = TREE_VEC_ELT (args, nargs - 1);
+
+  return ARGUMENT_PACK_P (last_parm);
+}
+
+/* Generate a new name for the parameter pack name NAME (an
+   IDENTIFIER_NODE) that incorporates its */
+static tree
+make_ith_pack_parameter_name (tree name, int i)
+{
+  /* Munge the name to include the parameter index.  */
+  char numbuf[128];
+  char* newname;
+  
+  sprintf(numbuf, "%i", i);
+  newname = (char*)alloca (IDENTIFIER_LENGTH (name) + strlen(numbuf) + 2);
+  sprintf(newname, "%s#%i", IDENTIFIER_POINTER (name), i);
+  return get_identifier (newname);
+}
+
+/* Structure used to track the progress of find_parameter_pack_r.  */
+struct find_parameter_pack_data 
+{
+  tree* parameter_packs;
+  struct pointer_set_t *visited;
+};
+
+/* Identifiers all of the argument packs that occur in a template
+   argument and appends them to the TREE_LIST inside DATA, which is a
+   find_parameter_pack_Data structure. This is a subroutine of
+   make_pack_expansion and uses_parameter_packs.  */
+static tree
+find_parameter_packs_r (tree *tp, int *walk_subtrees, void* data)
+{
+  tree t = *tp;
+  struct find_parameter_pack_data* ppd = 
+    (struct find_parameter_pack_data*)data;
+
+  if (TYPE_P (t))
+    {
+      tree context = TYPE_CONTEXT (t);
+      walk_tree (&context, &find_parameter_packs_r, ppd, ppd->visited);
+    }
+
+  /* This switch statement will return immediately if we don't find a
+     parameter pack.  */
+  switch (TREE_CODE (t)) 
+    {
+    case TEMPLATE_PARM_INDEX:
+      if (TEMPLATE_PARM_PARAMETER_PACK (t))
+        break;
+      return NULL_TREE;
+
+    case BOUND_TEMPLATE_TEMPLATE_PARM:
+      /* Check the template arguments.  */
+      walk_tree (&TYPE_TI_ARGS (t), &find_parameter_packs_r, ppd, 
+		 ppd->visited);
+
+      /* Dig out the underlying TEMPLATE_TEMPLATE_PARM.  */
+      t = TYPE_TI_TEMPLATE (t);
+      if (DECL_P (t) && TREE_TYPE (t))
+        t = TREE_TYPE (t);
+      *walk_subtrees = 0;
+      
+      /* Fall through.  */
+
+    case TEMPLATE_TYPE_PARM:
+    case TEMPLATE_TEMPLATE_PARM:
+      if (TEMPLATE_TYPE_PARAMETER_PACK (t))
+        break;
+      return NULL_TREE;
+
+    case PARM_DECL:
+      if (FUNCTION_PARAMETER_PACK_P (t))
+        {
+          /* We don't want to walk into the type of a PARM_DECL,
+             because we don't want to see the type parameter pack.*/
+          *walk_subtrees = 0;
+          break;
+        }
+      return NULL_TREE;
+
+    case RECORD_TYPE:
+      if (TYPE_PTRMEMFUNC_P (t))
+	return NULL_TREE;
+      /* Fall through.  */
+
+    case UNION_TYPE:
+    case ENUMERAL_TYPE:
+      if (TYPE_TEMPLATE_INFO (t))
+        {
+          tree args = TREE_VALUE (TYPE_TEMPLATE_INFO (t));
+          walk_tree (&args, &find_parameter_packs_r, ppd, ppd->visited);
+        }
+
+      *walk_subtrees = 0;
+      return NULL_TREE;
+
+    case TEMPLATE_DECL:
+      if (DECL_TEMPLATE_TEMPLATE_PARM_P (t)
+	  && TEMPLATE_TYPE_PARAMETER_PACK (TREE_TYPE (t)))
+	break;
+      
+      *walk_subtrees = 0;
+      return NULL_TREE;
+       
+    case TYPE_PACK_EXPANSION:
+    case EXPR_PACK_EXPANSION:
+      *walk_subtrees = 0;
+      return NULL_TREE;
+
+    default:
+      return NULL_TREE;
+    }
+  
+  /* Add this parameter pack to the list.  */
+  *ppd->parameter_packs = tree_cons (NULL_TREE, t, *ppd->parameter_packs);
+
+  return NULL_TREE;
+}
+
+/* Determines if the expression or type T uses any parameter packs.  */
+bool
+uses_parameter_packs (tree t)
+{
+  tree parameter_packs = NULL_TREE;
+  struct find_parameter_pack_data ppd;
+  ppd.parameter_packs = &parameter_packs;
+  ppd.visited = pointer_set_create ();
+  walk_tree (&t, &find_parameter_packs_r, &ppd, ppd.visited);
+  return parameter_packs != NULL_TREE;
+}
+
+/* Turn ARG, which may be an expression, type, or a TREE_LIST
+   representation a base-class initializer into a parameter pack
+   expansion. If all goes well, the resulting node will be an
+   EXPR_PACK_EXPANSION, TYPE_PACK_EXPANSION, or TREE_LIST,
+   respectively.  */
+tree 
+make_pack_expansion (tree arg)
+{
+  tree result;
+  tree parameter_packs = NULL_TREE;
+  bool for_types = false;
+  struct find_parameter_pack_data ppd;
+
+  if (!arg || arg == error_mark_node)
+  turn arg;
+
+  if (TREE_CODE (arg) == TREE_LIST)
+    {
+      /* The only time we will see a TREE_LIST here is for a base
+         class initializer.  In this case, the TREE_PURPOSE will be a
+         _TYPE node (representing the base class expansion we're
+         initializing) and the TREE_VALUE will be a TREE_LIST
+         containing the initialization arguments. 
+
+         The resulting expansion looks somewhat different from most
+         expansions. Rather than returning just one _EXPANSION, we
+         return a TREE_LIST whose TREE_PURPOSE is a
+         TYPE_PACK_EXPANSION containing the bases that will be
+         initialized.  The TREE_VALUE will be identical to the
+         original TREE_VALUE, which is a list of arguments that will
+         be passed to each base.  We do not introduce any new pack
+         expansion nodes into the TREE_VALUE (although it is possible
+         that some already exist), because the TREE_PURPOSE and
+         TREE_VALUE all need to be expanded together with the same
+         _EXPANSION node.  Note that the TYPE_PACK_EXPANSION in the
+         resulting TREE_PURPOSE will mention the parameter packs in
+         both the bases and the arguments to the bases.  */
+      tree purpose;
+      tree value;
+      tree parameter_packs = NULL_TREE;
+
+      /* Determine which parameter packs will be used by the base
+         class expansion.  */
+      ppd.visited = pointer_set_createeate ();
+      ppd.parameter_packs = &parameter_packs;
+      walk_tree (&TREE_PURPOSE (arg), &find_parameter_packs_r, 
+                 &ppd, ppd.visited);
+
+      if (parameter_packs == NULL_TREE)
+        {
+          error ("base initializer expansion %<%T%> contains no parameter packs", arg);
+          return error_mark_node;
+        }
+
+      if (TREE_VALUE (arg) != void_type_node)
+        {
+          /* Collect the sets of parameter packs used in each of the
+             initialization arguments.  */
+          for (value = TREE_VALUE (arg); value; value = TREE_CHAIN (value))
+            {
+              /* Determine which parameter packs will be expanded in this
+                 argument.  */
+              walk_tree (&TREE_VALUE (value), &find_parameter_packs_r, 
+                         &ppd, ppd.visited);
+            }
+        }
+
+      /* Create the pack expansion type for the base type.  */
+      purpose = make_node (TYPE_PACK_EXPANSION);
+      SET_PACK_EXPANSION_PATTERN (purpose, TREE_PURPOSE (arg));
+      PACK_EXPANSION_PARAMETER_PACKS (purpose) = parameter_packs;
+
+      /* Just use structural equality for these TYPE_PACK_EXPANSIONS;
+	 they will rarely be compared to anything.  */
+      SET_TYPE_STRUCTURAL_EQUALITY (purpose);
+
+      return tree_cons (purpose, TREE_VALUE (arg), NULL_TREE);
+    }
+
+  if (TYPE_P (arg) || TREE_CODE (arg) == TEMPLATE_DECL)
+    for_types = true;
+
+  /* Build the PACK_EXPON_* node.  */
+  result = make_node (for_types ? TYPE_PACK_EXPANSION : EXPR_PACK_EXPANSION);
+  SET_PACK_EXPANSION_PATTERN (result, arg);
+  if (TREE_CODE (result) == EXPR_PACK_EXPANSION)
+    {
+      /* Propagate type and const-expression information.  */
+      TREE_TYPE (result) = TREE_TYPE (arg);
+      TREE_CONSTANT (result) = TREE_CONSTANT (arg);
+    }
+  else
+    /* Just use structural equality for these TYPE_PACK_EXPANSIONS;
+       they will rarely be compared to anything.  */
+    SET_TYPE_STRUCTURAL_EQUALITY (result);
+
+  /* Determine which parameter packs will be expanded.  */
+  ppd.parameter_packs = &parameter_packs;
+  ppd.visited = pointer_set_create ();
+  walk_tree (&arg, &find_parameter_packs_r, &ppd, ppd.visited);
+
+  /* Make sure we found some parameter packs.  */
+  if (parameter_packs == NULL_TREE)
+    {
+      if (TYPE_P (arg))
+        error ("expansion pattern %<%T%> contains no argument packs", arg);
+      else
+        error ("expansion pattern %<%E%> contains no argument packs", arg);
+      return error_mark_node;
+    }
+  PACK_EXPANSION_PARAMETER_PACKS (result) = parameter_packs;
+
+  return result;
+}
+
+/* Checks T for any "bare" parameter packs, which have not yet been
+   expanded, and issues an error if any are found. This operation can
+   only be done on full expressions or types (e.g., an expression
+   statement, "if" condition, etc.), because we could have expressions like:
+
+     f   f(g(h(args)))...)
+
+   where "args" is a parameter pack. check_for_bare_parameter_packs
+   should not be called for the subexpressions args, h(args),
+   g(h(args)), or f(g(h(args))), because we would produce erroneous
+   error messages.  */
+void 
+check_for_bare_parameter_packs (tree t)
+{
+  tree parameter_packs = NULL_TREE;
+  struct find_parameter_pack_data ppd;
+
+  if (!processing_template_decl || !t || t == error_mark_node)
+    return;
+
+  if (TREE_CODE (t) == TYPE_DECL)
+    t = TREE_TYPE (t);
+
+  ppd.parameter_packs = &parameter_packs;
+  ppd.visited = pointer_set_create ();
+  walk_tree (&t, &find_parameter_packs_r, &ppd, ppd.visited);
+
+  if (parameter_packs) {
+    error ("parameter packs not expanded with `...':");
+    while (parameter_packs)
+      {
+        tree pack = TREE_VALUE (parameter_packs);
+        tree name = NULL_TREE;
+
+        if (TREE_CODE (pack) == TEMPLATE_TYPE_PARM
+            || TREE_CODE (pack) == TEMPLATE_TEMPLATE_PARM)
+          name = TYPE_NAME (pack);
+        else
+          name = DECL_NAME (pack);
+        inform ("        %qD", name);
+
+        parameter_packs = TREE_CHAIN (parameter_packs);
+      }
+  }
+}
+
+/* Expand any parameter packs that occur in the template arguments in
+   ARGS.  */
+tree
+expand_template_argument_pack (tree args)
+{
+  tree result_args = NULL_TREE;
+  int in_arg, out_arg = 0, nargs = args ? TREE_VEC_LENGTH (args) : 0;
+  int num_result_args = -1;
+
+
+
+  /* First, determine if we need to expand anything, and the number of
+     slots we'll need.  */
+  for (in_arg = 0; in_arg < nargs; ++in_arg)
+    {
+      tree arg = TREE_VEC_ELT (args, in_arg);
+      if (ARGUMENT_PACK_P (arg))
+        {
+          int num_packed = TREE_VEC_LENGTH (ARGUMENT_PACK_ARGS (arg));
+          if (num_result_args < 0)
+            num_result_args = in_arg + num_packed;
+          else
+            num_result_args += num_packed;
+        }
+      else
+        {
+          if (num_result_args >= 0)
+            num_result_args++;
+        }
+    }
+
+  /* If no expansion is necessary, we're done.  */
+  if (num_result_args < 0)
+    return args;
+
+  /* Expand arguments.  */
+  result_args = make_tree_vec (num_result_args);
+  for (in_arg = 0; in_arg < nargs; ++in_arg)
+    {
+      tree arg = TREE_VEC_ELT (args, in_arg);
+      if (ARGUMENT_PACK_P (arg))
+        {
+          tree packed = ARGUMENT_PACK_ARGS (arg);
+          int i, num_packed = TREE_VEC_LENGTH (packed);
+          for (i = 0; i < num_packed; ++i, ++out_arg)
+            TREE_VEC_ELT (result_args, out_arg) = TREE_VEC_ELT(packed, i);
+        }
+      else
+        {
+          TREE_VEC_ELT (result_args, out_arg) = arg;
+          ++out_arg;
+        }
+    }
+
+  return result_args;
+}
+
 /* Complain if DECL shadows a template parameter.
 
    [temp.local]: A template-parameter shall not be redeclared within its
@@ -2399,6 +2802,8 @@ reduce_template_parm_level (tree index, 
 				     TEMPLATE_PARM_ORIG_LEVEL (index),
 				     decl, type);
       TEMPLATE_PARM_DESCENDANTS (index) = t;
+      TEMPLATE_PARM_PARAMETER_PACK (t) 
+	= TEMPLATE_PARM_PARAMETER_PACK (index);
 
 	/* Template template parameters need this.  */
       if (TREE_CODE (decl) != CONST_DECL)
@@ -2411,10 +2816,12 @@ reduce_template_parm_level (tree index, 
 
 /* Process information from new template parameter PARM and append it to the
    LIST being built.  This new parameter is a non-type parameter iff
-   IS_NON_TYPE is true.  */
+   IS_NON_TYPE is true. This new parameter is a parameter
+   pack iff IS_PARAMETER_PACK is true.  */
 
 tree
-process_template_parm (tree list, tree parm, bool is_non_type)
+process_template_parm (tree list, tree parm, bool is_non_type, 
+                       bool is_parameter_pack)
 {
   tree decl = 0;
   tree defval;
@@ -2467,6 +2874,16 @@ process_template_parm (tree list, tree p
             TREE_VALUE (err_parm_list) = error_mark_node;
 	     return chainon (list, err_parm_list);
           }
+
+        if (uses_parameter_packs (TREE_TYPE (parm)) && !is_parameter_pack)
+	  {
+	    /* This template parameter is not a parameter pack, but it
+	       should be. Complain about "bare" parameter packs.  */
+	    check_for_bare_parameter_packs (TREE_TYPE (parm));
+	    
+	    /* Recover by calling this a parameter pack.  */
+	    is_parameter_pack = true;
+	  }
       }
 
       /* A template parameter is not modifiable.  */
@@ -2481,6 +2898,9 @@ process_template_parm (tree list, tree p
 	= build_template_parm_index (idx, processing_template_decl,
 				     processing_template_decl,
 				     decl, TREE_TYPE (parm));
+
+      TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (parm)) 
+	= is_parameter_pack;
     }
   else
     {
@@ -2510,6 +2930,7 @@ process_template_parm (tree list, tree p
 	= build_template_parm_index (idx, processing_template_decl,
 				     processing_template_decl,
 				     decl, TREE_TYPE (parm));
+      TEMPLATE_TYPE_PARAMETER_PACK (t) = is_parameter_pack;
       TYPE_CANONICAL (t) = canonical_type_parameter (t);
     }
   DECL_ARTIFICIAL (decl) = 1;
@@ -2602,11 +3023,38 @@ current_template_args (void)
 		{
 		  if (TREE_CODE (t) == TYPE_DECL
 		      || TREE_CODE (t) == TEMPLATE_DECL)
-		    t = TREE_TYPE (t);
-		  else
-		    t = DECL_INITIAL (t);
-		}
-
+                    {
+                      t = TREE_TYPE (t);
+                      
+                      if (TEMPLATE_TYPE_PARAMETER_PACK (t))
+                        {
+                          /* Turn this argument into a TYPE_ARGUMENT_PACK
+                             with a single element, which expands T.  */
+                          tree vec = make_tree_vec (1);
+                          TREE_VEC_ELT (vec, 0) = make_pack_expansion (t);
+                          
+                          t = make_node (TYPE_ARGUMENT_PACK);
+                          SET_ARGUMENT_PACK_ARGS (t, vec);
+                        }
+                    }
+                  else
+                    {
+                      t = DECL_INITIAL (t);
+                      
+                      if (TEMPLATE_PARM_PARAMETER_PACK (t))
+                        {
+                          /* Turn this argument into a NONTYPE_ARGUMENT_PACK
+                             with a single element, which expands T.  */
+                          tree vec = make_tree_vec (1);
+                          tree type = TREE_TYPE (TEMPLATE_PARM_DECL (t));
+                          TREE_VEC_ELT (vec, 0) = make_pack_expansion (t);
+                          
+                          t  = make_node (NONTYPE_ARGUMENT_PACK);
+                          SET_ARGUMENT_PACK_ARGS (t, vec);
+                          TREE_TYPE (t) = type;
+                        }
+                    }
+                }
 	      TREE_VEC_ELT (a, i) = t;
 	    }
 	}
@@ -2796,74 +3244,114 @@ process_partial_specialization (tree dec
 
      The type of a template parameter corresponding to a specialized
      non-type argument shall not be dependent on a parameter of the
-     specialization.  */
+     specialization. 
+
+     Also, we verify that pack expansions only occur at the
+     end of the argument list.  */
   gcc_assert (nargs == DECL_NTPARMS (maintmpl));
   tpd2.parms = 0;
   for (i = 0; i < nargs; ++i)
     {
+      tree parm = TREE_VALUE (TREE_VEC_ELT (main_inner_parms, i));
       tree arg = TREE_VEC_ELT (inner_args, i);
-      if (/* These first two lines are the `non-type' bit.  */
-	  !TYPE_P (arg)
-	  && TREE_CODE (arg) != TEMPLATE_DECL
-	  /* This next line is the `argument expression is not just a
-	     simple identifier' condition and also the `specialized
-	     non-type argument' bit.  */
-	  && TREE_CODE (arg) != TEMPLATE_PARM_INDEX)
-	{
-	  if (tpd.arg_uses_template_parms[i])
-	    error ("template argument %qE involves template parameter(s)", arg);
-	  else
-	    {
-	      /* Look at the corresponding template parameter,
-		 marking which template parameters its type depends
-		 upon.  */
-	      tree type =
-		TREE_TYPE (TREE_VALUE (TREE_VEC_ELT (main_inner_parms,
-						     i)));
+      tree packed_args = NULL_TREE;
+      int j, len = 1;
 
-	      if (!tpd2.parms)
-		{
-		  /* We haven't yet initialized TPD2.  Do so now.  */
-		  tpd2.arg_uses_template_parms
-		    = (int *) alloca (sizeof (int) * nargs);
-		  /* The number of parameters here is the number in the
-		     main template, which, as checked in the assertion
-		     above, is NARGS.  */
-		  tpd2.parms = (int *) alloca (sizeof (int) * nargs);
-		  tpd2.level =
-		    TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (maintmpl));
-		}
+      if (ARGUMENT_PACK_P (arg))
+        {
+          /* Extract the arguments from the argument pack. We'll be
+             iterating over these in the following loop.  */
+          packed_args = ARGUMENT_PACK_ARGS (arg);
+          len = TREE_VEC_LENGTH (packed_args);
+        }
 
-	      /* Mark the template parameters.  But this time, we're
-		 looking for the template parameters of the main
-		 template, not in the specialization.  */
-	      tpd2.current_arg = i;
-	      tpd2.arg_uses_template_parms[i] = 0;
-	      memset (tpd2.parms, 0, sizeof (int) * nargs);
-	      for_each_template_parm (type,
-				      &mark_template_parm,
-				      &tpd2,
-				      NULL);
+      for (j = 0; j < len; j++)
+        {
+          if (packed_args)
+            /* Get the Jth argument in the parameter pack.  */
+            arg = TREE_VEC_ELT (packed_args, j);
+
+          if (PACK_EXPANSION_P (arg))
+            {
+              /* Pack expansions must come at the end of the
+                 argument list.  */
+              if ((packed_args && j < len - 1)
+                  || (!packed_args && i < nargs - 1))
+                {
+                  if (TREE_CODE (arg) == EXPR_PACK_EXPANSION)
+                    error ("parameter pack argument %qE must be at the end of the template argument list", arg);
+                  else
+                    error ("parameter pack argument %qT must be at the end of the template argument list", arg);                   
+                }
+            }
 
-	      if (tpd2.arg_uses_template_parms [i])
-		{
-		  /* The type depended on some template parameters.
-		     If they are fully specialized in the
-		     specialization, that's OK.  */
-		  int j;
-		  for (j = 0; j < nargs; ++j)
-		    if (tpd2.parms[j] != 0
-			&& tpd.arg_uses_template_parms [j])
-		      {
-			error ("type %qT of template argument %qE depends "
-			       "on template parameter(s)",
-			       type,
-			       arg);
-			break;
-		      }
-		}
-	    }
-	}
+          if (TREE_CODE (arg) == EXPR_PACK_EXPANSION)
+            /* We only care about the pattern.  */
+            arg = PACK_EXPANSION_PATTERN (arg);
+
+          if (/* These first two lines are the `non-type' bit.  */
+              !TYPE_P (arg)
+              && TREE_CODE (arg) != TEMPLATE_DECL
+              /* This next line is the `argument expression is not just a
+                 simple identifier' condition and also the `specialized
+                 non-type argument' bit.  */
+              && TREE_CODE (arg) != TEMPLATE_PARM_INDEX)
+            {
+              if ((!packed_args && tpd.arg_uses_template_parms[i])
+                  || (packed_args && uses_template_parms (arg)))
+                error ("template argument %qE involves template parameter(s)",
+                       arg);
+              else 
+                {
+                  /* Look at the corresponding template parameter,
+                     marking which template parameters its type depends
+                     upon.  */
+                  tree type = TREE_TYPE (parm);
+
+                  if (!tpd2.parms)
+                    {
+                      /* We haven't yet initialized TPD2.  Do so now.  */
+                      tpd2.arg_uses_template_parms 
+                        = (int *) alloca (sizeof (int) * nargs);
+                      /* The number of parameters here is the number in the
+                         main template, which, as checked in the assertion
+                         above, is NARGS.  */
+                      tpd2.parms = (int *) alloca (sizeof (int) * nargs);
+                      tpd2.level = 
+                        TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (maintmpl));
+                    }
+
+                  /* Mark the template parameters.  But this time, we're
+                     looking for the template parameters of the main
+                     template, not in the specialization.  */
+                  tpd2.current_arg = i;
+                  tpd2.arg_uses_template_parms[i] = 0;
+                  memset (tpd2.parms, 0, sizeof (int) * nargs);
+                  for_each_template_parm (type,
+                                          &mark_template_parm,
+                                          &tpd2,
+                                          NULL);
+
+                  if (tpd2.arg_uses_template_parms [i])
+                    {
+                      /* The type depended on some template parameters.
+                         If they are fully specialized in the
+                         specialization, that's OK.  */
+                      int j;
+                      for (j = 0; j < nargs; ++j)
+                        if (tpd2.parms[j] != 0
+                            && tpd.arg_uses_template_parms [j])
+                          {
+                            error ("type %qT of template argument %qE depends "
+                                   "on template parameter(s)", 
+                                   type,
+                                   arg);
+                            break;
+                          }
+                    }
+                }
+            }
+        }
     }
 
   if (retrieve_specialization (maintmpl, specargs,
@@ -3158,9 +3646,36 @@ push_template_decl_real (tree decl, bool
   check_default_tmpl_args (decl, current_template_parms,
 			   primary, is_partial);
 
+  /* Ensure that there are no parameter packs in the type of this
+     declaration that have not been expanded.  */
+  check_for_bare_parameter_packs (TREE_TYPE (decl));
+
   if (is_partial)
     return process_partial_specialization (decl);
 
+  /* A primary class template can only have one parameter pack, at the
+     end of the template parameter list.  */
+  if (primary && TREE_CODE (decl) == TYPE_DECL)
+    {
+      tree inner_parms 
+	= INNERMOST_TEMPLATE_PARMS (current_template_parms);
+      int i, len = TREE_VEC_LENGTH (inner_parms);
+      for (i = 0; i < len - 1; i++)
+        {
+          tree parm = TREE_VALUE (TREE_VEC_ELT (inner_parms, i));
+
+	  if (template_parameter_pack_p (parm))
+	    {
+	      if (TREE_CODE (parm) == PARM_DECL)
+		error ("parameter pack %qE must be at the end of the"
+		       " template parameter list", parm);
+	      else
+		error ("parameter pack %qT must be at the end of the"
+		       " template parameter list", TREE_TYPE (parm));
+	    }
+        }
+    }
+
   args = current_template_args ();
 
   if (!ctx
@@ -3935,9 +4450,6 @@ coerce_template_template_parms (tree par
 
       switch (TREE_CODE (parm))
 	{
-	case TYPE_DECL:
-	  break;
-
 	case TEMPLATE_DECL:
 	  /* We encounter instantiations of templates like
 	       template <template <template <class> class> class TT>
@@ -3950,6 +4462,13 @@ coerce_template_template_parms (tree par
 		(parmparm, argparm, complain, in_decl, outer_args))
 	      return 0;
 	  }
+	  /* Fall through.  */
+
+	case TYPE_DECL:
+	  if (TEMPLATE_TYPE_PARAMETER_PACK (TREE_TYPE (parm))
+	      != TEMPLATE_TYPE_PARAMETER_PACK (TREE_TYPE (arg)))
+	    /* One is a parameter pack, the other is not.  */
+	    return 0;
 	  break;
 
 	case PARM_DECL:
@@ -3965,6 +4484,11 @@ coerce_template_template_parms (tree par
 		    (tsubst (TREE_TYPE (parm), outer_args, complain, in_decl),
 			     TREE_TYPE (arg)))
 	    return 0;
+
+	  if (TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (parm))
+	      != TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (arg+	    /* One is a parameter pack, the other is not.  */
+	    return 0;
 	  break;
 
 	default:
@@ -3991,6 +4515,7 @@ convert_template_argument (tree parm,
 {
   tree val;
   int is_type, requires_type, is_tmpl_type, requires_tmpl_type;
+  tree check_arg = arg;
 
   if (TREE_CODE (arg) == TREE_LIST
       && TREE_CODE (TREE_VALUE (arg)) == OFFSET_REF)
@@ -4008,10 +4533,16 @@ convert_template_argument (tree parm,
   requires_type = (TREE_CODE (parm) == TYPE_DECL
 		   || requires_tmpl_type);
 
-  is_tmpl_type = ((TREE_CODE (arg) == TEMPLATE_DECL
-		   && TREE_CODE (DECL_TEMPLATE_RESULT (arg)) == TYPE_DECL)
-		  || TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM
-		  || TREE_CODE (arg) == UNBOUND_CLASS_TEMPLATE);
+  /* When determining whether a argument pack expansion is a template,
+     look at the pattern.  */
+  if (TREE_CODE (check_arg) == TYPE_PACK_EXPANSION)
+    check_arg = PACK_EXPANSION_PATTERN (check_arg);
+
+  is_tmpl_type = 
+    ((TREE_CODE (check_arg) == TEMPLATE_DECL
+      && TREE_CODE (DECL_TEMPLATE_RESULT (check_arg)) == TYPE_DECL)
+     || TREE_CODE (check_arg) == TEMPLATE_TEMPLATE_PARM
+     || TREE_CODE (check_arg) == UNBOUND_CLASS_TEMPLATE);
 
   if (is_tmpl_type
       && (TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM
@@ -4079,7 +4610,15 @@ convert_template_argument (tree parm,
 	  else
 	    {
 	      tree parmparm = DECL_INNERMOST_TEMPLATE_PARMS (parm);
-	      tree argparm = DECL_INNERMOST_TEMPLATE_PARMS (arg);
+	   	      tree argparm;
+
+              check_arg = arg;
+              /* When determining whether a pack expansion is a template,
+                 look at the pattern.  */
+              if (TREE_CODE (check_arg) == TYPE_PACK_EXPANSION)
+                check_arg = PACK_EXPANSION_PATTERN (check_arg);
+
+              argparm = DECL_INNERMOST_TEMPLATE_PARMS (check_arg);
 
 	      if (coerce_template_template_parms (parmparm, argparm,
 						  complain, in_decl,
@@ -4089,9 +4628,17 @@ convert_template_argument (tree parm,
 
 		  /* TEMPLATE_TEMPLATE_PARM node is preferred over
 		     TEMPLATE_DECL.  */
-		  if (val != error_mark_node
-		      && DECL_TEMPLATE_TEMPLATE_PARM_P (val))
-		    val = TREE_TYPE (val);
+		  if (val != error_mark_node)
+                    {
+                      if (DECL_TEMPLATE_TEMPLATE_PARM_P (val))
+                        val = TREE_TYPE (val);
+                      else if (TREE_CODE (val) == TYPE_PACK_EXPANSION
+                               && DECL_TEMPLATE_TEMPLATE_PARM_P (check_arg))
+                        {
+                          val = TREE_TYPE (check_arg);
+                          val = make_pack_expansion (val);
+                        }
+                    }
 		}
 	      else
 		{
@@ -4175,12 +4722,20 @@ coerce_template_parms (tree parms,
   tree new_inner_args;
   bool saved_skip_evaluation;
 
-  inner_args = INNERMOST_TEMPLATE_ARGS (args);
+  /* When used as a boolean value, indicates whether this is a
+     variadic template parameter list. Since it's an int, we can also
+     subtract it from nparms to get the number of non-variadic
+     parameters.  */
+  int variadic_p = template_parms_variadic_p (parms) ? 1 : 0;
+
+  inner_args 
+    = expand_template_argument_pack (INNERMOST_TEMPLATE_ARGS (args));
+
   nargs = inner_args ? NUM_TMPL_ARGS (inner_args) : 0;
   nparms = TREE_VEC_LENGTH (parms);
 
-  if (nargs > nparms
-      || (nargs < nparms
+  if ((nargs > nparms - variadic_p && !variadic_p)
+      || (nargs < nparms - variadic_p
 	  && require_all_args
 	  && (!use_default_args
 	      || (TREE_VEC_ELT (parms, nargs) != error_mark_node
@@ -4188,8 +4743,15 @@ coerce_template_parms (tree parms,
     {
       if (complain & tf_error)
 	{
-	  error ("wrong number of template arguments (%d, should be %d)",
-		 nargs, nparms);
+          const char *or_more = "";
+          if (variadic_p)
+            {
+              or_more = " or more";
+              --nparms;
+            }
+
+	  error ("wrong number of template arguments (%d, should be %d%s)",
+                 nargs, nparms, or_more);
 
 	  if (in_decl)
 	    error ("provided for %q+D", in_decl);
@@ -4204,7 +4766,7 @@ coerce_template_parms (tree parms,
   skip_evaluation = false;
   new_inner_args = make_tree_vec (nparms);
   new_args = add_outermost_template_args (args, new_inner_args);
-  for (i = 0; i < nparms; i++)
+  for (i = 0; i < nparms - variadic_p; i++)
     {
       tree arg;
       tree parm;
@@ -4220,7 +4782,29 @@ coerce_template_parms (tree parms,
 
       /* Calculate the Ith argument.  */
       if (i < nargs)
-	arg = TREE_VEC_ELT (inner_args, i);
+        {
+          arg = TREE_VEC_ELT (inner_args, i);
+        
+          if (PACK_EXPANSION_P (arg))
+            {
+              /* If ARG is a pack expansion, then PARM must be
+                 a template parameter pack. We can't expand into a
+                 fixed-length argument list.  */
+              tree actual_parm = TREE_VALUE (parm);
+              bool parm_is_parameter_pack 
+		= template_parameter_pack_p (actual_parm);
+
+              if (!parm_is_parameter_pack)
+                {
+                  if (TREE_CODE (arg) == EXPR_PACK_EXPANSION)
+                    error ("cannot expand %<%E%> into a fixed-length "
+                           "argument list", arg);
+                  else
+                    error ("cannot expand %<%T%> into a fixed-length "
+                           "argument list", arg);
+                }
+            }
+        }
       else if (require_all_args)
 	/* There must be a default arg in this case.  */
 	arg = tsubst_template_arg (TREE_PURPOSE (parm), new_args,
@@ -4245,6 +4829,101 @@ coerce_template_parms (tree parms,
     }
   skip_evaluation = saved_skip_evaluation;
 
+  if (variadic_p)
+    {
+      int expected_len = nargs - nparms + 1;
+      tree parm = TREE_VEC_ELT (parms, nparms - 1);
+      tree packed_args;
+      tree argument_pack;
+      tree packed_types = NULL_TREE;
+      
+      packed_args = make_tree_vec (expected_len >= 0 ? expected_len : 0);
+
+      if (TREE_CODE (TREE_VALUE (parm)) == PARM_DECL
+	  && uses_parameter_packs (TREE_TYPE (TREE_VALUE (parm))))
+	{
+	  /* When the template parameter is a non-type template
+	     parameter pack whose type uses parameter packs, we need
+	     to look at each of the template arguments
+	     separately. Build a vector of the types for these
+	     non-type template parameters in PACKED_TYPES.  */
+	  tree expansion 
+	    = make_pack_expansion (TREE_TYPE (TREE_VALUE (parm)));
+	  packed_types = tsubst_pack_expansion (expansion, args,
+						complain, in_decl);
+
+	  if (packed_types == error_mark_node)
+	    return error_mark_node;
+
+	  /* Check that we have the right number of arguments.  */
+	  if (i < nargs
+	      && !PACK_EXPANSION_P (TREE_VEC_ELT (inner_args, i))
+	      && nargs - i != TREE_VEC_LENGTH (packed_types))
+	    {
+	      error ("wrong number of template arguments (%d, should be %d)",
+		     nargs, nparms - 1 + TREE_VEC_LENGTH (packed_types));
+	      return error_mark_node;
+	    }
+
+	  /* If we aren't able to check the actual arguments now
+	     (because they haven't been expanded yet), we can at least
+	     verify that all of the types used for the non-type
+	     template parameter pack are, in fact, valid for non-type
+	     template parameters.  */
+	  if (i < nargs && PACK_EXPANSION_P (TREE_VEC_ELT (inner_args, i)))
+	    {
+	      int j, len = TREE_VEC_LENGTH (packed_types);
+	      for (j = 0; j < len; ++j)
+		{
+		  tree t = TREE_VEC_ELT (packed_types, j);
+		  if (invalid_nontype_parm_type_p (t, complain))
+		    return error_mark_node;
+		}
+	    }
+	}
+
+      /* Convert the remaining arguments, which will be a part of the
+         parameter pack "parm".  */
+      for (; i < nargs; ++i)
+        {
+          tree arg = TREE_VEC_ELT (inner_args, i);
+	  tree actual_parm = TREE_VALUE (parm);
+
+	  if (packed_types && !PACK_EXPANSION_P (arg))
+	    {
+	      /* When we have a vector of types (corresponding to the
+		 non-type template parameter pack that uses parameter
+		 packs in its type, as mention above), and the
+		 argument is not an expansion (which expands to a
+		 currently unknown number of arguments), clone the
+		 parm and give it the next type in PACKED_TYPES.  */
+	      actual_parm = copy_node (actual_parm);
+	      TREE_TYPE (actual_parm) = 
+		TREE_VEC_ELT (packed_types, i - nparms + 1);
+	    }
+
+          arg = convert_template_argument (actual_parm, 
+                                           arg, new_args, complain, i,
+                                           in_decl);
+          if (arg == error_mark_node)
+            lost++;
+          TREE_VEC_ELT (packed_args, i - nparms + 1) = arg; 
+        }
+
+      if (TREE_CODE (TREE_VALUE (parm)) == TYPE_DECL
+          || TREE_CODE (TREE_VALUE (parm)) == TEMPLATE_DECL)
+          argument_pack = make_node (TYPE_ARGUMENT_PACK);
+      else
+        {
+          argument_pack = make_node (NONTYPE_ARGUMENT_PACK);
+          TREE_TYPE (argument_pack) = TREE_TYPE (TREE_VALUE (parm));
+          TREE_CONSTANT (argument_pack) = 1;
+        }
+
+      SET_ARGUMENT_PACK_ARGS (argument_pack, packed_args);
+      TREE_VEC_ELT (new_inner_args, nparms - 1) = argument_pack;
+    }
+
   if (lost)
     return error_mark_node;
 
@@ -4262,6 +4941,10 @@ template_args_equal (tree ot, tree nt)
   if (TREE_CODE (nt) == TREE_VEC)
     /* For member templates */
     return TREE_CODE (ot) == TREE_VEC && comp_template_args (ot, nt);
+  else if (PACK_EXPANSION_P (ot))
+    return PACK_EXPANSION_P (nt) 
+      && template_args_equal (PACK_EXPANSION_PATTERN (ot),
+                              PACK_EXPANSION_PATTERN (nt));
   else if (TYPE_P (nt))
     return TYPE_P (ot) && same_type_p (ot, nt);
   else if (TREE_CODE (ot) == TREE_VEC || TYPE_P (ot))
@@ -4278,6 +4961,9 @@ comp_template_args (tree oldargs, tree n
 {
   int i;
 
+  oldargs = expand_template_argument_pack (oldargs);
+  newargs = expand_template_argument_pack (newargs);
+
   if (TREE_VEC_LENGTH (oldargs) != TREE_VEC_LENGTH (newargs))
     return 0;
 
@@ -5018,16 +5704,6 @@ for_each_template_parm_r (tree *tp, int 
 	return error_mark_node;
       break;
 
-    case BASELINK:
-      /* If we do not handle this case specially, we end up walking
-	 the BINFO hierarchy, which is circular, and therefore
-	 confuses walk_tree.  */
-      *walk_subtrees = 0;
-      if (for_each_template_parm (BASELINK_FUNCTIONS (*tp), fn, data,
-				  pfd->visited))
-	return error_mark_node;
-      break;
-
     default:
       break;
     }
@@ -5720,15 +6396,37 @@ instantiate_class_template (tree type)
 	{
 	  tree base;
 	  tree access = BINFO_BASE_ACCESS (pbinfo, i);
+          tree expanded_bases = NULL_TREE;
+          int idx, len = 1;
 
-	  /* Substitute to figure out the base class.  */
-	  base = tsubst (BINFO_TYPE (pbase_binfo), args, tf_error, NULL_TREE);
-	  if (base == error_mark_node)
-	    continue;
-
-	  base_list = tree_cons (access, base, base_list);
-	  if (BINFO_VIRTUAL_P (pbase_binfo))
-	    TREE_TYPE (base_list) = integer_type_node;
+          if (PACK_EXPANSION_P (BINFO_TYPE (pbase_binfo)))
+            {
+              expanded_bases = 
+		tsubst_pack_expansion (BINFO_TYPE (pbase_binfo),
+				       args, tf_error, NULL_TREE);
+              if (expanded_bases == error_mark_node)
+                continue;
+
+              len = TREE_VEC_LENGTH (expanded_bases);
+            }
+
+          for (idx = 0; idx < len; idx++)
+            {
+              if (expanded_bases)
+                /* Extract the already-expanded base class.  */
+                base = TREE_VEC_ELT (expanded_bases, idx);
+              else
+                /* Substitute to figure out the base class.  */
+                base = tsubst (BINFO_TYPE (pbase_binfo), args, tf_error, 
+                               NULL_TREE);
+
+              if (base == error_mark_node)
+                continue;
+
+              base_list = tree_cons (access, base, base_list);
+              if (BINFO_VIRTUAL_P (pbase_binfo))
+                TREE_TYPE (base_list) = integer_type_node;
+            }
 	}
 
       /* The list is now in reverse order; correct that.  */
@@ -6074,7 +6772,196 @@ tsubst_template_arg (tree t, tree args, 
 		       /*integral_constant_expression_p=*/true);
       r = fold_non_dependent_expr (r);
     }
-  return r;
+  return r;
+}
+
+/* Substitute ARGS into T, which is an pack expansion
+   (i.e. TYPE_PACK_EXPANSION or EXPR_PACK_EXPANSION). Returns a
+   TREE_VEC with the substituted arguments, a PACK_EXPANSION_* node
+   (if only a partial substitution could be performed) or
+   ERROR_MARK_NODE if there was an error.  */
+tree
+tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
+		       tree in_decl)
+{
+  tree pattern;
+  tree pack, packs = NULL_TREE, unsubstituted_packs = NULL_TREE;
+  tree first_arg_pack; int i, len = -1;
+  tree result;
+  int incomplete = 0;
+
+  gcc_assert (PACK_EXPANSION_P (t));
+  pattern = PACK_EXPANSION_PATTERN (t);
+
+  /* Determine the argument packs that will instantiate the parameter
+     packs used in the expansion expression. While we're at it,
+     compute the number of arguments to be expanded and make sure it
+     is consistent.  */
+  for (pack = PACK_EXPANSION_PARAMETER_PACKS (t); pack; 
+       pack = TREE_CHAIN (pack))
+    {
+      tree parm_pack = TREE_VALUE (pack);
+      tree arg_pack = NULL_TREE;
+      tree orig_arg = NULL_TREE;
+
+      if (TREE_CODE (parm_pack) == PARM_DECL)
+        {
+          if (local_specializations)
+            arg_pack = retrieve_local_specialization (parm_pack);
+        }
+      else
+        {
+          int level, idx, levels;
+          template_parm_level_and_index (parm_pack, &level, &idx);
+
+          levels = TMPL_ARGS_DEPTH (args);
+          if (level <= levels)
+            arg_pack = TMPL_ARG (args, level, idx);
+        }
+
+      orig_arg = arg_pack;
+      if (arg_pack && TREE_CODE (arg_pack) == ARGUMENT_PACK_SELECT)
+	arg_pack = ARGUMENT_PACK_SELECT_FROM_PACK (arg_pack);
+      
+      if (arg_pack)
+        {
+          int my_len = 
+            TREE_VEC_LENGTH (ARGUMENT_PACK_ARGS (arg_pack));
+
+          /* It's all-or-nothing with incomplete argument packs.  */
+          if (incomplete && !ARGUMENT_PACK_INCOMPLETE_P (arg_pack))
+            return error_mark_node;
+          
+          if (ARGUMENT_PACK_INCOMPLETE_P (arg_pack))
+            incomplete = 1;
+
+          if (len < 0)
+            {
+              len = my_len;
+              first_arg_pack = arg_pack;
+            }
+          else if (len != my_len)
+            {
+              if (TREE_CODE (t) == TYPE_PACK_EXPANSION)
+                error ("mismatched argument pack lengths while expanding "
+                       "%<%T%>",
+                       pattern);
+              else
+                error ("mismatched argument pack lengths while expanding "
+                       "%<%E%>",
+                       pattern);
+              return error_mark_node;
+            }
+
+          /* Keep track of the parameter packs and their corresponding
+             argument packs.  */
+          packs = tree_cons (parm_pack, arg_pack, packs);
+          TREE_TYPE (packs) = orig_arg;
+        }
+      else
+        /* We can't substitute for this parameter pack.  */
+        unsubstituted_packs = tree_cons (TREE_PURPOSE (pack),
+                                         TREE_VALUE (pack),
+                                         unsubstituted_packs);
+    }
+
+  /* We cannot expand this expansion expression, because we don't have
+     all of the argument packs we need. Substitute into the pattern
+     and return a PACK_EXPANSION_*. The caller will need to deal with
+     that.  */
+  if (unsubstituted_packs)
+    return make_pack_expansion (tsubst (pattern, args, complain, 
+					in_decl));
+
+  /* We could not find any argument packs that work.  */
+  if (len < 0)
+    return error_mark_node;
+
+  /* For each argument in each argument pack, substitute into the
+     pattern.  */
+  result = make_tree_vec (len + incomplete);
+  for (i = 0; i < len + incomplete; ++i)
+    {
+      /* For parameter pack, change the substitution of the parameter
+         pack to the ith argument in its argument pack, then expand
+         the pattern.  */
+      for (pack = packs; pack; pack = TREE_CHAIN (pack))
+        {
+          tree parm = TREE_PURPOSE (pack);
+
+          if (TREE_CODE (parm) == PARM_DECL)
+            {
+	      /* Select the Ith argument from the pack.  */
+	      tree arg = make_node (ARGUMENT_PACK_SELECT);
+	      ARGUMENT_PACK_SELECT_FROM_PACK (arg) = TREE_VALUE (pack);
+	      ARGUMENT_PACK_SELECT_INDEX (arg) = i;
+              mark_used (parm);
+              register_local_specialization (arg, parm);
+            }
+          else
+            {
+              tree value = parm;
+              int idx, level;
+              template_parm_level_and_index (parm, &level, &idx);
+              
+	      if (i < len) 
+		{
+		  /* Select the Ith argument from the pack. */
+		  value = make_node (ARGUMENT_PACK_SELECT);
+		  ARGUMENT_PACK_SELECT_FROM_PACK (value) = TREE_VALUE (pack);
+		  ARGUMENT_PACK_SELECT_INDEX (value) = i;
+		}
+
+              /* Update the corresponding argument.  */
+              TMPL_ARG (args, level, idx) = value;
+            }
+        }
+
+      /* Substitute into the PATTERN with the altered arguments.  */
+      if (TREE_CODE (t) == EXPR_PACK_EXPANSION)
+        TREE_VEC_ELT (result, i) = 
+          tsubst_expr (pattern, args, complain, in_decl,
+                       /*integral_constant_expression_p=*/false);
+      else
+        TREE_VEC_ELT (result, i) = tsubst (pattern, args, complain, in_decl);
+
+      if (i == len)
+        /* When we have incomplete argument packs, the last "expanded"
+           result is itself a pack expansion, which allows us
+           to deduce more arguments.  */
+        TREE_VEC_ELT (result, i) = 
+          make_pack_expansion (TREE_VEC_ELT (result, i));
+
+      if (TREE_VEC_ELT (result, i) == error_mark_node)
+	{
+	  result = error_mark_node;
+	  break;
+	}
+    }
+  
+  /* Update ARGS to restore the substitution from parameter packs to
+     their argument packs.  */
+  for (pack = packs; pack; pack = TREE_CHAIN (pack))
+    {
+      tree parm = TREE_PURPOSE (pack);
+
+      if (TREE_CODE (parm) == PARM_DECL)
+        register_local_specialization (TREE_TYPE (pack), parm);
+      else
+        {
+          int idx, level;
+          template_parm_level_and_index (parm, &level, &idx);
+          
+          /* Update the corresponding argument.  */
+          if (TMPL_ARGS_HAVE_MULTIPLE_LEVELS (args))
+            TREE_VEC_ELT (TREE_VEC_ELT (args, level -1 ), idx) =
+              TREE_TYPE (pack);
+          else
+            TREE_VEC_ELT (args, idx) = TREE_TYPE (pack);
+        }
+    }
+
+  return result;
 }
 
 /* Substitute ARGS into the vector or list of template arguments T.  */
@@ -6082,8 +6969,9 @@ tsubst_template_arg (tree t, tree args, 
 static tree
 tsubst_template_args (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 {
+  tree orig_t = t;
   int len = TREE_VEC_LENGTH (t);
-  int need_new = 0, i;
+  int need_new = 0, i, expanded_len_adjust = 0, out;
   tree *elts = (tree *) alloca (len * sizeof (tree));
 
   for (i = 0; i < len; i++)
@@ -6093,6 +6981,42 @@ tsubst_template_args (tree t, tree args,
 
       if (TREE_CODE (orig_arg) == TREE_VEC)
 	new_arg = tsubst_template_args (orig_arg, args, complain, in_decl);
+      else if (PACK_EXPANSION_P (orig_arg))
+        {
+          /* Substitute into an expansion expression.  */
+          new_arg = tsubst_pack_expansion (orig_arg, args, complain, in_decl);
+
+          if (TREE_CODE (new_arg) == TREE_VEC)
+            /* Add to the expanded length adjustment the number of
+               expanded arguments. We subtract one from this
+               measurement, because the argument pack expression
+               itself is already counted as 1 in
+               LEN. EXPANDED_LEN_ADJUST can actually be negative, if
+               the argument pack is empty.  */
+            expanded_len_adjust += TREE_VEC_LENGTH (new_arg) - 1;
+        }
+      else if (ARGUMENT_PACK_P (orig_arg))
+        {
+          /* Substitute into each of the arguments.  */
+          new_arg = make_node (TCODE (orig_arg));
+          
+          SET_ARGUMENT_PACK_ARGS (
+            new_arg,
+            tsubst_template_args (ARGUMENT_PACK_ARGS (orig_arg),
+                                  args, complain, in_decl));
+
+          if (ARGUMENT_PACK_ARGS (new_arg) == error_mark_node)
+            new_arg = error_mark_node;
+
+          if (TREE_CODE (new_arg) == NONTYPE_ARGUMENT_PACK) {
+            TREE_TYPE (new_arg) = tsubst (TREE_TYPE (orig_arg), args,
+                                          complain, in_decl);
+            TREE_CONSTANT (new_arg) = TREE_CONSTANT (orig_arg);
+
+            if (TREE_TYPE (new_arg) == error_mark_node)
+              new_arg = error_mark_node;
+          }
+        }
       else
 	new_arg = tsubst_template_arg (orig_arg, args, complain, in_decl);
 
@@ -6107,9 +7031,27 @@ tsubst_template_args (tree t, tree args,
   if (!need_new)
     return t;
 
-  t = make_tree_vec (len);
-  for (i = 0; i < len; i++)
-    TREE_VEC_ELT (t, i) = elts[i];
+  /* Make space for the expanded arguments coming from template
+     argument packs.  */
+  t = make_tree_vec (len + expanded_len_adjust);
+  for (i = 0, out = 0; i < len; i++)
+    {
+      if ((PACK_EXPANSION_P (TREE_VEC_ELT (orig_t, i))
+           || ARGUMENT_PACK_P (TREE_VEC_ELT (orig_t, i)))
+          && TREE_CODE (elts[i]) == TREE_VEC)
+        {
+          int idx;
+
+          /* Now expand the template argument pack "in place".  */
+          for (idx =dx = 0; idx < TREE_VEC_LENGTH (elts[i]); idx++, out++)
+            TREE_VEC_ELT (t, out) = TREE_VEC_ELT (elts[i], idx);
+        }
+      else
+        {
+          TREE_VEC_ELT (t, out) = elts[i];
+          out++;
+        }
+    }
 
   return t;
 }
@@ -6718,33 +7660,112 @@ tsubst_decl (tree t, tree args, tsubst_f
 
     case PARM_DECL:
       {
-	tree type;
-
-	r = copy_node (t);
-	if (DECL_TEMPLATE_PARM_P (t))
-	  SET_DECL_TEMPLATE_PARM_P (r);
-
-	type = tsubst (TREE_TYPE (t), args, complain, in_decl);
-	type = type_decays_to (type);
-	TREE_TYPE (r) = type;
-	cp_apply_type_quals_to_decl (cp_type_quals (type), r);
+	tree type = NULL_TREE;
+        int i, len = 1;
+        tree expanded_types = NULL_TREE;
+        tree prev_r = NULL_TREE;
+        tree first_r = NULL_TREE;
 
-	if (DECL_INITIAL (r))
-	  {
-	    if (TREE_CODE (DECL_INITIAL (r)) != TEMPLATE_PARM_INDEX)
-	      DECL_INITIAL (r) = TREE_TYPE (r);
-	    else
-	      DECL_INITIAL (r) = tsubst (DECL_INITIAL (r), args,
-					 complain, in_decl);
-	  }
+        if (FUNCTION_PARAMETER_PACK_P (t))
+          {
+            /* If there is a local specialization that isn't a
+               parameter pack, it means that we're doing a "simple"
+               substitution from inside tsubst_pack_expansion. Just
+               return the local specialiation (which will be a single
+               parm).  */
+            tree spec = NULL_TREE;
+            if (local_specializations)
+          spec = retrieve_local_specialization (t);
+            if (spec 
+                && TREE_CODE (spec) == PARM_DECL
+                && TREE_CODE (TREE_TYPE (spec)) != TYPE_PACK_EXPANSION)
+              return spec;
+
+            /* Expand the TYPE_PACK_EXPANSION that provides the types for
+               the parameters in this function parameter pack.  */
+            expanded_types = tsubst_pack_expansion (TREE_TYPE (t), args,
+						    complain, in_decl);
+            if (TREE_CODE (expanded_types) == TREE_VEC)
+              {
+                len = TREE_VEC_LENGTH (expanded_types);
+
+                /* Zero-length parameter packs are boring. Just substitute
+                   into the chain.  */
+                if (len == 0)
+                  return tsubst (TREE_CHAIN (t), args, complain, 
+                                 TREE_CHAIN (t));
+              }
+            else
+              {
+                /* All we did was update the type. Make a note of that.  */
+                type = expanded_types;
+                expanded_types = NULL_TREE;
+              }
+          }
 
-	DECL_CONTEXT (r) = NULL_TREE;
+        /* Loop through all of the parameter's we'll build. When T is
+           a function parameter pack, LEN is the number of expanded
+           types in EXPANDED_TYPES; otherwise, LEN is 1.  */
+        r = NULL_TREE;
+        for (i = 0; i < len; ++i)
+          {
+            prev_r = r;
+            r = copy_node (t);
+            if (DECL_TEMPLATE_PARM_P (t))
+              SET_DECL_TEMPLATE_PARM_P (r);
+
+            if (expanded_types)
+              /* We're on the Ith parameter of the function parameter
+                 pack.  */
+              {
+                /* Get the Ith type.  */
+                type = TREE_VEC_ELT (expanded_types, i);
+
+                if (DECL_NAME (r))
+                  /* Rename the parameter to include the index.  */
+                  DECL_NAME (r) =
+                    make_ith_pack_parameter_name (DECL_NAME (r), i);
+              }
+            else if (!type)
+              /* We're dealing with a normal parameter.  */
+              type = tsubst (TREE_TYPE (t), args, complain, in_decl);
+
+            type = type_decays_to (type);
+            TREE_TYPE (r) = type;
+            cp_apply_type_quals_to_decl (cp_type_quals (type), r);
+
+            if (DECL_INITIAL (r))
+              {
+                if (TREE_CODE (DECL_INITIAL (r)) != TEMPLATE_PARM_INDEX)
+                  DECL_INITIAL (r) = TREE_TYPE (r);
+                else
+                  DECL_INITIAL (r) = tsubst (DECL_INITIAL (r), args,
+                                             complain, in_decl);
+              }
+
+            DECL_CONTEXT (r) = NULL_TREE;
+
+            if (!DECL_TEMPLATE_PARM_P (r))
+              DECL_ARG_TYPE (r) = type_passed_as (type);
+
+            /* Keep track of the first new parametemeter we
+               generate. That's what will be returned to the
+               caller.  */
+            if (!first_r)
+              first_r = r;
+
+            /* Build a proper chain of parameters when substituting
+               into a function parameter pack.  */
+            if (prev_r)
+              TREE_CHAIN (prev_r) = r;
+          }
 
-	if (!DECL_TEMPLATE_PARM_P (r))
-	  DECL_ARG_TYPE (r) = type_passed_as (type);
 	if (TREE_CHAIN (t))
 	  TREE_CHAIN (r) = tsubst (TREE_CHAIN (t), args,
 				   complain, TREE_CHAIN (t));
+
+        /* FIRST_R contains the start of the chain we've built.  */
+        r = first_r;
       }
       break;
 
@@ -6986,9 +8007,10 @@ tsubst_arg_types (tree arg_types,
 		  tree in_decl)
 {
   tree remaining_arg_types;
-  tree type;
+  tree type = NULL_TREE;
+  int i = 1;
+  tree expanded_args = NULL_TREE;
   tree default_arg;
-  tree result = NULL_TREE;
 
   if (!arg_types || arg_types == void_list_node)
     return arg_types;
@@ -6998,42 +8020,73 @@ tsubst_arg_types (tree arg_types,
   if (remaining_arg_types == error_mark_node)
     return error_mark_node;
 
-  type = tsubst (TREE_VALUE (arg_types), args, complain, in_decl);
-  if (type == error_mark_node)
-    return error_mark_node;
-  if (VOID_TYPE_P (type))
+  if (PACK_EXPANSION_P (TREE_VALUE (arg_types)))
     {
-      if (complain & tf_error)
-	{
-	  error ("invalid parameter type %qT", type);
-	  if (in_decl)
-	    error ("in declaration %q+D", in_decl);
-	}
-      return error_mark_node;
+      /* For a pack expansion, perform substitution on the
+         entire expression. Later on, we'll handle the arguments
+         one-by-one.  */
+      expanded_args = tsubst_pack_expansion (TREE_VALUE (arg_types),
+                                            args, complain, in_decl);
+
+      if (TREE_CODE (expanded_args) == TREE_VEC)
+        /* So that we'll spin through the parameters, one by one.  */
+        i = TREE_VEC_LENGTH (expanded_args);
+      else
+        {
+          /* We only partially substituted into the parameter
+             pack. Our type is TYPE_PACK_EXPANSION.  */
+          type = expanded_args;
+          expanded_args = NULL_TREE;
+        }
     }
 
-  /* Do array-to-pointer, function-to-pointer conversion, and ignore
-     top-level qualifiers as required.  */
-  type = TYPE_MAIN_VARIANT (type_decays_to (type));
-
-  /* We do not substitute into default arguments here.  The standard
-     mandates that they be instantiated only when needed, which is
-     done in build_over_call.  */
-  default_arg = TREE_PURPOSE (arg_types);
-
-  if (default_arg && TREE_CODE (default_arg) == DEFAULT_ARG)
-    {
-      /* We've instantiated a template before its default arguments
-	 have been parsed.  This can happen for a nested template
-	 class, and is not an error unless we require the default
-	 argument in a call of this function.  */
-      result = tree_cons (default_arg, type, remaining_arg_types);
-      VEC_safe_push (tree, gc, DEFARG_INSTANTIATIONS (default_arg), result);
-    }
-  else
-    result = hash_tree_cons (default_arg, type, remaining_arg_types);
+  while (i > 0) {
+    --i;
+    
+    if (expanded_args)
+      type = TREE_VEC_ELT (expanded_args, i);
+    else if (!type)
+      type = tsubst (TREE_VALUE (arg_types), args, complain, in_decl);
 
-  return result;
+    if (type == error_mark_node)
+      return error_mark_node;
+    if (VOID_TYPE_P (type))
+      {
+        if (complain & tf_error)
+          {
+            error ("invalid parameter type %qT", type);
+            if (in_decl)
+              error ("in declaration %q+D", in_decl);
+          }
+        return error_mark_node;
+    }
+    
+    /* Do array-to-pointer, function-to-pointer conversion, and ignore
+       top-level qualifiers as required.  */
+    type = TYPE_MAIN_VARIANT (type_decays_to (type));
+
+    /* We do not substitute into default arguments here.  The standard
+       mandates that they be instantiated only when needed, which is
+       done in build_over_call.  */
+    default_arg = TREE_PURPOSE (arg_types);
+
+    if (default_arg && TREE_CODE (default_arg) == DEFAULT_ARG)
+      {
+        /* We've instantiated a template before its default arguments
+           have been parsed.  This can happen for a nested template
+           class, and is not an error unless we require the default
+           argument in a call of this function.  */
+        remaining_arg_types = 
+          tree_cons (default_arg, type, remaining_arg_types);
+        VEC_safe_push (tree, gc, DEFARG_INSTANTIATIONS (default_arg), 
+                       remaining_arg_types);
+      }
+    else
+      remaining_arg_types = 
+        hash_tree_cons (default_arg, type, remaining_arg_types);
+  }
+	
+  return remaining_arg_types;
 }
 
 /* Substitute into a FUNCTION_TYPE or METHOD_TYPE.  This routine does
@@ -7153,11 +8206,31 @@ tsubst_exception_specification (tree fnt
 	while (specs)
 	  {
 	    tree spec;
-	    spec = tsubst (TREE_VALUE (specs), args, complain, in_decl);
-	    if (spec == error_mark_node)
-	      return spec;
-	    new_specs = add_exception_specifier (new_specs, spec, complain);
-	    specs = TREE_CHAIN (specs);
+            int i, len = 1;
+            tree expanded_specs = NULL_TREE;
+
+            if (PACK_EXPANSION_P (TREE_VALUE (specs)))
+              {
+                /* Expand the pack expansion type.  */
+                expanded_specs = tsubst_pack_expansion (TREE_VALUE (specs),
+                                                       args, complain,
+                                                       in_decl);
+                len = TREE_VEC_LENGTH (expanded_specs);
+              }
+
+            for (i = 0; i < len; ++i)
+              {
+                if (expanded_specs)
+                  spec = TREE_VEC_ELT (expanspecs, i);
+                else
+                  spec = tsubst (TREE_VALUE (specs), args, complain, in_decl);
+                if (spec == error_mark_node)
+                  return spec;
+                new_specs = add_exception_specifier (new_specs, spec, 
+                                                     complain);
+              }
+
+            specs = TREE_CHAIN (specs);
 	  }
     }
   return new_specs;
@@ -7307,12 +8380,32 @@ tsubst (tree t, tree args, tsubst_flags_
 
 	levels = TMPL_ARGS_DEPTH (args);
 	if (level <= levels)
-	  arg = TMPL_ARG (args, level, idx);
+	  {
+	    arg = TMPL_ARG (args, level, idx);
+
+	    if (arg && TREE_CODE (arg) == ARGUMENT_PACK_SELECT)
+	      /* See through ARGUMENT_PACK_SELECT arguments. */
+	      arg = ARGUMENT_PACK_SELECT_ARG (arg);
+	  }
 
 	if (arg == error_mark_node)
 	  return error_mark_node;
 	else if (arg != NULL_TREE)
 	  {
+	    if (ARGUMENT_PACK_P (arg))
+	      /* If ARG is an argument pack, we don't actually want to
+		 perform a substitution here, because substitutions
+		 for argument packs are only done
+		 element-by-element. We can get to this point when
+		 substituting the type of a non-type template
+		 parameter pack, when that type actually contains
+		 template parameter packs from an outer template, e.g.,
+
+	         template<typename... Types> struct A {
+		   template<Types... Values> struct B { };
+                 };  */
+	      return t;
+
 	    if (if (TREE_CODE (t) == TEMPLATE_TYPE_PARM)
 	      {
 		int quals;
@@ -7782,6 +8875,26 @@ tsubst (tree t, tree args, tsubst_flags_
 					     complain);
       }
 
+    case TYPE_ARGUMENT_PACK:
+    case NONTYPE_ARGUMENT_PACK:
+      {
+        tree r = make_node (TREE_CODE (t));
+        tree packed_out = 
+          tsubst_template_args (ARGUMENT_PACK_ARGS (t), 
+                                args,
+                                complain,
+                                in_decl);
+        SET_ARGUMENT_PACK_ARGS (r, packed_out);
+
+        /* For template nontype argument packs, also substitute into
+           the type.  */
+        if (TREE_CODE (t) == NONTYPE_ARGUMENT_PACK)
+          TREE_TYPE (r) = tsubst (TREE_TYPE (t), args, complain, in_decl);
+
+        return r;
+      }
+      break;
+
     default:
       sorry ("use of %qs in template",
 	     tree_code_name [(int) TREE_CODE (t)]);
@@ -7991,6 +9104,8 @@ tsubst_copy (tree t, tree args, tsubst_f
     case PARM_DECL:
       r = retrieve_local_specialization (t);
       gcc_assert (r != NULL);
+      if (TREE_CODE (r) == ARGUMENT_PACK_SELECT)
+	r = ARGUMENT_PACK_SELECT_ARG (r);
       mark_used (r);
       return r;
 
@@ -8110,13 +9225,22 @@ tsubst_copy (tree t, tree args, tsubst_f
 	(code, tsubst (TREE_TYPE (t), args, complain, in_decl),
 	 tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl));
 
+    case SIZEOF_EXPR:
+      if (PACK_EXPANSION_P (TREE_OPERAND (t, 0)))
+        {
+          /* We only want to compute the number of arguments.  */
+          tree expanded = tsubst_pack_expansion (TREE_OPERAND (t, 0), args,
+                                                complain, in_decl);
+          return build_int_cst (size_type_node, TREE_VEC_LENGTH (expanded));
+        }
+      /* Fall through */
+
     case INDIRECT_REF:
     case NEGATE_EXPR:
     case TRUTH_NOT_EXPR:
     case BIT_NOT_EXPR:
     case ADDR_EXPR:
     case UNARY_PLUS_EXPR:      /* Unary + */
-    case SIZEOF_EXPR:
     case ALIGNOF_EXPR:
     case ARROW_EXPR:
     case THROW_EXPR:
@@ -8345,6 +9469,14 @@ tsubst_copy (tree t, tree args, tsubst_f
       mark_used (TREE_OPERAND (t, 1));
       return t;
 
+    case EXPR_PACK_EXPANSION:
+      error ("invalid use of pack expansion expression");
+      return error_mark_node;
+
+    case NONTYPE_ARGUMENT_PACK:
+      error ("use %<...%> to expand argument pack");
+      return error_mark_node;
+
     default:
       return t;
     }
@@ -8801,6 +9933,14 @@ tsubst_expr (tree t, tree args, tsubst_f
         }
       break;
 
+    case EXPR_PACK_EXPANSION:
+      error ("invalid use of pack expansion expression");
+      return error_mark_node;
+
+    case NONTYPE_ARGUMENT_PACK:
+      error ("use %<...%> to expand argument pack");
+      return error_mark_node;
+
     default:
       gcc_assert (!STATEMENT_CODE_P (TREE_CODE (t)));
 
@@ -9069,6 +10209,15 @@ tsubst_copy_and_build (tree t,
 				/*overloaded_p=*/NULL);
 
     case SIZEOF_EXPR:
+      if (PACK_EXPANSION_P (TREE_OPERAND (t, 0)))
+        {
+          /* We only want to compute the number of arguments.  */
+          tree expanded = tsubst_pack_expansion (TREE_OPERAND (t, 0), args,
+                                                complain, in_decl);
+          return build_int_cst (size_type_node, TREE_VEC_LENGTH (expanded));
+        }
+      /* Fall through */
+      
     case ALIGNOF_EXPR:
       op1 = TREE_OPERAND (t, 0);
       if (!args)
@@ -9241,6 +10390,69 @@ tsubst_copy_and_build (tree t,
 	if (t == void_list_node)
 	  return t;
 
+        if ((TREE_PURPOSE (t) && PACK_EXPANSION_P (TREE_PURPOSE (t)))
+            || (TREE_VALUE (t) && PACK_EXPANSION_P (TREE_VALUE (t))))
+          {
+            /* We have pack expansions, so expand those and
+               create a new list out of it.  */
+            tree purposevec = NULL_TREE;
+            tree valuevec = NULL_TREE;
+            tree chain;
+            int i, len = -1;
+
+            /* Expand the argument expressions.  */
+            if (TREE_PURPOSE (t))
+              purposevec = tsubst_pack_expansion (TREE_PURPOSE (t), args,
+                                                 complain, in_decl);
+            if (TREE_VALUE (t))
+              valuevec = tsubst_pack_expansion (TREE_VALUE (t), args,
+                                               complain, in_decl);
+
+            /* Build the rest of the list.  */
+            chain = TREE_CHAIN (t);
+            if (chain && chain != void_type_node)
+              chain = RECUR (chain);
+
+            /* Determine the number of arguments.  */
+            if (purposevec && TREE_CODE (purposevec) == TREE_VEC)
+              {
+                len = TREE_VEC_LENGTH (purposevec);
+                gcc_assert (!valuevec || len == TREE_VEC_LENGTH (valuevec));
+              }
+            else if (TREE_CODE (valuevec) == TREE_VEC)
+              len = TREE_VEC_LENGTH (valuevec);
+            else
+              {
+                /* Since we only performed a partial substitution into
+                   the argument pack, we only return a single list
+                   node.  */
+                if (purposevec == TREE_PURPOSE (t)
+                    && valuevec == TREE_VALUE (t)
+                    && chain == TREE_CHAIN (t))
+                  return t;
+
+                return tree_cons (purposevec, valuevec, chain);
+              }
+            
+            /* Convert the argument vectors into a TREE_LIST */
+            i = len;
+            while (i > 0)
+              {
+                /* Grab the Ith values.  */
+                i--;
+                purpose = purposevec ? TREE_VEC_ELT (purposevec, i) 
+		                     : NULL_TREE;
+                value 
+		  = valuevec ? convert_from_reference (TREE_VEC_ELT (valuevec, i)) 
+                             : NULL_TREE;
+
+                /* Build the list (backwards).  */
+                chain = tree_cons (purpose, value, chain);
+              }
+
+            return chain;
+          }
+
 	purpose = TREE_PURPOSE (t);
 	if (purpose)
 	  purpose = RECUR (purpose);
@@ -9353,6 +10565,8 @@ tsubst_copy_and_build (tree t,
 	unsigned HOST_WIDE_INT idx;
 	tree type = tsubst (TREE_TYPE (t), args, complain, in_decl);
 	bool process_index_p;
+        int newlen;
+        bool need_copy_p = false;
 
 	if (type == error_mark_node)
 	  return error_mark_node;
@@ -9367,13 +10581,54 @@ tsubst_copy_and_build (tree t,
 	process_index_p = !(type && IS_AGGR_TYPE (type));
 
 	n = VEC_copy (constructor_elt, gc, CONSTRUCTOR_ELTS (t));
+        newlen = VEC_length (constructor_elt, n);
 	for (idx = 0; VEC_iterate (constructor_elt, n, idx, ce); idx++)
 	  {
 	    if (ce->index && process_index_p)
 	      ce->index = RECUR (ce->index);
-	    ce->value = RECUR (ce->value);
+
+            if (PACK_EXPANSION_P (ce->value))
+              {
+                /* Substitute into the pack expansion.  */
+                ce->value = tsubst_pack_expansion (ce->value, args, complain,
+                                                  in_decl);
+
+                if (TREE_VEC_LENGTH (ce->value) == 1)
+                  /* Just move the argument into place.  */
+                  ce->value = TREE_VEC_ELT (ce->value, 0);
+                else
+                  {
+                    /* Update the length of the final CONSTRUCTOR
+                       arguments vector, and note that we will need to
+                       copy.*/
+                    newlen = newlen + TREE_VEC_LENGTH (ce->value) - 1;
+                    need_copy_p = true;
+                  }
+              }
+            else
+              ce->value = RECUR (ce->value);
 	  }
 
+        if (need_copy_p)
+          {
+            VEC(constructor_elt,gc) *old_n = n;
+
+            n = VEC_alloc (constructor_elt, gc, newlen);
+            for (idx = 0; VEC_iterate (constructor_elt, old_n, idx, ce); 
+                 idx++)
+              {
+                if (TREE_CODE (ce->value) == TREE_VEC)
+                  {
+                    int i, len = TREE_VEC_LENGTH (ce->value);
+                    for (i = 0; i < len; ++i)
+                      CONSTRUCTOR_APPEND_ELT (n, 0,
+                                              TREE_VEC_ELT (ce->value, i));
+                  }
+                else
+                  CONSTRUCTOR_APPEND_ELT (n, 0, ce->value);
+              }
+          }
+
 	if (TREE_HAS_CONSTRUCTOR (t))
 	  return finish_compound_literal (type, n);
 
@@ -9662,6 +10917,7 @@ fn_type_unification (tree fn,
   tree parms;
   tree fntype;
   int result;
+  bool incomplete_argument_packs_p = false;
 
   gcc_assert (TREE_CODE (fn) == TEMPLATE_DECL);
 
@@ -9685,16 +10941,16 @@ fn_type_unification (tree fn,
 	 specified template argument values.  If a substitution in a
 	 template parameter or in the function type of the function
 	 template results in an invalid type, type deduction fails.  */
-      int i;
+      tree tparms = DECL_INNERMOST_TEMPLATE_PARMS (fn);
+      int i, len = TREE_VEC_LENGTH (tparms);
       tree converted_args;
-      bool incomplete;
+      bool incomplete = false;
 
       if (explicit_targs == error_mark_node)
 	return 1;
 
       converted_args
-	= (coerce_template_parms (DECL_INNERMOST_TEMPLATE_PARMS (fn),
-				  explicit_targs, NULL_TREE, tf_none,
+	= (coerce_template_parms (tparms, explicit_targs, NULL_TREE, tf_none,
 				  /*require_all_args=*/false,
 				  /*use_default_args=*/false));
       if (converted_args == error_mark_node)
@@ -9706,7 +10962,49 @@ fn_type_unification (tree fn,
 	 an incomplete set of explicit args, we must not do semantic
 	 processing during substitution as we could create partial
 	 instantiations.  */
-      incomplete = NUM_TMPL_ARGS (explicit_targs) != NUM_TMPL_ARGS (targs);
+      for (i = 0; i < len; i++)
+        {
+          tree parm = TREE_VALUE (TREE_VEC_ELT (tparms, i));
+          bool parameter_pack = false;
+
+          /* Dig out the actual parm.  */
+          if (TREE_CODE (parm) == TYPE_DECL
+              || TREE_CODE (parm) == TEMPLATE_DECL)
+            {
+              parm = TREE_TYPE (parm);
+              parameter_pack = TEMPLATE_TYPE_PARAMETER_PACK (parm);
+            }
+          else if (TREE_CODE (parm) == PARM_DECL)
+            {
+              parm = DECL_INITIAL (parm);
+              parameter_pack = TEMPLATE_PARM_PARAMETER_PACK (parm);
+            }
+
+          if (parameter_pack)
+            {
+              int level, idx;
+              tree targ;
+              template_parm_level_and_index (parm, &level, &idx);
+
+              /* Mark the argument pack as "incomplete". We could
+                 still deduce more arguments during unification.  */
+              targ = TMPL_ARG (converted_args, level, idx);
+              ARGUMENT_PACK_INCOMPLETE_P(targ) = 1;
+              ARGUMENT_PACK_EXPLICIT_ARGS (targ) = ARGUMENT_PACK_ARGS (targ);
+
+              /* We have some incomplete argument packs.  */
+              incomplete_argument_packs_p = true;
+            }
+        }
+
+      if (incomplete_argument_packs_p)
+        /* Any substitution is guaranteed to be incomplete if there
+           are incomplete argument packs, because we can still deduce
+           more arguments.  */
+        incomplete = 1;
+      else
+        incomplete = NUM_TMPL_ARGS (explicit_targs) != NUM_TMPL_ARGS (targs);
+
       processing_template_decl += incomplete;
       fntype = tsubst (fntype, converted_args, tf_none, NULL_TREE);
       processing_template_decl -= incomplete;
@@ -9736,6 +11034,22 @@ fn_type_unification (tree fn,
 				  targs, parms, args, /*subr=*/0,
 				  strict, flags);
 
+  if (result == 0 && incomplete_argument_packs_p)
+    {
+      int i, len = NUM_TMPL_ARGS (targs);
+
+      /* Clear the "incomplete" flags on all argument packs.  */
+      for (i = 0; i < len; i++)
+        {
+          tree arg = TREE_VEC_ELT (targs, i);
+          if (ARGUMENT_PACK_P (arg))
+            {
+              ARGUMENT_PACK_INCOMPLETE_P (arg) = 0;
+              ARGUMENT_PACK_EXPLICIT_ARGS (arg) = NULL_TREE;
+            }
+        }
+    }
+
   if (result == 0)
     /* All is well so far.  Now, check:
 
@@ -9891,6 +11205,9 @@ type_unification_real (tree tparms,
   while (parms && parms != void_list_node
 	 && args && args != void_list_node)
     {
+      if (TREE_CODE (TREE_VALUE (parms)) == TYPE_PACK_EXPANSION)
+        break;
+
       parm = TREE_VALUE (parms);
       parms = TREE_CHAIN (parms);
       arg = TREE_VALUE (args);
@@ -9959,6 +11276,39 @@ type_unification_real (tree tparms,
       }
     }
 
+
+  if (parms 
+      && parms != void_list_node
+      && TREE_CODE (TREE_VALUE (parms)) == TYPE_PACK_EXPANSION)
+    {
+      /* Unify the remaining arguments with the pack expansion type.  */
+      tree argvec;
+      tree parmvec = make_tree_vec (1);
+      int len = 0;
+      tree t;
+
+      /* Count the number of arguments that remain.  */
+      for (t = args; t && t != void_list_node; t = TREE_CHAIN (t))
+        len++;
+        
+      /* Allocate a TREE_VEC and copy in all of the arguments */ 
+      argvec = make_tree_vec (len);
+      for (i = 0; args && args != void_list_node; args = TREE_CHAIN (args))
+        {
+          TREE_VEC_ELT (argvec, i) = TREE_VALUE (args);
+          ++i;
+        }
+
+      /* Copy the parameter into parmvec.  */
+      TREE_VEC_ELT (parmvec, 0) = TREE_VALUE (parms);
+      if (unify_pack_expansion (tparms, targs, parmvec, argvec, strict,
+                                /*call_args_p=*/true, /*subr=*/subr))
+        return 1;
+
+      /* Advance to the end of the list of parameters.  */
+      parms = TREE_CHAIN (parms);
+    }
+
   /* Fail if we've reached the end of the parm list, and more args
      are present, and the parm list isn't variadic.  */
   if (args && args != void_list_node && parms == void_list_node)
@@ -10330,6 +11680,246 @@ check_cv_quals_for_unify (int strict, tr
   return 1;
 }
 
+/* Determines the LEVEL and INDEX for the template parameter PARM.  */
+void 
+template_parm_level_and_index (tree parm, int* level, int* index)
+{
+  if (TREE_CODE (parm) == TEMPLATE_TYPE_PARM
+      || TREE_CODE (parm) == TEMPLATE_TEMPLATE_PARM
+      || TREE_CODE (parm) == BOUND_TEMPLATE_TEMPLATE_PARM)
+    {
+      *index = TEMPLATE_TYPE_IDX (parm);
+      *level = TEMPLATE_TYPE_LEVEL (parm);
+    }
+  else
+    {
+      *index = TEMPLATE_PARM_IDX (parm);
+      *level = TEMPLATE_PARM_LEVEL (parm);
+    }
+}
+
+/* Unifies the remaining arguments in PACKED_ARGS with the pack
+   expansion at the end of PACKED_PARMS. Returns 0 if the type
+   deduction succeeds, 1 otherwise. STRICT is the same as in
+   unify. CALL_ARGS_P is true iff PACKED_ARGS is actually a function
+   call argument list. We'll need to adjust the arguments to make them
+   types. SUBR tells us if this is from a recursive call to
+   type_unification_real.  */
+int
+unify_pack_expansion (tree tparms, tree targs, tree packed_parms, 
+                      tree packed_args, int strict, bool call_args_p,
+                      bool subr)
+{
+  tree parm 
+    = TREE_VEC_ELT (packed_parms, TREE_VEC_LENGTH (packed_parms) - 1);
+  tree pattern = PACK_EXPANSION_PATTERN (parm);
+  tree pack, packs = NULL_TREE;
+  int i, start = TREE_VEC_LENGTH (packed_parms) - 1;
+  int len = TREE_VEC_LENGTH (packed_args);
+
+  /* Determine the parameter packs we will be deducing from the
+     pattern, and record their current deductions.  */
+  for (pack = PACK_EXPANSION_PARAMETER_PACKS (parm); 
+       pack; pack = TREE_CHAIN (pack))
+    {
+      tree parm_pack = TREE_VALUE (pack);
+      int idx, level;
+
+      /* Determine the index and level of this parameter pack.  */
+      template_parm_level_and_index (parm_pack, &level, &idx);
+
+      /* Keep track of the parameter packs and their corresponding
+         argument packs.  */
+      packs = tree_cons (parm_pack, TMPL_ARG (targs, level, idx), packs);
+      TREE_TYPE (packs) = make_tree_vec (len - start);
+    }
+  
+  /* Loop through all of the arguments that have not yet been
+     unified and unify each with the pattern.  */
+  for (i = start; i < len; i++)
+    {
+      tree parm = pattern;
+
+      /* For each parameter pack, clear out the deduced value so that
+         we can deduce it again.  */
+      for (pack = packs; pack; pack = TREE_CHAIN (pack))
+        {
+          int idx, level;
+          template_parm_level_and_index (TREE_PURPOSE (pack), &level, &idx);
+
+          TMPL_ARG (targs, level, idx) = NULL_TREE;
+        }
+
+      /* Unify the pattern with the current argument.  */
+      {
+        tree arg = TREE_VEC_ELT (packed_args, i);
+        int arg_strict = strict;
+        bool skip_arg_p = false;
+
+        if (call_args_p)
+          {
+            int sub_strict;
+
+            /* This mirrors what we do in type_unification_real.  */
+            switch (strict)
+              {
+              case DEDUCE_CALL:
+                sub_strict = (UNIFY_ALLOW_OUTER_LEVEL 
+                              | UNIFY_ALLOW_MORE_CV_QUAL
+                              | UNIFY_ALLOW_DERIVED);
+                break;
+                
+              case DEDUCE_CONV:
+                sub_strict = UNIFY_ALLOW_LESS_CV_QUAL;
+                break;
+                
+              case DEDUCE_EXACT:
+                sub_strict = UNIFY_ALLOW_NONE;
+                break;
+                
+              default:
+                gcc_unreachable ();
+              }
+
+            if (!TYPE_P (arg))
+              {
+                gcc_assert (TREE_TYPE (arg) != NULL_TREE);
+                if (type_unknown_p (arg))
+                  {
+                    /* [temp.deduct.type] A template-argument can be
+                       deduced from a pointer to function or pointer
+                       to member function argument if the set of
+                       overloaded functions does not contain function
+                       templates and at most one of a set of
+                       overloaded functions provides a unique
+                       match.  */
+
+                    if (resolve_overloaded_unification
+                        (tparms, targs, parm, arg, strict, sub_strict)
+                        != 0)
+                      return 1;
+                    skip_arg_p = true;
+                  }
+
+                if (!skip_arg_p)
+                  {
+                    arg = TREE_TYPE (arg);
+                    if (arg == error_mark_node)
+                      return 1;
+                  }
+              }
+      
+            arg_strict = sub_strict;
+
+            if (!subr)
+              arg_strict |= 
+                maybe_adjust_types_for_deduction (strict, &parm, &arg);
+          }
+
+        if (!skip_arg_p)
+          {
+            if (unify (tparms, targs, parm, arg, arg_strict))
+              return 1;
+          }
+      }
+
+      /* For each parameter pack, col the deduced value.  */
+      for (pack = packs; pack; pack = TREE_CHAIN (pack))
+        {
+          int idx, level;
+          template_parm_level_and_index (TREE_PURPOSE (pack), &level, &idx);
+
+          TREE_VEC_ELT (TREE_TYPE (pack), i - start) = 
+            TMPL_ARG (targs, level, idx);
+        }
+    }
+
+  /* Verify that the results of unification with the parameter packs
+     produce results consistent with what we've seen before, and make
+     the deduced argument packs available.  */
+  for (pack = packs; pack; pack = TREE_CHAIN (pack))
+    {
+      tree old_pack = TREE_VALUE (pack);
+      tree new_args = TREE_TYPE (pack);
+
+      if (old_pack && ARGUMENT_PACK_INCOMPLETE_P (old_pack))
+        {
+          /* Prepend the explicit arguments onto NEW_ARGS.  */
+          tree explicit_args = ARGUMENT_PACK_EXPLICIT_ARGS (old_pack);
+          tree old_args = new_args;
+          int i, explicit_len = TREE_VEC_LENGTH (explicit_args);
+          int len = explicit_len + TREE_VEC_LENGTH (old_args);
+
+          /* Copy the explicit arguments.  */
+          new_args = make_tree_vec (len);
+          for (i = 0; i < explicit_len; i++)
+            TREE_VEC_ELT (new_args, i) = TREE_VEC_ELT (explicit_args, i);
+
+          /* Copy the deduced arguments.  */
+          for (; i < len; i++)
+            TREE_VEC_ELT (new_args, i) =
+              TREE_VEC_ELT (old_args, i - explicit_len);
+        }
+
+      if (!old_pac_pack)
+        {
+          tree result;
+          int idx, level;
+          
+          template_parm_level_and_index (TREE_PURPOSE (pack), &level, &idx);
+
+          /* Build the deduced *_ARGUMENT_PACK.  */
+          if (TREE_CODE (TREE_PURPOSE (pack)) == TEMPLATE_PARM_INDEX)
+            {
+              result = make_node (NONTYPE_ARGUMENT_PACK);
+              TREE_TYPE (result) = 
+                TREE_TYPE (TEMPLATE_PARM_DECL (TREE_PURPOSE (pack)));
+              TREE_CONSTANT (result) = 1;
+            }
+          else
+            result = make_node (TYPE_ARGUMENT_PACK);
+
+          SET_ARGUMENT_PACK_ARGS (result, new_args);
+
+          /* Note the deduced argument packs for this parameter
+             pack.  */
+          TMPL_ARG (targs, level, idx) = result;
+        }
+      else if (ARGUMENT_PACK_INCOMPLETE_P (old_pack)
+               && (ARGUMENT_PACK_ARGS (old_pack) 
+                   == ARGUMENT_PACK_EXPLICIT_ARGS (old_pack)))
+        {
+          /* We only had the explicitly-provided arguments before, but
+             now we have a complete set of arguments.  */
+          int idx, level;
+          tree explicit_args = ARGUMENT_PACK_EXPLICIT_ARGS (old_pack);
+          template_parm_level_and_index (TREE_PURPOSE (pack), &level, &idx);
+
+          /* Keep the original deduced argument pack.  */
+          TMPL_ARG (targs, level, idx) = old_pack;
+
+          SET_ARGUMENT_PACK_ARGS (old_pack, new_args);
+      ARGUMENT_PACK_INCOMPLETE_P (old_pack) = 1;
+          ARGUMENT_PACK_EXPLICIT_ARGS (old_pack) = explicit_args;
+        }
+      else if (!comp_template_args (ARGUMENT_PACK_ARGS (old_pack),
+                                    new_args))
+        /* Inconsistent unification of this parameter pack.  */
+        return 1;
+      else
+        {
+          int idx, level;
+          
+          template_parm_level_and_index (TREE_PURPOSE (pack), &level, &idx);
+
+          /* Keep the original deduced argument pack.  */
+          TMPL_ARG (targs, level, idx) = old_pack;
+        }
+    }
+
+  return 0;
+}
+
 /* Deduce the value of template parameters.  TPARMS is the (innermost)
    set of template parameters to a template.  TARGS is the bindings
    for those template parameters, as determined thus far; TARGS may
@@ -10570,6 +12160,12 @@ unify (tree tparms, tree targs, tree par
 	    return 1;
 	}
 
+      /* If ARG is a parameter pack or an expansion, we cannot unify
+	 against it unless PARM is also a parameter pack.  */
+      if ((template_parameter_pack_p (arg) || PACK_EXPANSION_P (arg))
+	  && !template_parameter_pack_p (parm))
+	return 1;
+
       TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), idx) = arg;
       return 0;
 
@@ -10620,6 +12216,12 @@ unify (tree tparms, tree targs, tree par
       else
 	return 1;
 
+      /* If ARG is a parameter pack or an expansion, we cannot unify
+	 against it unless PARM is also a paramaram pack.  */
+      if ((template_parameter_pack_p (arg) || PACK_EXPANSION_P (arg))
+	  && !TEMPLATE_PARM_PARAMETER_PACK (parm))
+	return 1;
+
       TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), idx) = arg;
       return 0;
 
@@ -10920,6 +12522,47 @@ unify (tree tparms, tree targs, tree par
       /* Matched cases are handled by the ARG == PARM test above.  */
       return 1;
 
+    case TYPE_ARGUMENT_PACK:
+    case NONTYPE_ARGUMENT_PACK:
+      {
+        tree packed_parms = ARGUMENT_PACK_ARGS (parm);
+        tree packed_args = ARGUMENT_PACK_ARGS (arg);
+        int i, len = TREE_VEC_LENGTH (packed_parms);
+        int argslen = TREE_VEC_LENGTH (packed_args);
+        int parm_variadic_p = 0;
+
+        /* Check if the parameters end in a pack, making them variadic.  */
+        if (len > 0 
+	    && PACK_EXPANSION_P (TREE_VEC_ELT (packed_parms, len - 1)))
+          parm_variadic_p = 1;
+
+        /* If we don't have enough arguments to satisfy the parameters
+           (not counting the pack expression at the end), or we have
+           too many arguments for a parameter list that doesn't end in
+           a pack expression, we can't unify.  */
+        if (argslen < (len - parm_variadic_p)
+            || (argslen > len && !parm_variadic_p))
+          return 1;
+
+        /* Unify all of the parameters that precede the (optional)
+           pack expression.  */
+        for (i = 0; i < len - parm_variadic_p; ++i)
+              {
+            if (unify (tparms, targs, TREE_VEC_ELT (packed_parms, i),
+                       TREE_VEC_ELT (packed_args, i), strict))
+              return 1;
+          }
+
+        if (parm_variadic_p)
+          return unify_pack_expansion (tparms, targs, 
+                                       packed_parms, packed_args,
+                                       strict, /*call_args_p=*/false,
+                                       /*subr=*/false);
+        return 0;
+      }
+
+      break;
+
     default:
       gcc_assert (EXPR_P (parm));
 
@@ -11090,6 +12733,18 @@ more_specialized_fn (tree pat1, tree pat
       int quals1 = -1;
       int quals2 = -1;
 
+      if (TREE_CODE (arg1) == TYPE_PACK_EXPANSION
+          && TREE_CODE (arg2) == TYPE_PACK_EXPANSION)
+        {
+          /* When both arguments are pack expansions, we need only
+             unify the patterns themselves.  */
+          arg1 = PACK_EXPANSION_PATTERN (arg1);
+          arg2 = PACK_EXPANSION_PATTERN (arg2);
+
+          /* This is the last comparison we need to do.  */
+          len = 0;
+        }
+
       if (TREE_CODE (arg1) == REFERENCE_TYPE)
 	{
 	  arg1 = TREE_TYPE (arg1);
@@ -11145,8 +12800,62 @@ more_specialized_fn (tree pat1, tree pat
       arg1 = TYPE_MAIN_VARIANT (arg1);
       arg2 = TYPE_MAIN_VARIANT (arg2);
 
-      deduce1 = !unify (tparms1, targs1, arg1, arg2, UNIFY_ALLOW_NONE);
-      deduce2 = !unify (tparms2, targs2, arg2, arg1, UNIFY_ALLOW_NONE);
+      if (TREE_CODE (arg1) == TYPE_PACK_EXPANSION)
+        {
+          int i, len2 = len + 1;
+          tree parmvec = make_tree_vec (1);
+          tree argvec = make_tree_vec (len2);
+          tree ta = args2;
+
+          /* Setup the parameter vector, which contains only ARG1.  */
+          TREE_VEC_ELT (parmvec, 0) = arg1;
+
+          /* Setup the argument vector, which contains the remaining
+             arguments.  */
+          for (i = 0; i < len2; i++, ta = TREE_CHAIN (ta))
+            TREE_VEC_ELT (argvec, i) = TREE_VALUE (ta);
+
+          deduce1 = !unify_pack_expansion (tparms1, targs1, parmvec, 
+					   argvec, UNIFY_ALLOW_NONE, 
+                                           /*call_args_p=*/false, 
+					   /*subr=*/0);
+
+          /* We cannot deduce in the other direction, because ARG1 is
+             a pack expansion but ARG2 is not.  */
+          deduce2 = 0;
+        }
+      else if (TREE_CODE (arg2) == TYPE_PACK_EXPANSION)
+        {
+          int i, len1 = len + 1;
+          tree parmvec = make_tree_vec (1);
+          tree argvec = make_tree_vec (len1);
+          tree ta = args1;
+
+          /* Setup the parameter vector, which contains only ARG1.  */
+          TREE_VEC_ELT (parmvec, 0) = arg2;
+
+          /* Setup the argument vector, which contains the remaining
+             arguments.  */
+          for (i = 0; i < len1; i++, ta = TREE_CHAIN (ta))
+            TREE_VEC_ELT (argvec, i) = TREE_VALUE (ta);
+
+          deduce2 = !unify_pack_expansion (tparms2, targs2, parmvec, 
+					   argvec, UNIFY_ALLOW_NONE, 
+                                           /*call_args_p=*/false, 
+					   /*subr=*/0);
+
+          /* We cannot deduce in the other direction, because ARG2 is
+             a pack expansion but ARG1 is not.*/
+          deduce1 = 0;
+        }
+
+      else
+        {
+          /* The normal case, where neither argument is a pack
+             expansion.  */
+          deduce1 = !unify (tparms1, targs1, arg1, arg2, UNIFY_ALLOW_NONE);
+          deduce2 = !unify (tparms2, targs2, arg2, arg1, UNIFY_ALLOW_NONE);
+        }
 
       if (!deduce1)
 	better2 = -1;
@@ -11171,12 +12880,31 @@ more_specialized_fn (tree pat1, tree pat
       if (deduce2 && !deduce1 && !better1)
 	better1 = 1;
 
+      if (TREE_CODE (arg1) == TYPE_PACK_EXPANSION
+          || TREE_CODE (arg2) == TYPE_PACK_EXPANSION)
+        /* We have already processed all of the arguments in our
+           handing of the pack expansion type.  */
+        len = 0;
+
       args1 = TREE_CHAIN (args1);
       args2 = TREE_CHAIN (args2);
     }
 
   processing_template_decl--;
 
+  /* All things being equal, if the next argument is a pack expansion
+     for one function but not for the other, prefer the
+     non-variadic function.  */
+  if ((better1 > 0) - (better2 > 0) == 0
+      && args1 && TREE_VALUE (args1)
+      && args2 && TREE_VALUE (args2))
+    {
+      if (TREE_CODE (TREE_VALUE (args1)) == TYPE_PACK_EXPANSION)
+        return TREE_CODE (TREE_VALUE (args2)) == TYPE_PACK_EXPANSION ? 0 : -1;
+      else if (TREE_CODE (TREE_VALUE (args2)) == TYPE_PACK_EXPANSION)
+        return 1;
+    }
+
   return (better1 > 0) - (better2 > 0);
 }
 
@@ -11200,6 +12928,7 @@ more_specialized_class (tree pat1, tree 
   tree targs;
   tree tmpl1, tmpl2;
   int winner = 0;
+  bool any_deductions = false;
 
   tmpl1 = TREE_TYPE (pat1);
   tmpl2 = TREE_TYPE (pat2);
@@ -11213,15 +12942,46 @@ more_specialized_class (tree pat1, tree 
 			      CLASSTYPE_TI_ARGS (tmpl1),
 			      CLASSTYPE_TI_ARGS (tmpl2));
   if (targs)
-    --winner;
+    {
+      --winner;
+      any_deductions = true;
+    }
 
   targs = get_class_bindings (TREE_VALUE (pat2),
 			      CLASSTYPE_TI_ARGS (tmpl2),
 			      CLASSTYPE_TI_ARGS (tmpl1));
   if (targs)
-    ++winner;
+    {
+      ++winner;
+      any_deductions = true;
+    }
   --processing_template_decl;
 
+  /* In the case of a tie where at least one of the class templates
+     has a parameter pack at the end, the template with the most
+     non-packed parameters wins.  */
+  if (winner == 0
+      && any_deductions
+      && (template_args_variadic_p (TREE_PURPOSE (pat1))
+          || template_args_variadic_p (TREE_PURPOSE (pat2))))
+    {
+      tree args1 = INNERMOST_TEMPLATE_ARGS (TREE_PURPOSE (pat1));
+      tree args2 = INNERMOST_TEMPLATE_ARGS (TREE_PURPOSE (pat2));
+      int len1 = TREE_VEC_LENGTH (args1);
+      int len2 = TREE_VEC_LENGTH (args2);
+
+      /* We don't count the pack expansion at the end.  */
+      if (template_args_variadic_p (TREE_PURPOSE (pat1)))
+        --len1;
+      if (template_args_variadic_p (TREE_PURPOSE (pat2)))
+        --len2;
+
+      if (len1 > len2)
+        return 1;
+      else if (len1 < len2)
+        return -1;
+    }
+
   return winner;
 }
 
@@ -11910,11 +13670,11 @@ regenerate_decl_from_template (tree decl
       pattern_parm
 	= skip_artificial_parms_for (code_pattern,
 				     DECL_ARGUMENTS (code_pattern));
-      while (decl_parm)
+      while (decl_parm && !FUNCTION_PARAMETER_PACK_P (pattern_parm))
 	{
 	  tree parm_type;
 	  tree attributes;
-
+          
 	  if (DECL_NAME (decl_parm) != DECL_NAME (pattern_parm))
 	    DECL_NAME (decl_parm) = DECL_NAME (pattern_parm);
 	  parm_type = tsubst (TREE_TYPE (pattern_parm), args, tf_error,
@@ -11931,7 +13691,39 @@ regenerate_decl_from_template (tree decl
 	  decl_parm = TREE_CHAIN (decl_parm);
 	  pattern_parm = TREE_CHAIN (pattern_parm);
 	}
-
+      /* Merge any parameters that match with the function parameter
+         pack.  */
+      if (pattern_parm && FUNCTION_PARAMETER_PACK_P (pattern_parm))
+        {
+          int i, len;
+          tree expanded_types;
+          /* Expand the TYPE_PACK_EXPANSION that provides the types for
+             the parameters in this function parameter pack.  */
+          expanded_types = tsubst_pack_expansion (TREE_TYPE (pattern_parm), 
+                                                 args, tf_error, NULL_TREE);
+          len = TREE_VEC_LENGTH (expanded_types);
+          for (i = 0; i < len; i++)
+            {
+              tree parm_type;
+              tree attributes;
+          
+              if (DECL_NAME (decl_parm) != DECL_NAME (pattern_parm))
+                /* Rename the parameter to include the index.  */
+                DECL_NAME (decl_parm) = 
+                  make_ith_pack_parameter_name (DECL_NAME (pattern_parm), i);
+              parm_type = TREE_VEC_ELT (expanded_types, i);
+              parm_type = type_decays_to (parm_type);
+              if (!same_type_p (TREE_TYPE (decl_parm), parm_type))
+                TREE_TYPE (decl_parm) = parm_type;
+              attributes = DECL_ATTRIBUTES (pattern_parm);
+              if (DECL_ATTRIBUTES (decl_parm) != attributes)
+                {
+                  DECL_ATTRIBUTES (decl_parm) = attributes;
+                  cplus_decl_attributes (&decl_parm, attributes, /*flags=*/0);
+                }
+              decl_parm = TREE_CHAIN (decl_parm);
+            }
+        }
       /* Merge additional specifiers from the CODE_PATTERN.  */
       if (DECL_DECLARED_INLINE_P (code_pattern)
 	  && !DECL_DECLARED_INLINE_P (decl))
@@ -12138,8 +13930,8 @@ instantiate_decl (tree d, int defer_ok,
       if (TREE_CODE (gen) == FUNCTION_DECL)
 	{
 	  tsubst (DECL_ARGUMENTS (gen), gen_args, tf_warning_or_error, d);
-	  tsubst (TYPE_RAISES_EXCEPTIONS (type), gen_args,
-		  tf_warning_or_error, d);
+          tsubst_exception_specification (type, gen_args, tf_warning_or_error,
+                                          d);
 	  /* Don't simply tsubst the function type, as that will give
 	     duplicate warnings about poor parameter qualifications.
 	     The function arguments are the same as the decl_arguments
@@ -12314,12 +14106,46 @@ instantiate_decl (tree d, int defer_ok,
 	  spec_parm = skip_artificial_parms_for (d, spec_parm);
 	  tmpl_parm = skip_artificial_parms_for (subst_decl, tmpl_parm);
 	}
-      while (tmpl_parm)
+      while (tmpl_parm && !FUNCTION_PARAMETER_PACK_P (tmpl_parm))
 	{
 	  register_local_specialization (spec_parm, tmpl_parm);
 	  tmpl_parm = TREE_CHAIN (tmpl_parm);
 	  spec_parm = TREE_CHAIN (spec_parm);
 	}
+      if (tmpl_parm && FUNCTION_PARAMETER_PACK_P (tmpl_parm))
+        {
+          /* Collect all of the extra "packed" parameters into an
+             argument pack.  */
+          tree parmvec;
+          tree parmtypevec;
+          tree argpack = make_node (NONTYPE_ARGUMENT_PACK);
+          tree argtypepack = make_node (TYPE_ARGUMENT_PACK);
+          int i, len = 0;
+          tree t;
+          
+          /* Count how many parameters remain.  */
+          for (t = spec_parm; t; t = TREE_CHAIN (t))
+            len++;
+
+          /* Fill in PARMVEC and PARMTYPEVEC with all of the parameters.  */
+          parmvec = make_tree_vec (len);
+          parmtypevec = make_tree_vec (len);
+          for(i = 0; i < len; i++, spec_parm = TREE_CHAIN (spec_parm))
+            {
+              TREE_VEC_ELT (parmvec, i) = spec_parm;
+              TREE_VEC_ELT (parmtypevec, i) = TREE_TYPE (spec_parm);
+            }
+
+          /* Build the argument packs.  */
+          SET_ARGUMENT_PACK_ARGS (argpack, parmvec);
+          SET_ARGUMENT_PACK_ARGS (argtypepack, parmtypevec);
+          TREE_TYPE (argpack) = argtypepack;
+          
+          /* Register the (value) argument pack as a specialization of
+             TMPL_PARM, then move on.  */
+          register_local_specialization (argpack, tmpl_parm);
+          tmpl_parm = TREE_CHAIN (tmpl_parm);
+        }
       gcc_assert (!spec_parm);
 
       /* Substitute into the body of the function.  */
@@ -12471,24 +14297,99 @@ tsubst_initializer_list (tree t, tree ar
     {
       tree decl;
       tree init;
+      tree expanded_bases = NULL_TREE;
+      tree expanded_arguments = NULL_TREE;
+      int i, len = 1;
 
-      decl = tsubst_copy (TREE_PURPOSE (t), argvec, tf_warning_or_error,
-			  NULL_TREE);
-      decl = expand_member_init (decl);
-      if (decl && !DECL_P (decl))
-	in_base_initializer = 1;
-
-      init = tsubst_expr (TREE_VALUE (t), argvec, tf_warning_or_error,
-			  NULL_TREE, 
-			  /*integral_constant_expression_p=*/false);
-      in_base_initializer = 0;
-
-      if (decl)
-	{
-	  init = build_tree_list (decl, init);
-	  TREE_CHAIN (init) = inits;
-	  inits = init;
-	}
+      if (TREE_CODE (TREE_PURPOSE (t)) == TYPE_PACK_EXPANSION)
+        {
+          tree expr;
+          tree arg;
+
+          /* Expand the base class expansion type into separate base
+             classes.  */
+          expanded_bases = tsubst_pack_expansion (TREE_PURPOSE (t), argvec,
+                                                 tf_warning_or_error,
+                                                 NULL_TREE);
+          if (expanded_bases == error_mark_node)
+            continue;
+          
+          /* We'll be building separate TREE_LISTs of arguments for
+             each base.  */
+          len = TREE_VEC_LENGTH (expanded_bases);
+          expanded_arguments = make_tree_vec (len);
+          for (i = 0; i < len; i++)
+            TREE_VEC_ELT (expanded_arguments, i) = NULL_TREE;
+
+          /* Build a dummy EXPR_PACK_EXPANSION that will be used to
+             expand each argument in the TREE_VALUE of t.  */
+          expr = make_node (EXPR_PACK_EXPANSION);
+          PACK_EXPANSION_PARAMETER_PACKS (expr) =
+            PACK_EXPANSION_PARAMETER_PACKS (TREE_PURPOSE (t));
+
+          /* Substitute parameter packs into each argument in the
+             TREE_LIST.  */
+          in_base_initializer = 1;
+          for (arg = TREE_VALUE (t); arg; arg = TREE_CHAIN (arg))
+            {
+              tree expanded_exprs;
+
+              /* Expand the argument.  */
+              SET_PACK_EXPANSION_PATTERN (expr, TREE_VALUE (arg));
+              expanded_exprs = tsubst_pack_expansion (expr, argvec,
+                                                      tf_warning_or_error,
+                                                      NULL_TREE);
+
+              /* Prepend each of the expanded expressions to the
+                 corresponding TREE_LIST in EXPANDED_ARGUMENTS.  */
+              for (i = 0; i < len; i++)
+                {
+                  TREE_VEC_ELT (expanded_arguments, i) = 
+                    tree_cons (NULL_TREE, TREE_VEC_ELT (expanded_exprs, i),
+                               TREE_VEC_ELT (expanded_arguments, i));
+                }
+            }
+          in_base_initializer = 0;
+
+          /* Reverse all of the TREE_LISTs in EXPANDED_ARGUMENTS,
+             since we built them backwards.  */
+          for (i = 0; i < len; i++)
+            {
+              TREE_VEC_ELT (expanded_arguments, i) = 
+                nreverse (TREE_VEC_ELT (expanded_arguments, i));
+            }
+        }
+
+      for (i = 0; i < len; ++i)
+        {
+          if (expanded_bases)
+            {
+              decl = TREE_VEC_ELT (expanded_bases, i);
+              decl = expand_member_init (decl);
+              init = TREE_VEC_ELT (expanded_ments, i);
+            }
+          else
+            {
+              decl = tsubst_copy (TREE_PURPOSE (t), argvec, 
+                                  tf_warning_or_error, NULL_TREE);
+
+              decl = expand_member_init (decl);
+              if (decl && !DECL_P (decl))
+                in_base_initializer = 1;
+
+              init = tsubst_expr (TREE_VALUE (t), argvec, 
+				  tf_warning_or_error, NULL_TREE,
+                                  /*integral_constant_expression_p=*/false);
+              in_base_initializer = 0;
+            }
+
+          if (decl)
+            {
+              init = build_tree_list (decl, init);
+              TREE_CHAIN (init) = inits;
+              inits = init;
+            }
+        }
     }
   return inits;
 }
@@ -12729,6 +14630,22 @@ dependent_type_p_r (tree type)
   if (TREE_CODE (type) == TYPEOF_TYPE)
     return true;
 
+  /* A template argument pack is dependent if any of its packed
+     arguments are.  */
+  if (TREE_CODE (type) == TYPE_ARGUMENT_PACK)
+    {
+      tree args = ARGUMENT_PACK_ARGS (type);
+      int i, len = TREE_VEC_LENGTH (args);
+      for (i = 0; i < len; ++i)
+        if (dependent_template_arg_p (TREE_VEC_ELT (args, i)))
+          return true;
+    }
+
+  /* All TYPE_PACK_EXPANSIONs are dependent, because parameter packs must
+     be template parameters.  */
+  if (TREE_CODE (type) == TYPE_PACK_EXPANSION)
+    return true;
+
   /* The standard does not not specifically mention types that are local
      to template functions or local classes, but they should be
      considered dependent too.  For example:
@@ -12900,9 +14817,11 @@ value_dependent_expression_p (tree expre
     case SIZEOF_EXPR:
     case ALIGNOF_EXPR:
       /* A `sizeof' expression is value-dependent if the operand is
-	 type-dependent.  */
+	 type-dependent or is a pack expansion.  */
       expression = TREE_OPERAND (expression, 0);
-      if (TYPE_P (expression))
+      if (PACK_EXPANSION_P (expression))
+        return true;
+      else if (TYPE_P (expression))
 	return dependent_type_p (expression);
       return type_dependent_expression_p (expression);
 
@@ -12919,6 +14838,20 @@ value_dependent_expression_p (tree expre
 	 such calls are value-dependent.  */
       return true;
 
+    case NONTYPE_ARGUMENT_PACK:
+      /* A NONTYPE_ARGUMENT_PACK is value-dependent if any packed argument
+         is value-dependent.  */
+      {
+        tree values = ARGUMENT_PACK_ARGS (expression);
+        int i, len = TREE_VEC_LENGTH (values);
+        
+        for (i = 0; i < len; ++i)
+          if (value_dependent_expression_p (TREE_VEC_ELT (values, i)))
+            return true;
+        
+        return false;
+      }
+
     default:
       /* A constant expression is value-dependent if any subexpression is
 	 value-dependent.  */
@@ -13095,7 +15028,7 @@ any_type_dependent_arguments_p (tree arg
 
 /* Returns TRUE if the ARG (a template argument) is dependent.  */
 
-static bool
+bool
 dependent_template_arg_p (tree arg)
 {
   if (!processing_template_decl)
@@ -13104,6 +15037,18 @@ dependent_template_arg_p (tree arg)
   if (TREE_CODE (arg) == TEMPLATE_DECL
       || TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM)
     return dependent_template_p (arg);
+  else if (ARGUMENT_PACK_P (arg))
+    {
+      tree args = ARGUMENT_PACK_ARGS (arg);
+      int i, len = TREE_VEC_LENGTH (args);
+      for (i = 0; i < len; ++i)
+        {
+          if (dependent_template_arg_p (TREE_VEC_ELT (args, i)))
+            return true;
+        }
+
+      return false;
+    }
   else if (TYPE_P (arg))
     return dependent_type_p (arg);
   else
@@ -13131,14 +15076,30 @@ any_template_arguments_need_structural_e
       for (j = 0; j < TREE_VEC_LENGTH (level); ++j)
 	{
 	  tree arg = TREE_VEC_ELT (level, j);
-	  if (TREE_CODE (arg) == TEMPLATE_DECL
-	      || TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM)
-	    continue;
-	  else if (TYPE_P (arg) && TYPE_STRUCTURAL_EQUALITY_P (arg))
-	    return true;
-	  else if (!TYPE_P (arg) && TREE_TYPE (arg)
-		   && TYPE_STRUCTURAL_EQUALITY_P (TREE_TYPE (arg)))
-	    return true;
+	  tree packed_args = NULL_TREE;
+	  int k, len = 1;
+
+	  if (ARGUMENT_PACK_P (arg))
+	    {
+	      /* Look inside the argument pack.  */
+	      packed_args = ARGUMENT_PACK_ARGS (arg);
+	      len = TREE_VEC_LENGTH (packed_args);
+	    }
+
+	  for (k = 0; k < len; ++k)   {
+	      if (packed_args)
+		arg = TREE_VEC_ELT (packed_args, k);
+
+	      if (TREE_CODE (arg) == TEMPLATE_DECL
+		  || TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM)
+		continue;
+	      else if (TYPE_P (arg) && TYPE_STRUCTURAL_EQUALITY_P (arg))
+		return true;
+	      else if (!TYPE_P (arg) && TREE_TYPE (arg)
+		       && TYPE_STRUCTURAL_EQUALITY_P (TREE_TYPE (arg)))
+		return true;
+	    }
 	}
     }
 
Index: semantics.c
===================================================================
--- semantics.c	(revision 122403)
+++ semantics.c	(working copy)
@@ -509,6 +509,8 @@ finish_cond (tree *cond_p, tree expr)
       tree cond = pop_stmt_list (*cond_p);
       if (TREE_CODE (cond) == DECL_EXPR)
 	expr = cond;
+
+      check_for_bare_parameter_packs (expr);
     }
   *cond_p = expr;
 }
@@ -618,6 +620,8 @@ finish_expr_stmt (tree expr)
       else if (!type_dependent_expression_p (expr))
 	convert_to_void (build_non_dependent_expr (expr), "statement");
 
+      check_for_bare_parameter_packs (expr);
+
       /* Simplification of inner statement expressions, compound exprs,
 	 etc can result in us already having an EXPR_STMT.  */
       if (TREE_CODE (expr) != CLEANUP_POINT_EXPR)
@@ -866,6 +870,7 @@ finish_for_expr (tree expr, tree for_stm
   else if (!type_dependent_expression_p (expr))
     convert_to_void (build_non_dependent_expr (expr), "3rd expression in for");
   expr = maybe_cleanup_point_expr_void (expr);
+  check_for_bare_pae_pater_packs (expr);
   FOR_EXPR (for_stmt) = expr;
 }
 
@@ -966,6 +971,7 @@ finish_switch_cond (tree cond, tree swit
   add_stmt (switch_stmt);
   push_switch (switch_stmt);
   SWITCH_STMT_BODY (switch_stmt) = push_stmt_list ();
+  check_for_bare_parameter_packs (cond);
 }
 
 /* Finish the body of a switch-statement, which may be given by
@@ -1362,7 +1368,22 @@ finish_mem_initializers (tree mem_inits)
   mem_inits = nreverse (mem_inits);
 
   if (processing_template_decl)
-    add_stmt (build_min_nt (CTOR_INITIALIZER, mem_inits));
+    {
+      tree mem;
+
+      for (mem = mem_inits; mem; mem = TREE_CHAIN (mem))
+        {
+          /* If the TREE_PURPOSE is a TYPE_PACK_EXPANSION, skip the
+             check for bare parameter packs in the TREE_VALUE, because
+             any parameter packs in the TREE_VALUE have already been
+             bound as part of the TREE_PURPOSE.  See
+             make_pack_expansion for more information.  */
+          if (TREE_CODE (TREE_PURPOSE (mem)) != TYPE_PACK_EXPANSION)
+            check_for_bare_parameter_packs (TREE_VALUE (mem));
+        }
+
+      add_stmt (build_min_nt (CTOR_INITIALIZER, mem_inits));
+    }
   else
     emit_mem_initializers (mem_inits);
 }
Index: name-lookup.c
===================================================================
--- name-lookup.c	(revision 122403)
+++ name-lookup.c	(working copy)
@@ -4563,6 +4563,18 @@ arg_assoc_type (struct arg_lookup *k, tr
     case LAe LANG_TYPE:
       gcc_assert (type == unknown_type_node);
       return false;
+    case TYPE_PACK_EXPANSION:
+      return arg_assoc_type (k, PACK_EXPANSION_PATTERN (type));
+    case TYPE_ARGUMENT_PACK:
+      {
+        tree args = ARGUMENT_PACK_ARGS (type);
+        int i, len = TREE_VEC_LENGTH (args);
+        for (i = 0; i < len; i++)
+          if (arg_assoc_type (k, TREE_VEC_ELT (args, i)))
+            return true;
+      }
+      break;
+
     default:
       gcc_unreachable ();
     }
Index: decl2.c
===================================================================
--- decl2.c	(revision 122403)
+++ decl2.c	(working copy)
@@ -136,6 +136,12 @@ cp_build_parm_decl (tree name, tree type
      sees templates.  */
   if (!processing_template_decl)
     DECL_ARG_TYPE (parm) = type_passed_as (type);
+
+  /* If the type is a pack expansion, then we have a function
+     parameter pack. */
+  if (type && TREE_CODE (type) == TYPE_PACK_EXPANSION)
+    FUNCTION_PARAMETER_PACK_P (parm) = 1;
+
   return parm;
 }
 
Index: parser.c
===================================================================
--- parser.c	(revision 122403)
+++ parser.c	(working copy)
@@ -891,6 +891,7 @@ make_declarator (cp_declarator_kind kind
   declarator->kind = kind;
   declarator->attributes = NULL_TREE;
   declarator->declarator = NULL;
+  declarator->parameter_pack_p = false;
 
   return declarator;
 }
@@ -928,7 +929,7 @@ make_id_declarator (tree qualifying_scop
   declarator->u.id.qualifying_scope = qualifying_scope;
   declarator->u.id.unqualified_name = unqualified_name;
   declarator->u.id.sfk = sfk;
-
+  
   return declarator;
 }
 
@@ -945,6 +946,13 @@ make_pointer_declarator (cp_cv_quals cv_
   declarator->declarator = target;
   declarator->u.pointer.qualifiers = cv_qualifiers;
   declarator->u.pointer.class_type = NULL_TREE;
+  if (target)
+    {
+      declarator->parameter_pack_p = target->parameter_pack_p;
+      target->parameter_pack_p = false;
+    }
+  else
+    declarator->parameter_pack_p = false;
 
   return declarator;
 }
@@ -960,6 +968,13 @@ make_reference_declarator (cp_cv_quals c
   declarator->declarator = target;
   declarator->u.pointer.qualifiers = cv_qualifiers;
   declarator->u.pointer.class_type = NULL_TREE;
+  if (target)
+    {
+      declarator->parameter_pack_p = target->parameter_pack_p;
+      target->parameter_pack_p = false;
+    }
+  else
+    declarator->parameter_pack_p = false;
 
   return declarator;
 }
@@ -978,6 +993,14 @@ make_ptrmem_declarator (cp_cv_quals cv_q
   declarator->u.pointer.qualifiers = cv_qualifiers;
   declarator->u.pointer.class_type = class_type;
 
+  if (pointee)
+    {
+      declarator->parameter_pack_p = pointee->parameter_pack_p;
+      pointee->parameter_pack_p = false;
+    }
+  else
+    declarator->parameter_pack_p = false;
+
   return declarator;
 }
 
@@ -999,6 +1022,13 @@ make_call_declarator (cp_declarator *tar
   declarator->u.function.parameters = parms;
   declarator->u.function.qualifiers = cv_qualifiers;
   declarator->u.function.exception_specification = exception_specification;
+  if (target)
+    {
+      declarator->parameter_pack_p = target->parameter_pack_p;
+      target->parameter_pack_p = false;
+    }
+  else
+    declarator->parameter_pack_p = false;
 
   return declarator;
 }
@@ -1014,6 +1044,13 @@ make_array_declarator (cp_declarator *el
   declarator = make_declarator (cdk_array);
   declarator->declarator = element;
   declarator->u.array.bounds = bounds;
+  if (element)
+    {
+      declarator->parameter_pack_p = element->parameter_pack_p;
+      element->parameter_pack_p = false;
+    }
+  else
+    declarator->parameter_pack_p = false;
 
   return declarator;
 }
@@ -1517,7 +1554,7 @@ static tree cp_parser_postfix_open_squar
 static tree cp_parser_postfix_dot_deref_expression
   (cp_parser *, enum cpp_ttype, tree, bool, cp_id_kind *);
 static tree cp_parser_parenthesized_expression_list
-  (cp_parser *, bool, bool, bool *);
+  (cp_parser *, bool, bool, bool, bool *);
 static void cp_parser_pseudo_destructor_name
   (cp_parser *, tree *, tree *);
 static tree cp_parser_unary_expression
@@ -1730,9 +1767,9 @@ static void cp_parser_template_declarati
 static tree cp_parser_template_parameter_list
   (cp_parser *);
 static tree cp_parser_template_parameter
-  (cp_parser *, bool *);
+  (cp_parser *, bool *, bool *);
 static tree cp_parser_type_parameter
-  (cp_parser *);
+  (cp_parser *, bool *);
 static tree cp_parser_template_id
   (cp_parser *, bool, bool, bool);
 static tree cp_parser_template_name
@@ -4367,7 +4404,7 @@ cp_parser_postfix_expression (cp_parser 
 	      }
 	    args = (cp_parser_parenthesized_expression_list
 		    (parser, /*is_attribute_list=*/false,
-		     /*cast_p=*/false,
+		     /*cast_p=*/false, /*allow_expansion_p=*/true,
 		     /*non_constant_p=*/NULL));
 	    if (is_builtin_constant_p)
 	      {
@@ -4763,6 +4800,9 @@ cp_parser_postfix_dot_deref_expression (
 
    CAST_P is true if this expression is the target of a cast.
 
+   ALLOW_EXPANSION_P is true if this expression allows expansion of an
+   argument pack.
+
    Returns a TREE_LIST.  The TREE_VALUE of each node is a
    representation of an assignment-expression.  Note that a TREE_LIST
    is returned even if there is only a single expression in the list.
@@ -4777,6 +4817,7 @@ static tree
 cp_parser_parenthesized_expression_list (cp_parser* parser,
 					 bool is_attribute_list,
 					 bool cast_p,
+                                         bool allow_expansion_p,
 					 bool *non_constant_p)
 {
   tree expression_list = NULL_TREE;
@@ -4826,6 +4867,18 @@ cp_parser_parenthesized_expression_list 
 	    if (fold_expr_p)
 	      expr = fold_non_dependent_expr (expr);
 
+            /* If we have an ellipsis, then this is an expression
+	       expansion.  */
+            if (allow_expansion_p
+                && cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
+              {
+                /* Consume the `...'.  */
+                cp_lexer_consume_token (parser->lexer);
+
+                /* Build the argument pack.  */
+                expr = make_pack_expansion (expr);
+              }
+
 	     /* Add it to the list.  We add error_mark_node
 		expressions to the list, so that we can still tell if
 		the correct form for a parenthesized expression-list
@@ -5275,7 +5328,7 @@ cp_parser_new_placement (cp_parser* pars
 
   /* Parse the expression-list.  */
   expression_list = (cp_parser_parenthesized_expression_list
-		     (parser, false, /*cast_p=*/false,
+		     (parser, false, /*cast_p=*/false, /*allow_expansion_p=*/true,
 		      /*non_constant_p=*/NULL));
 
   return expression_list;
@@ -5480,7 +5533,7 @@ cp_parser_new_initializer (cp_parser* pa
   tree expression_list;
 
   expression_list = (cp_parser_parenthesized_expression_list
-		     (parser, false, /*cast_p=*/false,
+		     (parser, false, /*cast_p=*/false, /*allow_expansion_p=*/true,
 		      /*non_constant_p=*/NULL));
   if (!expression_list)
     expression_list = void_zero_node;
@@ -8168,8 +8221,8 @@ cp_parser_ctor_initializer_opt (cp_parse
 /* Parse a mem-initializer-list.
 
    mem-initializer-list:
-     mem-initializer
-     mem-initializer , mem-initializer-list  */
+     mem-initializer ... [opt]
+     mem-initializer ... [opt] , mem-initializer-list  */
 
 static void
 cp_parser_mem_initializer_list (cp_parser* parser)
@@ -8188,6 +8241,26 @@ cp_parser_mem_initializer_list (cp_parse
 
       /* Parse the mem-initializer.  */
       mem_initializer = cp_parser_mem_initializer (parser);
+      /* If the next token is a `...', we're expanding member initializers. */
+      if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
+        {
+          /* Consume the `...'. */
+          cp_lexer_consume_token (parser->lexer);
+
+          /* The TREE_PURPOSE must be a _TYPE, because base-specifiers
+             can be expanded but members cannot. */
+          if (mem_initializer != error_mark_node
+              && !TYPE_P (TREE_PURPOSE (mem_initializer)))
+            {
+              error ("cannot expand initializer for member %<%D%>", 
+                     TREE_PURPOSE (mem_initializer));
+              mem_initializer = error_mark_node;
+            }
+
+          /* Construct the pack expansion type. */
+          if (mem_initializer != error_mark_node)
+            mem_initializer = make_pack_expansion (mem_initializer);
+        }
       /* Add it to the list, unless it was erroneous.  */
       if (mem_initializer != error_mark_node)
 	{
@@ -8243,6 +8316,7 @@ cp_parser_mem_initializer (cp_parser* pa
   expression_list
     = cp_parser_parenthesized_expression_list (parser, false,
 					       /*cast_p=*/false,
+                                               /*allow_expansion_p=*/true,
 					       /*non_constant_p=*/NULL);
   if (expression_list == error_mark_node)
     return error_mark_node;
@@ -8646,14 +8720,18 @@ cp_parser_template_parameter_list (cp_pa
       tree parameter;
       cp_token *token;
       bool is_non_type;
+      bool is_parameter_pack;
 
       /* Parse the template-parameter.  */
-      parameter = cp_parser_template_parameter (parser, &is_non_type);
+      parameter = cp_parser_template_parameter (parser, 
+                                                &is_non_type,
+                                                &is_parameter_pack);
       /* Add it to the list.  */
       if (parameter != error_mark_node)
 	parameter_list = process_template_parm (parameter_list,
 						parameter,
-						is_non_type);
+						is_non_type,
+                                                is_parameter_pack);
       else
        {
          tree err_parm = build_tree_list (parameter, parameter);
@@ -8682,10 +8760,12 @@ cp_parser_template_parameter_list (cp_pa
    If all goes well, returns a TREE_LIST.  The TREE_VALUE represents
    the parameter.  The TREE_PURPOSE is the default value, if any.
    Returns ERROR_MARK_NODE on failure.  *IS_NON_TYPE is set to true
-   iff this parameter is a non-type parameter.  */
+   iff this parameter is a non-type parameter.  *IS_PARAMETER_PACK is
+   set to true iff this parameter is a parameter pack. */
 
 static tree
-cp_parser_template_parameter (cp_parser* parser, bool *is_non_type)
+cp_parser_template_parameter (cp_parser* parser, bool *is_non_type,
+                              bool *is_parameter_pack)
 {
   cp_token *token;
   cp_parameter_declarator *parameter_declarator;
@@ -8693,11 +8773,13 @@ cp_parser_template_parameter (cp_parser*
 
   /* Assume it is a type parameter or a template parameter.  */
   *is_non_type = false;
+  /* Assume it not a parameter pack. */
+  *is_parameter_pack = false;
   /* Peek at the next token.  */
   token = cp_lexer_peek_token (parser->lexer);
   /* If it is `class' or `template', we have a type-parameter.  */
   if (token->keyword == RID_TEMPLATE)
-    return cp_parser_type_parameter (parser);
+    return cp_parser_type_parameter (parser, is_parameter_pack);
   /* If it is `class' or `typename' we do not know yet whether it is a
      type parameter or a non-type parameter.  Consider:
 
@@ -8715,6 +8797,10 @@ cp_parser_template_parameter (cp_parser*
     {
       /* Peek at the token after `class' or `typename'.  */
       token = cp_lexer_peek_nth_token (parser->lexer, 2);
+      /* If it's an ellipsis, we have a template type parameter
+         pack. */
+      if (token->type == CPP_ELLIPSIS)
+        return cp_parser_type_parameter (parser, is_parameter_pack);
       /* If it's an identifier, skip it.  */
       if (token->type == CPP_NAME)
 	token = cp_lexer_peek_nth_token (parser->lexer, 3);
@@ -8723,7 +8809,7 @@ cp_parser_template_parameter (cp_parser*
       if (token->type == CPP_COMMA
 	  || token->type == CPP_EQ
 	  || token->type == CPP_GREATER)
-	return cp_parser_type_parameter (parser);
+	return cp_parser_type_parameter (parser, is_parameter_pack);
     }
 
   /* Otherwise, it is a non-type parameter.
@@ -8738,12 +8824,40 @@ cp_parser_template_parameter (cp_parser*
   parameter_declarator
      = cp_parser_parameter_declaration (parser, /*template_parm_p=*/true,
 					/*parenthesized_p=*/NULL);
+
+  /* If the parameter declaration is marked as a parameter pack, set
+     *IS_PARAMETER_PACK to notify the caller. Also, unmark the
+     declarator's PACK_EXPANSION_P, otherwise we'll get errors from
+     grokdeclarator. */
+  if (parameter_declarator
+      && parameter_declarator->declarator
+      && parameter_declarator->declarator->parameter_pack_p)
+    {
+      *is_parameter_pack = true;
+      parameter_declarator->declarator->parameter_pack_p = false;
+    }
+
+  /* If the next token is an ellipsis, and we don't already have it
+     marked as a parameter pack, then we have a parameter pack (that
+     has no declarator); */
+  if (!*is_parameter_pack
+      && cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
+    {
+
+      /* Consume the `...'. */
+      cp_lexer_consume_token (parser->lexer);
+      maybe_warn_variadic_templates ();
+      
+      *is_parameter_pack = true;
+    }
+
   parm = grokdeclarator (parameter_declarator->declarator,
 			 &parameter_declarator->decl_specifiers,
 			 PARM, /*initialized=*/0,
 			 /*attrlist=*/NULL);
   if (parm == error_mark_node)
     return error_mark_node;
+
   return build_tree_list (parameter_declarator->default_argument, parm);
 }
 
@@ -8758,12 +8872,20 @@ cp_parser_template_parameter (cp_parser*
      template < template-parameter-list > class identifier [opt]
        = id-expression
 
+   GNU Extension (variadic templates):
+
+   type-parameter:
+     class ... identifier [opt]
+     typename ... identifier [opt]
+
    Returns a TREE_LIST.  The TREE_VALUE is itself a TREE_LIST.  The
    TREE_PURPOSE is the default-argument, if any.  The TREE_VALUE is
-   the declaration of the parameter.  */
+   the declaration of the parameter.
+
+   Sets *IS_PARAMETER_PACK if this is a template parameter pack. */
 
 static tree
-cp_parser_type_parameter (cp_parser* parser)
+cp_parser_type_parameter (cp_parser* parser, bool *is_parameter_pack)
 {
   cp_token *token;
   tree parameter;
@@ -8782,6 +8904,17 @@ cp_parser_type_parameter (cp_parser* par
 	tree identifier;
 	tree default_argument;
 
+        /* If the next token is an ellipsis, we have a template
+           argument pack. */
+        if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
+          {
+            /* Consume the `...' token. */
+            cp_lexer_consume_token (parser->lexer);
+            maybe_warn_variadic_templates ();
+
+            *is_parameter_pack = true;
+          }
+
 	/* If the next token is an identifier, then it names the
 	   parameter.  */
 	if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
@@ -8800,6 +8933,18 @@ cp_parser_type_parameter (cp_parser* par
 	    /* Parse the default-argument.  */
 	    push_deferring_access_checks (dk_no_deferred);
 	    default_argument = cp_parser_type_id (parser);
+
+            /* Template parameter packs cannot have default
+               arguments. */
+            if (*is_parameter_pack)
+              {
+                if (identifier)
+                  error ("template parameter pack %qD cannot have a default argument", 
+                         identifier);
+                else
+                  error ("template parameter packs cannot have default arguments");
+                default_argument = NULL_TREE;
+              }
 	    pop_deferring_access_checks ();
 	  }
 	else
@@ -8825,6 +8970,16 @@ cp_parser_type_parameter (cp_parser* par
 	cp_parser_require (parser, CPP_GREATER, "`>'");
 	/* Look for the `class' keyword.  */
 	cp_parser_require_keyword (parser, RID_CLASS, "`class'");
+        /* If the next token is an ellipsis, we have a template
+           argument pack. */
+        if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
+          {
+            /* Consume the `...' token. */
+            cp_lexer_consume_token (parser->lexer);
+            maybe_warn_variadic_templates ();
+
+            *is_parameter_pack = true;
+          }
 	/* If the next token is an `=', then there is a
 	   default-argument.  If the next token is a `>', we are at
 	   the end of the parameter-list.  If the next token is a `,',
@@ -8879,6 +9034,18 @@ cp_parser_type_parameter (cp_parser* par
 	    /* See if the default argument is valid.  */
 	    default_argument
 	      = check_template_template_default_arg (default_argument);
+
+            /* Template parameter packs cannot have default
+               arguments. */
+            if (*is_parameter_pack)
+              {
+                if (identifier)
+                  error ("template parameter pack %qD cannot have a default argument", 
+                         identifier);
+                else
+                  error ("template parameter packs cannot have default arguments");
+                default_argument = NULL_TREE;
+              }
 	    pop_deferring_access_checks ();
 	  }
 	else
@@ -9295,8 +9462,8 @@ cp_parser_template_name (cp_parser* pars
 /* Parse a template-argument-list.
 
    template-argument-list:
-     template-argument
-     template-argument-list , template-argument
+     template-argument ... [opt]
+     template-argument-list , template-argument ... [opt]
 
    Returns a TREE_VEC containing the arguments.  */
 
@@ -9332,6 +9499,19 @@ cp_parser_template_argument_list (cp_par
 
       /* Parse the template-argument.  */
       argument = cp_parser_template_argument (parser);
+
+      /* If the next token is an ellipsis, we're expanding a template
+         argument pack. */
+      if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
+        {
+          /* Consume the `...' token. */
+          cp_lexer_consume_token (parser->lexer);
+
+          /* Make the argument into a TYPE_PACK_EXPANSION or
+             EXPR_PACK_EXPANSION. */
+          argument = make_pack_expansion (argument);
+        }
+
       if (n_args == alloced)
 	{
 	  alloced *= 2;
@@ -11857,17 +12037,47 @@ cp_parser_direct_declarator (cp_parser* 
 	  tree unqualified_name;
 	  special_function_kind sfk;
 	  bool abstract_ok;
+          bool pack_expansion_p = false;
 
 	  /* Parse a declarator-id */
 	  abstract_ok = (dcl_kind == CP_PARSER_DECLARATOR_EITHER);
 	  if (abstract_ok)
-	    cp_parser_parse_tentatively (parser);
+            {
+              cp_parser_parse_tentatively (parser);
+
+              /* If we see an ellipsis, we should be looking at a
+                 parameter pack. */
+              if (token->type == CPP_ELLIPSIS)
+                {
+                  /* Consume the `...' */
+                  cp_lexer_consume_token (parser->lexer);
+
+                  pack_expansion_p = true;
+                }
+            }
+
 	  unqualified_name
 	    = cp_parser_declarator_id (parser, /*optional_p=*/abstract_ok);
 	  qualifying_scope = parser->scope;
 	  if (abstract_ok)
 	    {
-	      if (!cp_parser_parse_definitely (parser))
+              bool okay = false;
+
+              if (!unqualified_name && pack_expansion_p)
+                {
+                  /* Check whether an error occurred. */
+                  okay = !cp_parser_error_occurred (parser);
+
+                  /* We already consumed the ellipsis to mark a
+                     parameter pack, but we have no way to report it,
+                     so abort the tentative parse. We will be exiting
+                     immediately anyway. */
+                  cp_parser_abort_tentative_parse (parser);
+                }
+              else
+                okay = cp_parser_parse_definitely (parser);
+
+	      if (!okay)
 		unqualified_name = error_mark_node;
 	      else if (unqualified_name
 		       && (qualifying_scope
@@ -11884,6 +12094,8 @@ cp_parser_direct_declarator (cp_parser* 
 	  if (unqualified_name == error_mark_node)
 	    {
 	      declarator = cp_error_declarator;
+              pack_expansion_p = false;
+              declarator->parameter_pack_p = false;
 	      break;
 	    }
 
@@ -11920,6 +12132,7 @@ cp_parser_direct_declarator (cp_parser* 
 	    }
 
 	  sfk = sfk_none;
+
 	  if (unqualified_name)
 	    {
 	      tree class_type;
@@ -11987,6 +12200,10 @@ cp_parser_direct_declarator (cp_parser* 
 					   unqualified_name,
 					   sfk);
 	  declarator->id_loc = token->location;
+          declarator->parameter_pack_p = pack_expansion_p;
+
+          if (pack_expansion_p)
+            maybe_warn_variadic_templates ();
 
 	handle_declarator:;
 	  scope = get_scope_of_declarator (declarator);
@@ -12548,9 +12765,9 @@ cp_parser_parameter_declaration_list (cp
 /* Parse a parameter declaration.
 
    parameter-declaration:
-     decl-specifier-seq declarator
+     decl-specifier-seq ... [opt] declarator
      decl-specifier-seq declarator = assignment-expression
-     decl-specifier-seq abstract-declarator [opt]
+     decl-specifier-seq ... [opt] abstract-declarator [opt]
      decl-specifier-seq abstract-declarator [opt] = assignment-expression
 
    If TEMPLATE_PARM_P is TRUE, then this parameter-declaration
@@ -12605,12 +12822,13 @@ cp_parser_parameter_declaration (cp_pars
 
   /* Peek at the next token.  */
   token = cp_lexer_peek_token (parser->lexer);
+
   /* If the next token is a `)', `,', `=', `>', or `...', then there
-     is no declarator.  */
+     is no declarator. However, when variadic templates are enabled,
+     there may be a declarator following `...'.  */
   if (token->type == CPP_CLOSE_PAREN
       || token->type == CPP_COMMA
       || token->type == CPP_EQ
-      || token->type == CPP_ELLIPSIS
       || token->type == CPP_GREATER)
     {
       declarator = NULL;
@@ -12652,6 +12870,34 @@ cp_parser_parameter_declaration (cp_pars
 		   cp_parser_attributes_opt (parser));
     }
 
+  /* If the next token is an ellipsis, and the type of the declarator
+     contains parameter packs but it is not a TYPE_PACK_EXPANSION, then
+     we actually have a parameter pack expansion expression. Otherwise,
+     leave the ellipsis for a C-style variadic function. */
+  token = cp_lexer_peek_token (parser->lexer);
+  if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
+    {
+      tree type = decl_specifiers.type;
+
+      if (DECL_P (type))
+        type = TREE_TYPE (type);
+
+      if (TREE_CODE (type) != TYPE_PACK_EXPANSION
+          && (!declarator || !declarator->parameter_pack_p)
+          && uses_parameter_packs (type))
+        {
+          /* Consume the `...'. */
+          cp_lexer_consume_token (parser->lexer);
+          maybe_warn_variadic_templates ();
+          
+          /* Build a pack expansion type */
+          if (declarator)
+            declarator->parameter_pack_p = true;
+          else
+            decl_specifiers.type = make_pack_expansion (type);
+        }
+    }
+
   /* The restriction on defining new types applies only to the type
      of the parameter, not to the default argument.  */
   parser->type_definition_forbidden_message = saved_message;
@@ -12883,6 +13129,7 @@ cp_parser_initializer (cp_parser* parser
   else if (token->type == CPP_OPEN_PAREN)
     init = cp_parser_parenthesized_expression_list (parser, false,
 						    /*cast_p=*/false,
+                                                    /*allow_expansion_p=*/true,
 						    non_constant_p);
   else
     {
@@ -12958,8 +13205,8 @@ crser_initializer_clause (cp_parser*
 /* Parse an initializer-list.
 
    initializer-list:
-     initializer-clause
-     initializer-list , initializer-clause
+     initializer-clause ... [opt]
+     initializer-list , initializer-clause ... [opt]
 
    GNU Extension:
 
@@ -13013,6 +13260,17 @@ cp_parser_initializer_list (cp_parser* p
       if (clause_non_constant_p)
 	*non_constant_p = true;
 
+      /* If we have an ellipsis, this is an initializer pack
+	 expansion.  */
+      if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
+        {
+          /* Consume the `...'.  */
+          cp_lexer_consume_token (parser->lexer);
+
+          /* Turn the initializer into an initializer expansion.  */
+          initializer = make_pack_expansion (initializer);
+        }
+
       /* Add it to the vector.  */
       CONSTRUCTOR_APPEND_ELT(v, identifier, initializer);
 
@@ -14314,8 +14572,8 @@ cp_parser_constant_initializer (cp_parse
      : base-specifier-list
 
    base-specifier-list:
-     base-specifier
-     base-specifier-list , base-specifier
+     base-specifier ... [opt]
+     base-specifier-list , base-specifier ... [opt]
 
    Returns a TREE_LIST representing the base-classes, in the order in
    which they were declared.  The representation of each node is as
@@ -14337,12 +14595,28 @@ cp_parser_base_clause (cp_parser* parser
     {
       cp_token *token;
       tree base;
+      bool pack_expansion_p = false;
 
           /* Look for the base-specifier.  */
       base = cp_parser_base_specifier (parser);
+      /* Look for the (optional) ellipsis. */
+      if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
+        {
+          /* Consume the `...'. */
+          cp_lexer_consume_token (parser->lexer);
+
+          pack_expansion_p = true;
+        }
+
       /* Add BASE to the front of the list.  */
       if (base != error_mark_node)
 	{
+          if (pack_expansion_p)
+            /* Make this a pack expansion type. */
+            TREE_VALUE (base) = make_pack_expansion (TREE_VALUE (base));
+          else
+            check_for_bare_parameter_packs (TREE_VALUE (base));
+
 	  TREE_CHAIN (base) = bases;
 	  bases = base;
 	}
@@ -14548,8 +14822,8 @@ cp_parser_exception_specification_opt (c
 /* Parse an (optional) type-id-list.
 
    type-id-list:
-     type-id
-     type-id-list , type-id
+     type-id ... [opt]
+     type-id-list , type-id ... [opt]
 
    Returns a TREE_LIST.  The TREE_VALUE of each node is a TYPE,
    in the order that the types were presented.  */
@@ -14566,6 +14840,15 @@ cp_parser_type_id_list (cp_parser* parse
 
       /* Get the next type-id.  */
       type = cp_parser_type_id (parser);
+      /* Parse the optional ellipsis. */
+      if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
+        {
+          /* Consume the `...'. */
+          cp_lexer_consume_token (parser->lexer);
+
+          /* Turn the type into a pack expansion expression. */
+          type = make_pack_expansion (type);
+        }
       /* Add it to the list.  */
       types = add_exception_specifier (types, type, /*complain=*/1);
       /* Peek at the next token.  */
@@ -14999,6 +15282,7 @@ cp_parser_attribute_list (cp_parser* par
 	    {
 	      arguments = cp_parser_parenthesized_expression_list
 			  (parser, true, /*cast_p=*/false,
+                           /*allow_expansion_p=*/false,
 			   /*non_constant_p=*/NULL);
 	      /* Save the arguments away.  */
 	      TREE_VALUE (attribute) = arguments;
@@ -16081,6 +16365,7 @@ cp_parser_functional_cast (cp_parser* pa
   expression_list
     = cp_parser_parenthesized_expression_list (parser, false,
 					       /*cast_p=*/true,
+                                               /*allow_expansion_p=*/true,
 					       /*non_constant_p=*/NULL);
 
   cast = build_functional_cast (type, expression_list);
@@ -16430,6 +16715,7 @@ cp_parser_sizeof_operand (cp_parser* par
   const char *saved_message;
   bool saved_integral_constant_expression_p;
   bool saved_non_integral_constant_expression_p;
+  bool pack_expansion_p = false;
 
   /* Initialize FORMAT the first time we get here.  */
   if (!format)
@@ -16454,6 +16740,19 @@ cp_parser_sizeof_operand (cp_parser* par
     = parser->non_integral_constant_expression_p;
   parser->integral_constant_expression_p = false;
 
+  /* If it's a `...', then we are computing the length of a parameter
+     pack.  */
+  if (keyword == RID_SIZEOF
+      && cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
+    {
+      /* Consume the `...'.  */
+      cp_lexer_consume_token (parser->lexer);
+      maybe_warn_variadic_templates ();
+
+      /* Note that this is an expansion.  */
+      pack_expansion_p = true;
+    }
+
   /* Do not actually evaluate the expression.  */
   ++skip_evaluation;
   /* If it's a `(', then we might be looking at the type-id
@@ -16498,6 +16797,11 @@ cp_parser_sizeof_operand (cp_parser* par
   if (!expr)
     expr = cp_parser_unary_expression (parser, /*address_p=*/false,
 				       /*cast_p=*/false);
+
+  if (pack_expansion_p)
+    /* Build a pack expansion. */
+    expr = make_pack_expansion (expr);
+
   /* Go back to evaluating expressions.  */
   --skip_evaluation;
 
@@ -16790,7 +17094,9 @@ cp_parser_next_token_ends_template_argum
   cp_token *token;
 
   token = cp_lexer_peek_token (parser->lexer);
-  return (token->type == CPP_COMMA || token->type == CPP_GREATER);
+  return (token->type == CPP_COMMA 
+          || token->type == CPP_GREATER
+          || token->type == CPP_ELLIPSIS);
 }
 
 /* Returns TRUE iff the n-th token is a "<", or the n-th is a "[" and the

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]