Patchwork C++ PATCH for c++/41933 (variadic lambda capture)

login
register
mail settings
Submitter Jason Merrill
Date Sept. 15, 2013, 7:38 p.m.
Message ID <52360CA1.9040808@redhat.com>
Download mbox | patch
Permalink /patch/275070/
State New
Headers show

Comments

Jason Merrill - Sept. 15, 2013, 7:38 p.m.
This patch fixes one of the few remaining holes in GCC's C++11 support: 
lambda capture of a variadic function parameter pack.  The 
implementation involves introducing the internal notion of a FIELD_DECL 
pack, even though such a thing can not be written explicitly in C++11.

Tested x86_64-pc-linux-gnu, applying to trunk.

Patch

commit 85cb3c43f2b8aa7897b499e125a5d77e7a8a5a3c
Author: Jason Merrill <jason@redhat.com>
Date:   Sun Sep 15 08:56:42 2013 -0700

    	Core DR 904
    	PR c++/41933
    	* parser.c (cp_parser_lambda_introducer): Handle variadic capture.
    	* lambda.c (add_capture): Handle variadic capture.
    	(add_default_capture, lambda_capture_field_type): Likewise.
    	(build_capture_proxy, register_capture_members): Likewise.
    	* pt.c (register_specialization): Allow FIELD_DECL.
    	(retrieve_specialization): Likewise.
    	(find_parameter_packs_r): Handle FIELD_DECL and VAR_DECL.
    	(tsubst_pack_expansion): Handle FIELD_DECL packs.
    	(gen_elem_of_pack_expansion_instantiation): Likewise.
    	(instantiate_class_template_1): Likewise.
    	(tsubst_decl, tsubst_copy): Likewise.
    	(tsubst_expr) [DECL_EXPR]: Handle capture proxy packs.
    	(tsubst_copy_and_build) [VAR_DECL]: Likewise.
    	* semantics.c (finish_non_static_data_member): Don't try to represent
    	the type of a COMPOUND_REF of a FIELD_DECL pack.

diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c
index bf75834..1af301d 100644
--- a/gcc/cp/lambda.c
+++ b/gcc/cp/lambda.c
@@ -215,7 +215,8 @@  lambda_capture_field_type (tree expr, bool explicit_init_p)
     }
   else
     type = non_reference (unlowered_expr_type (expr));
-  if (!type || WILDCARD_TYPE_P (type) || type_uses_auto (type))
+  if (!type || WILDCARD_TYPE_P (type) || type_uses_auto (type)
+      || DECL_PACK_P (expr))
     {
       type = cxx_make_type (DECLTYPE_TYPE);
       DECLTYPE_TYPE_EXPR (type) = expr;
@@ -320,15 +321,21 @@  tree
 lambda_proxy_type (tree ref)
 {
   tree type;
+  if (ref == error_mark_node)
+    return error_mark_node;
   if (REFERENCE_REF_P (ref))
     ref = TREE_OPERAND (ref, 0);
+  gcc_assert (TREE_CODE (ref) == COMPONENT_REF);
   type = TREE_TYPE (ref);
-  if (type && !WILDCARD_TYPE_P (non_reference (type)))
-    return type;
-  type = cxx_make_type (DECLTYPE_TYPE);
-  DECLTYPE_TYPE_EXPR (type) = ref;
-  DECLTYPE_FOR_LAMBDA_PROXY (type) = true;
-  SET_TYPE_STRUCTURAL_EQUALITY (type);
+  if (!type || WILDCARD_TYPE_P (non_reference (type)))
+    {
+      type = cxx_make_type (DECLTYPE_TYPE);
+      DECLTYPE_TYPE_EXPR (type) = ref;
+      DECLTYPE_FOR_LAMBDA_PROXY (type) = true;
+      SET_TYPE_STRUCTURAL_EQUALITY (type);
+    }
+  if (DECL_PACK_P (TREE_OPERAND (ref, 1)))
+    type = make_pack_expansion (type);
   return type;
 }
 
@@ -341,6 +348,9 @@  build_capture_proxy (tree member)
 {
   tree var, object, fn, closure, name, lam, type;
 
+  if (PACK_EXPANSION_P (member))
+    member = PACK_EXPANSION_PATTERN (member);
+
   closure = DECL_CONTEXT (member);
   fn = lambda_function (closure);
   lam = CLASSTYPE_LAMBDA_EXPR (closure);
@@ -422,12 +432,20 @@  vla_capture_type (tree array_type)
    and return it.  */
 
 tree
-add_capture (tree lambda, tree id, tree initializer, bool by_reference_p,
+add_capture (tree lambda, tree id, tree orig_init, bool by_reference_p,
 	     bool explicit_init_p)
 {
   char *buf;
   tree type, member, name;
   bool vla = false;
+  bool variadic = false;
+  tree initializer = orig_init;
+
+  if (PACK_EXPANSION_P (initializer))
+    {
+      initializer = PACK_EXPANSION_PATTERN (initializer);
+      variadic = true;
+    }
 
   if (TREE_CODE (initializer) == TREE_LIST)
     initializer = build_x_compound_expr_from_list (initializer, ELK_INIT,
@@ -498,6 +516,9 @@  add_capture (tree lambda, tree id, tree initializer, bool by_reference_p,
       IDENTIFIER_MARKED (name) = true;
     }
 
+  if (variadic)
+    type = make_pack_expansion (type);
+
   /* Make member variable.  */
   member = build_decl (input_location, FIELD_DECL, name, type);
   DECL_VLA_CAPTURE_P (member) = vla;
@@ -518,8 +539,14 @@  add_capture (tree lambda, tree id, tree initializer, bool by_reference_p,
       && current_class_type == LAMBDA_EXPR_CLOSURE (lambda))
     finish_member_declaration (member);
 
+  tree listmem = member;
+  if (variadic)
+    {
+      listmem = make_pack_expansion (member);
+      initializer = orig_init;
+    }
   LAMBDA_EXPR_CAPTURE_LIST (lambda)
-    = tree_cons (member, initializer, LAMBDA_EXPR_CAPTURE_LIST (lambda));
+    = tree_cons (listmem, initializer, LAMBDA_EXPR_CAPTURE_LIST (lambda));
 
   if (LAMBDA_EXPR_CLOSURE (lambda))
     return build_capture_proxy (member);
@@ -538,9 +565,14 @@  register_capture_members (tree captures)
     return;
 
   register_capture_members (TREE_CHAIN (captures));
+
+  tree field = TREE_PURPOSE (captures);
+  if (PACK_EXPANSION_P (field))
+    field = PACK_EXPANSION_PATTERN (field);
+
   /* We set this in add_capture to avoid duplicates.  */
-  IDENTIFIER_MARKED (DECL_NAME (TREE_PURPOSE (captures))) = false;
-  finish_member_declaration (TREE_PURPOSE (captures));
+  IDENTIFIER_MARKED (DECL_NAME (field)) = false;
+  finish_member_declaration (field);
 }
 
 /* Similar to add_capture, except this works on a stack of nested lambdas.
@@ -565,6 +597,8 @@  add_default_capture (tree lambda_stack, tree id, tree initializer)
       tree lambda = TREE_VALUE (node);
 
       current_class_type = LAMBDA_EXPR_CLOSURE (lambda);
+      if (DECL_PACK_P (initializer))
+	initializer = make_pack_expansion (initializer);
       var = add_capture (lambda,
                             id,
                             initializer,
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index e00e56c..2b0695a 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -8753,6 +8753,14 @@  cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr)
                  /*template_arg_p=*/false,
                  &error_msg,
                  capture_token->location);
+
+	  if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
+	    {
+	      cp_lexer_consume_token (parser->lexer);
+	      capture_init_expr = make_pack_expansion (capture_init_expr);
+	    }
+	  else
+	    check_for_bare_parameter_packs (capture_init_expr);
 	}
 
       if (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda_expr) != CPLD_NONE
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index ecae904..2ef160a 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -1004,7 +1004,10 @@  optimize_specialization_lookup_p (tree tmpl)
 
    If TMPL is a type template and CLASS_SPECIALIZATIONS_P is true,
    then we search for a partial specialization matching ARGS.  This
-   parameter is ignored if TMPL is not a class template.  */
+   parameter is ignored if TMPL is not a class template.
+
+   We can also look up a FIELD_DECL, if it is a lambda capture pack; the
+   result is a NONTYPE_ARGUMENT_PACK.  */
 
 static tree
 retrieve_specialization (tree tmpl, tree args, hashval_t hash)
@@ -1015,12 +1018,15 @@  retrieve_specialization (tree tmpl, tree args, hashval_t hash)
   if (args == error_mark_node)
     return NULL_TREE;
 
-  gcc_assert (TREE_CODE (tmpl) == TEMPLATE_DECL);
+  gcc_assert (TREE_CODE (tmpl) == TEMPLATE_DECL
+	      || TREE_CODE (tmpl) == FIELD_DECL);
 
   /* There should be as many levels of arguments as there are
      levels of parameters.  */
   gcc_assert (TMPL_ARGS_DEPTH (args)
-	      == TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (tmpl)));
+	      == (TREE_CODE (tmpl) == TEMPLATE_DECL
+		  ? TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (tmpl))
+		  : template_class_depth (DECL_CONTEXT (tmpl))));
 
   if (optimize_specialization_lookup_p (tmpl))
     {
@@ -1311,7 +1317,10 @@  is_specialization_of_friend (tree decl, tree friend_decl)
 /* Register the specialization SPEC as a specialization of TMPL with
    the indicated ARGS.  IS_FRIEND indicates whether the specialization
    is actually just a friend declaration.  Returns SPEC, or an
-   equivalent prior declaration, if available.  */
+   equivalent prior declaration, if available.
+
+   We also store instantiations of field packs in the hash table, even
+   though they are not themselves templates, to make lookup easier.  */
 
 static tree
 register_specialization (tree spec, tree tmpl, tree args, bool is_friend,
@@ -1321,7 +1330,9 @@  register_specialization (tree spec, tree tmpl, tree args, bool is_friend,
   void **slot = NULL;
   spec_entry elt;
 
-  gcc_assert (TREE_CODE (tmpl) == TEMPLATE_DECL && DECL_P (spec));
+  gcc_assert ((TREE_CODE (tmpl) == TEMPLATE_DECL && DECL_P (spec))
+	      || (TREE_CODE (tmpl) == FIELD_DECL
+		  && TREE_CODE (spec) == NONTYPE_ARGUMENT_PACK));
 
   if (TREE_CODE (spec) == FUNCTION_DECL
       && uses_template_parms (DECL_TI_ARGS (spec)))
@@ -1443,7 +1454,7 @@  register_specialization (tree spec, tree tmpl, tree args, bool is_friend,
 
   /* A specialization must be declared in the same namespace as the
      template it is specializing.  */
-  if (DECL_TEMPLATE_SPECIALIZATION (spec)
+  if (DECL_P (spec) && DECL_TEMPLATE_SPECIALIZATION (spec)
       && !check_specialization_namespace (tmpl))
     DECL_CONTEXT (spec) = DECL_CONTEXT (tmpl);
 
@@ -3084,6 +3095,7 @@  find_parameter_packs_r (tree *tp, int *walk_subtrees, void* data)
         parameter_pack_p = true;
       break;
 
+    case FIELD_DECL:
     case PARM_DECL:
       if (DECL_PACK_P (t))
         {
@@ -3094,6 +3106,18 @@  find_parameter_packs_r (tree *tp, int *walk_subtrees, void* data)
         }
       break;
 
+      /* Look through a lambda capture proxy to the field pack.  */
+    case VAR_DECL:
+      if (DECL_HAS_VALUE_EXPR_P (t))
+	{
+	  tree v = DECL_VALUE_EXPR (t);
+	  cp_walk_tree (&v,
+			&find_parameter_packs_r,
+			ppd, ppd->visited);
+	  *walk_subtrees = 0;
+	}
+      break;
+
     case BASES:
       parameter_pack_p = true;
       break;
@@ -8913,6 +8937,8 @@  instantiate_class_template_1 (tree type)
 	      else if (TREE_CODE (t) != CONST_DECL)
 		{
 		  tree r;
+		  tree vec = NULL_TREE;
+		  int len = 1;
 
 		  /* The file and line for this declaration, to
 		     assist in error message reporting.  Since we
@@ -8925,55 +8951,68 @@  instantiate_class_template_1 (tree type)
 		  r = tsubst (t, args, tf_warning_or_error, NULL_TREE);
 		  if (TREE_CODE (t) == TEMPLATE_DECL)
 		    --processing_template_decl;
-		  if (VAR_P (r))
+
+		  if (TREE_CODE (r) == TREE_VEC)
 		    {
-		      /* In [temp.inst]:
-
-			   [t]he initialization (and any associated
-			   side-effects) of a static data member does
-			   not occur unless the static data member is
-			   itself used in a way that requires the
-			   definition of the static data member to
-			   exist.
-
-			 Therefore, we do not substitute into the
-			 initialized for the static data member here.  */
-		      finish_static_data_member_decl
-			(r,
-			 /*init=*/NULL_TREE,
-			 /*init_const_expr_p=*/false,
-			 /*asmspec_tree=*/NULL_TREE,
-			 /*flags=*/0);
-		      /* Instantiate members marked with attribute used.  */
-		      if (r != error_mark_node && DECL_PRESERVE_P (r))
-			mark_used (r);
+		      /* A capture pack became multiple fields.  */
+		      vec = r;
+		      len = TREE_VEC_LENGTH (vec);
 		    }
-		  else if (TREE_CODE (r) == FIELD_DECL)
+
+		  for (int i = 0; i < len; ++i)
 		    {
-		      /* Determine whether R has a valid type and can be
-			 completed later.  If R is invalid, then its type is
-			 replaced by error_mark_node.  */
-		      tree rtype = TREE_TYPE (r);
-		      if (can_complete_type_without_circularity (rtype))
-			complete_type (rtype);
-
-		      if (!COMPLETE_TYPE_P (rtype))
+		      if (vec)
+			r = TREE_VEC_ELT (vec, i);
+		      if (VAR_P (r))
 			{
-			  cxx_incomplete_type_error (r, rtype);
-			  TREE_TYPE (r) = error_mark_node;
+			  /* In [temp.inst]:
+
+			     [t]he initialization (and any associated
+			     side-effects) of a static data member does
+			     not occur unless the static data member is
+			     itself used in a way that requires the
+			     definition of the static data member to
+			     exist.
+
+			     Therefore, we do not substitute into the
+			     initialized for the static data member here.  */
+			  finish_static_data_member_decl
+			    (r,
+			     /*init=*/NULL_TREE,
+			     /*init_const_expr_p=*/false,
+			     /*asmspec_tree=*/NULL_TREE,
+			     /*flags=*/0);
+			  /* Instantiate members marked with attribute used. */
+			  if (r != error_mark_node && DECL_PRESERVE_P (r))
+			    mark_used (r);
+			}
+		      else if (TREE_CODE (r) == FIELD_DECL)
+			{
+			  /* Determine whether R has a valid type and can be
+			     completed later.  If R is invalid, then its type
+			     is replaced by error_mark_node.  */
+			  tree rtype = TREE_TYPE (r);
+			  if (can_complete_type_without_circularity (rtype))
+			    complete_type (rtype);
+
+			  if (!COMPLETE_TYPE_P (rtype))
+			    {
+			      cxx_incomplete_type_error (r, rtype);
+			      TREE_TYPE (r) = error_mark_node;
+			    }
 			}
-		    }
 
-		  /* If it is a TYPE_DECL for a class-scoped ENUMERAL_TYPE,
-		     such a thing will already have been added to the field
-		     list by tsubst_enum in finish_member_declaration in the
-		     CLASSTYPE_NESTED_UTDS case above.  */
-		  if (!(TREE_CODE (r) == TYPE_DECL
-			&& TREE_CODE (TREE_TYPE (r)) == ENUMERAL_TYPE
-			&& DECL_ARTIFICIAL (r)))
-		    {
-		      set_current_access_from_decl (r);
-		      finish_member_declaration (r);
+		      /* If it is a TYPE_DECL for a class-scoped ENUMERAL_TYPE,
+			 such a thing will already have been added to the field
+			 list by tsubst_enum in finish_member_declaration in the
+			 CLASSTYPE_NESTED_UTDS case above.  */
+		      if (!(TREE_CODE (r) == TYPE_DECL
+			    && TREE_CODE (TREE_TYPE (r)) == ENUMERAL_TYPE
+			    && DECL_ARTIFICIAL (r)))
+			{
+			  set_current_access_from_decl (r);
+			  finish_member_declaration (r);
+			}
 		    }
 		}
 	    }
@@ -9367,7 +9406,8 @@  gen_elem_of_pack_expansion_instantiation (tree pattern,
 	argument_pack_element_is_expansion_p (arg_pack, index);
 
       /* Select the Ith argument from the pack.  */
-      if (TREE_CODE (parm) == PARM_DECL)
+      if (TREE_CODE (parm) == PARM_DECL
+	  || TREE_CODE (parm) == FIELD_DECL)
 	{
 	  if (index == 0)
 	    {
@@ -9481,6 +9521,8 @@  tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
 	      need_local_specializations = true;
 	    }
 	}
+      else if (TREE_CODE (parm_pack) == FIELD_DECL)
+	arg_pack = tsubst_copy (parm_pack, args, complain, in_decl);
       else
         {
 	  int idx;
@@ -9605,7 +9647,8 @@  tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
     {
       tree parm = TREE_PURPOSE (pack);
 
-      if (TREE_CODE (parm) == PARM_DECL)
+      if (TREE_CODE (parm) == PARM_DECL
+	  || TREE_CODE (parm) == FIELD_DECL)
         register_local_specialization (TREE_TYPE (pack), parm);
       else
         {
@@ -10572,39 +10615,88 @@  tsubst_decl (tree t, tree args, tsubst_flags_t complain)
 
     case FIELD_DECL:
       {
-	tree type;
+	tree type = NULL_TREE;
+	tree vec = NULL_TREE;
+	tree expanded_types = NULL_TREE;
+	int len = 1;
 
-	r = copy_decl (t);
-	type = tsubst (TREE_TYPE (t), args, complain, in_decl);
-	if (type == error_mark_node)
-	  RETURN (error_mark_node);
-	TREE_TYPE (r) = type;
-	cp_apply_type_quals_to_decl (cp_type_quals (type), r);
+	if (PACK_EXPANSION_P (TREE_TYPE (t)))
+	  {
+	    /* This field is a lambda capture pack.  Return a TREE_VEC of
+	       the expanded fields to instantiate_class_template_1 and
+	       store them in the specializations hash table as a
+	       NONTYPE_ARGUMENT_PACK so that tsubst_copy can find them.  */
+            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);
+		vec = make_tree_vec (len);
+              }
+            else
+              {
+                /* All we did was update the type. Make a note of that.  */
+                type = expanded_types;
+                expanded_types = NULL_TREE;
+              }
+	  }
 
-	if (DECL_C_BIT_FIELD (r))
-	  /* For bit-fields, DECL_INITIAL gives the number of bits.  For
-	     non-bit-fields DECL_INITIAL is a non-static data member
-	     initializer, which gets deferred instantiation.  */
-	  DECL_INITIAL (r)
-	    = tsubst_expr (DECL_INITIAL (t), args,
-			   complain, in_decl,
-			   /*integral_constant_expression_p=*/true);
-	else if (DECL_INITIAL (t))
+	for (int i = 0; i < len; ++i)
 	  {
-	    /* Set up DECL_TEMPLATE_INFO so that we can get at the
-	       NSDMI in perform_member_init.  Still set DECL_INITIAL
-	       so that we know there is one.  */
-	    DECL_INITIAL (r) = void_zero_node;
-	    gcc_assert (DECL_LANG_SPECIFIC (r) == NULL);
-	    retrofit_lang_decl (r);
-	    DECL_TEMPLATE_INFO (r) = build_template_info (t, args);
+	    r = copy_decl (t);
+	    if (expanded_types)
+	      {
+		type = TREE_VEC_ELT (expanded_types, i);
+		DECL_NAME (r)
+		  = make_ith_pack_parameter_name (DECL_NAME (r), i);
+	      }
+            else if (!type)
+              type = tsubst (TREE_TYPE (t), args, complain, in_decl);
+
+	    if (type == error_mark_node)
+	      RETURN (error_mark_node);
+	    TREE_TYPE (r) = type;
+	    cp_apply_type_quals_to_decl (cp_type_quals (type), r);
+
+	    if (DECL_C_BIT_FIELD (r))
+	      /* For bit-fields, DECL_INITIAL gives the number of bits.  For
+		 non-bit-fields DECL_INITIAL is a non-static data member
+		 initializer, which gets deferred instantiation.  */
+	      DECL_INITIAL (r)
+		= tsubst_expr (DECL_INITIAL (t), args,
+			       complain, in_decl,
+			       /*integral_constant_expression_p=*/true);
+	    else if (DECL_INITIAL (t))
+	      {
+		/* Set up DECL_TEMPLATE_INFO so that we can get at the
+		   NSDMI in perform_member_init.  Still set DECL_INITIAL
+		   so that we know there is one.  */
+		DECL_INITIAL (r) = void_zero_node;
+		gcc_assert (DECL_LANG_SPECIFIC (r) == NULL);
+		retrofit_lang_decl (r);
+		DECL_TEMPLATE_INFO (r) = build_template_info (t, args);
+	      }
+	    /* We don't have to set DECL_CONTEXT here; it is set by
+	       finish_member_declaration.  */
+	    DECL_CHAIN (r) = NULL_TREE;
+
+	    apply_late_template_attributes (&r, DECL_ATTRIBUTES (r), 0,
+					    args, complain, in_decl);
+
+	    if (vec)
+	      TREE_VEC_ELT (vec, i) = r;
 	  }
-	/* We don't have to set DECL_CONTEXT here; it is set by
-	   finish_member_declaration.  */
-	DECL_CHAIN (r) = NULL_TREE;
 
-	apply_late_template_attributes (&r, DECL_ATTRIBUTES (r), 0,
-					args, complain, in_decl);
+	if (vec)
+	  {
+	    r = vec;
+	    tree pack = make_node (NONTYPE_ARGUMENT_PACK);
+	    tree tpack = cxx_make_type (TYPE_ARGUMENT_PACK);
+	    SET_ARGUMENT_PACK_ARGS (pack, vec);
+	    SET_ARGUMENT_PACK_ARGS (tpack, expanded_types);
+	    TREE_TYPE (pack) = tpack;
+	    register_specialization (pack, t, args, false, 0);
+	  }
       }
       break;
 
@@ -10753,14 +10845,14 @@  tsubst_decl (tree t, tree args, tsubst_flags_t complain)
 	      {
 		/* It may seem that this case cannot occur, since:
 
-		     typedef void f();
-		     void g() { f x; }
+		   typedef void f();
+		   void g() { f x; }
 
 		   declares a function, not a variable.  However:
       
-		     typedef void f();
-		     template <typename T> void g() { T t; }
-		     template void g<f>();
+		   typedef void f();
+		   template <typename T> void g() { T t; }
+		   template void g<f>();
 
 		   is an attempt to declare a variable with function
 		   type.  */
@@ -12261,6 +12353,23 @@  tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
       return t;
 
     case FIELD_DECL:
+      if (PACK_EXPANSION_P (TREE_TYPE (t)))
+	{
+	  /* Check for a local specialization set up by
+	     tsubst_pack_expansion.  */
+	  tree r = retrieve_local_specialization (t);
+	  if (r)
+	    {
+	      if (TREE_CODE (r) == ARGUMENT_PACK_SELECT)
+		r = ARGUMENT_PACK_SELECT_ARG (r);
+	      return r;
+	    }
+
+	  /* Otherwise return the full NONTYPE_ARGUMENT_PACK that
+	     tsubst_decl put in the hash table.  */
+	  return retrieve_specialization (t, args, 0);
+	}
+
       if (DECL_CONTEXT (t))
 	{
 	  tree ctx;
@@ -13020,6 +13129,12 @@  tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
 	    else
 	      do_local_using_decl (decl, scope, name);
 	  }
+	else if (DECL_PACK_P (decl))
+	  {
+	    /* Don't build up decls for a variadic capture proxy, we'll
+	       instantiate the elements directly as needed.  */
+	    break;
+	  }
 	else
 	  {
 	    init = DECL_INITIAL (decl);
@@ -14585,6 +14700,14 @@  tsubst_copy_and_build (tree t,
     case VAR_DECL:
       if (!args)
 	RETURN (t);
+      else if (DECL_PACK_P (t))
+	{
+	  /* We don't build decls for an instantiation of a
+	     variadic capture proxy, we instantiate the elements
+	     when needed.  */
+	  gcc_assert (DECL_HAS_VALUE_EXPR_P (t));
+	  return RECUR (DECL_VALUE_EXPR (t));
+	}
       /* Fall through */
 
     case PARM_DECL:
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 6d7f55f..0299b69 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -1604,6 +1604,9 @@  finish_non_static_data_member (tree decl, tree object, tree qualifying_scope)
 
       if (TREE_CODE (type) == REFERENCE_TYPE)
 	/* Quals on the object don't matter.  */;
+      else if (PACK_EXPANSION_P (type))
+	/* Don't bother trying to represent this.  */
+	type = NULL_TREE;
       else
 	{
 	  /* Set the cv qualifiers.  */
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-variadic2.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-variadic2.C
new file mode 100644
index 0000000..fab1f6c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-variadic2.C
@@ -0,0 +1,57 @@ 
+// { dg-do run { target c++11 } }
+
+int g() { return 0; }
+template <class T, class... U>
+int g(T t, U... u)
+{
+  return t + g(u...);
+}
+
+template <class... T>
+int f1(T... t)
+{
+  return [t...] {
+    return g(t...);
+  }();
+}
+
+template <class... T>
+int f2(T... t)
+{
+  return [&t...] {
+    return g(t...);
+  }();
+}
+
+template <class... T>
+int f3(T... t)
+{
+  return [=] {
+    return g(t...);
+  }();
+}
+
+template <class... T>
+int f4(T... t)
+{
+  return [&] {
+    return g(t...);
+  }();
+}
+
+#define assert(E) do { if (!(E)) __builtin_abort(); } while(0)
+int main()
+{
+  assert (f1() == 0);
+  assert (f2() == 0);
+  assert (f3() == 0);
+  assert (f4() == 0);
+  assert (f1(42) == 42);
+  assert (f2(42) == 42);
+  assert (f3(42) == 42);
+  assert (f4(42) == 42);
+  assert (f1(1,2,3) == 6);
+  assert (f2(1,2,3) == 6);
+  assert (f3(1,2,3) == 6);
+  assert (f4(1,2,3) == 6);
+}

commit 2ed46e10e051a3cabf6dbb47567c85e012e50ab8
Author: Jason Merrill <jason@redhat.com>
Date:   Sat Sep 14 10:49:38 2013 -0700

    	PR c++/41933
    	* cp-tree.h (DECL_PACK_P): Replace FUNCTION_PARAMETER_PACK_P.
    	* cxx-pretty-print.c (direct_declarator): Adjust.
    	* decl2.c (cp_build_parm_decl): Adjust.
    	* pt.c (function_parameter_pack_p): Adjust.
    	(find_parameter_packs_r, push_template_decl_real): Adjust.
    	(tsubst_pack_expansion, tsubst_decl): Adjust.
    	(regenerate_decl_from_template, instantiate_decl): Adjust.

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 0d8bd95..4680053 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -138,7 +138,6 @@  c-common.h, not after.
    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)
       USING_DECL_TYPENAME_P (in USING_DECL)
       DECL_VLA_CAPTURE_P (in FIELD_DECL)
    2: DECL_THIS_EXTERN (in VAR_DECL or FUNCTION_DECL).
@@ -2874,10 +2873,9 @@  extern void decl_shadowed_for_var_insert (tree, tree);
    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)))
+/* Determine if a declaration (PARM_DECL or FIELD_DECL) is a pack.  */
+#define DECL_PACK_P(NODE) \
+  (DECL_P (NODE) && PACK_EXPANSION_P (TREE_TYPE (NODE)))
 
 /* Determines if NODE is an expansion of one or more parameter packs,
    e.g., a TYPE_PACK_EXPANSION or EXPR_PACK_EXPANSION.  */
diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c
index 86d8b47..bcef876 100644
--- a/gcc/cp/cxx-pretty-print.c
+++ b/gcc/cp/cxx-pretty-print.c
@@ -1527,7 +1527,7 @@  cxx_pretty_printer::direct_declarator (tree t)
 	{
 	  pp_cxx_space_for_pointer_operator (this, TREE_TYPE (t));
 
-	  if ((TREE_CODE (t) == PARM_DECL && FUNCTION_PARAMETER_PACK_P (t))
+	  if ((TREE_CODE (t) == PARM_DECL && DECL_PACK_P (t))
 	      || template_parameter_pack_p (t))
 	    /* A function parameter pack or non-type template
 	       parameter pack.  */
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index d5d2912..c518551 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -188,11 +188,6 @@  cp_build_parm_decl (tree name, tree type)
   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;
 }
 
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index fed004c..ecae904 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -2852,7 +2852,7 @@  bool
 function_parameter_pack_p (const_tree t)
 {
   if (t && TREE_CODE (t) == PARM_DECL)
-    return FUNCTION_PARAMETER_PACK_P (t);
+    return DECL_PACK_P (t);
   return false;
 }
 
@@ -3085,7 +3085,7 @@  find_parameter_packs_r (tree *tp, int *walk_subtrees, void* data)
       break;
 
     case PARM_DECL:
-      if (FUNCTION_PARAMETER_PACK_P (t))
+      if (DECL_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.  */
@@ -4646,7 +4646,7 @@  push_template_decl_real (tree decl, bool is_friend)
 
       while (arg && argtype)
         {
-          if (!FUNCTION_PARAMETER_PACK_P (arg)
+          if (!DECL_PACK_P (arg)
               && check_for_bare_parameter_packs (TREE_TYPE (arg)))
             {
             /* This is a PARM_DECL that contains unexpanded parameter
@@ -9472,7 +9472,7 @@  tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
 		 have the wrong value for a recursive call.  Just make a
 		 dummy decl, since it's only used for its type.  */
 	      arg_pack = tsubst_decl (parm_pack, args, complain);
-	      if (arg_pack && FUNCTION_PARAMETER_PACK_P (arg_pack))
+	      if (arg_pack && DECL_PACK_P (arg_pack))
 		/* Partial instantiation of the parm_pack, we can't build
 		   up an argument pack yet.  */
 		arg_pack = NULL_TREE;
@@ -10465,7 +10465,7 @@  tsubst_decl (tree t, tree args, tsubst_flags_t complain)
         tree prev_r = NULL_TREE;
         tree first_r = NULL_TREE;
 
-        if (FUNCTION_PARAMETER_PACK_P (t))
+        if (DECL_PACK_P (t))
           {
             /* If there is a local specialization that isn't a
                parameter pack, it means that we're doing a "simple"
@@ -10515,10 +10515,6 @@  tsubst_decl (tree t, tree args, tsubst_flags_t complain)
               /* We're on the Ith parameter of the function parameter
                  pack.  */
               {
-		/* An argument of a function parameter pack is not a parameter
-		   pack.  */
-		FUNCTION_PARAMETER_PACK_P (r) = false;
-
                 /* Get the Ith type.  */
                 type = TREE_VEC_ELT (expanded_types, i);
 
@@ -18705,7 +18701,7 @@  regenerate_decl_from_template (tree decl, tree tmpl)
       pattern_parm
 	= skip_artificial_parms_for (code_pattern,
 				     DECL_ARGUMENTS (code_pattern));
-      while (decl_parm && !FUNCTION_PARAMETER_PACK_P (pattern_parm))
+      while (decl_parm && !DECL_PACK_P (pattern_parm))
 	{
 	  tree parm_type;
 	  tree attributes;
@@ -18728,7 +18724,7 @@  regenerate_decl_from_template (tree decl, tree tmpl)
 	}
       /* Merge any parameters that match with the function parameter
          pack.  */
-      if (pattern_parm && FUNCTION_PARAMETER_PACK_P (pattern_parm))
+      if (pattern_parm && DECL_PACK_P (pattern_parm))
         {
           int i, len;
           tree expanded_types;
@@ -19247,7 +19243,7 @@  instantiate_decl (tree d, int defer_ok,
 	}
       for (; tmpl_parm; tmpl_parm = DECL_CHAIN (tmpl_parm))
 	{
-	  if (!FUNCTION_PARAMETER_PACK_P (tmpl_parm))
+	  if (!DECL_PACK_P (tmpl_parm))
 	    {
 	      register_local_specialization (spec_parm, tmpl_parm);
 	      spec_parm = DECL_CHAIN (spec_parm);

commit 76b473356bfd7c7a1192b8756dec5f20890e23f1
Author: Jason Merrill <jason@redhat.com>
Date:   Sun Sep 15 08:12:38 2013 -0700

    	* lambda.c (add_capture): Don't add DECL_LANG_SPECIFIC.

diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c
index a53e692..bf75834 100644
--- a/gcc/cp/lambda.c
+++ b/gcc/cp/lambda.c
@@ -499,7 +499,7 @@  add_capture (tree lambda, tree id, tree initializer, bool by_reference_p,
     }
 
   /* Make member variable.  */
-  member = build_lang_decl (FIELD_DECL, name, type);
+  member = build_decl (input_location, FIELD_DECL, name, type);
   DECL_VLA_CAPTURE_P (member) = vla;
 
   if (!explicit_init_p)
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index d560e3c..fed004c 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -10500,7 +10500,7 @@  tsubst_decl (tree t, tree args, tsubst_flags_t complain)
               }
           }
 
-        /* Loop through all of the parameter's we'll build. When T is
+        /* Loop through all of the parameters 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;