--- gcc/match.pd.jj	2016-11-07 18:32:56.000000000 +0100
+++ gcc/match.pd	2016-11-08 14:00:05.391773322 +0100
@@ -2547,8 +2547,15 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
     (with
      {
        int equal = 2;
-       if (decl_in_symtab_p (base0)
-	   && decl_in_symtab_p (base1))
+       /* Punt in GENERIC on variables with value expressions;
+	  the value expressions might point to fields/elements
+	  of other vars etc.  */
+       if (GENERIC
+	   && ((VAR_P (base0) && DECL_HAS_VALUE_EXPR_P (base0))
+	       || (VAR_P (base1) && DECL_HAS_VALUE_EXPR_P (base1))))
+	 ;
+       else if (decl_in_symtab_p (base0)
+		&& decl_in_symtab_p (base1))
          equal = symtab_node::get_create (base0)
 	           ->equal_address_to (symtab_node::get_create (base1));
        else if ((DECL_P (base0)
--- gcc/cp/cp-tree.h.jj	2016-11-07 18:20:30.295762920 +0100
+++ gcc/cp/cp-tree.h	2016-11-09 12:11:58.088010491 +0100
@@ -2228,7 +2228,8 @@ struct GTY(()) lang_decl_base {
   unsigned u2sel : 1;
   unsigned concept_p : 1;                  /* applies to vars and functions */
   unsigned var_declared_inline_p : 1;	   /* var */
-  /* 2 spare bits */
+  unsigned decomposition_p : 1;		   /* var */
+  /* 1 spare bit */
 };
 
 /* True for DECL codes which have template info and access.  */
@@ -3626,6 +3627,16 @@ more_aggr_init_expr_args_p (const aggr_i
   (DECL_LANG_SPECIFIC (VAR_DECL_CHECK (NODE))->u.base.var_declared_inline_p \
    = true)
 
+/* Nonzero if NODE is the artificial VAR_DECL for decomposition
+   declaration.  */
+#define DECL_DECOMPOSITION_P(NODE) \
+  (DECL_LANG_SPECIFIC (VAR_DECL_CHECK (NODE))			\
+   ? DECL_LANG_SPECIFIC (NODE)->u.base.decomposition_p		\
+   : false)
+#define SET_DECL_DECOMPOSITION_P(NODE) \
+  (DECL_LANG_SPECIFIC (VAR_DECL_CHECK (NODE))->u.base.decomposition_p \
+   = true)
+
 /* Nonzero if NODE is an inline VAR_DECL.  In C++17, static data members
    declared with constexpr specifier are implicitly inline variables.  */
 #define DECL_INLINE_VAR_P(NODE) \
@@ -5157,7 +5168,8 @@ enum auto_deduction_context
   adc_unspecified,   /* Not given */
   adc_variable_type, /* Variable initializer deduction */
   adc_return_type,   /* Return type deduction */
-  adc_requirement    /* Argument dedution constraint */
+  adc_requirement,   /* Argument dedution constraint */
+  adc_decomp_type    /* Decomposition declaration initializer deduction */
 };
 
 /* True iff this TEMPLATE_TYPE_PARM represents decltype(auto).  */
@@ -5374,6 +5386,7 @@ enum cp_declarator_kind {
   cdk_pointer,
   cdk_reference,
   cdk_ptrmem,
+  cdk_decomp,
   cdk_error
 };
 
@@ -5404,7 +5417,8 @@ struct cp_declarator {
   /* Whether we parsed an ellipsis (`...') just before the declarator,
      to indicate this is a parameter pack.  */
   BOOL_BITFIELD parameter_pack_p : 1;
-  location_t id_loc; /* Currently only set for cdk_id and cdk_function. */
+  location_t id_loc; /* Currently only set for cdk_id, cdk_decomp and
+			cdk_function. */
   /* GNU Attributes that apply to this declarator.  If the declarator
      is a pointer or a reference, these attribute apply to the type
      pointed to.  */
@@ -5413,8 +5427,8 @@ struct cp_declarator {
      declarator is a pointer or a reference, these attributes apply
      to the pointer, rather than to the type pointed to.  */
   tree std_attributes;
-  /* For all but cdk_id and cdk_error, the contained declarator.  For
-     cdk_id and cdk_error, guaranteed to be NULL.  */
+  /* For all but cdk_id, cdk_decomp and cdk_error, the contained declarator.
+     For cdk_id, cdk_decomp and cdk_error, guaranteed to be NULL.  */
   cp_declarator *declarator;
   union {
     /* For identifiers.  */
@@ -5785,6 +5799,7 @@ extern tree start_decl				(const cp_decl
 extern void start_decl_1			(tree, bool);
 extern bool check_array_initializer		(tree, tree, tree);
 extern void cp_finish_decl			(tree, tree, bool, tree, int);
+extern void cp_finish_decomp			(tree, tree, unsigned int);
 extern int cp_complete_array_type		(tree *, tree, bool);
 extern int cp_complete_array_type_or_error	(tree *, tree, bool, tsubst_flags_t);
 extern tree build_ptrmemfunc_type		(tree);
@@ -6056,7 +6071,7 @@ extern tree implicitly_declare_fn
 extern bool maybe_clone_body			(tree);
 
 /* In parser.c */
-extern tree cp_convert_range_for (tree, tree, tree, bool);
+extern tree cp_convert_range_for (tree, tree, tree, tree, unsigned int, bool);
 extern bool parsing_nsdmi (void);
 extern void inject_this_parameter (tree, cp_cv_quals);
 
--- gcc/cp/parser.c.jj	2016-11-07 18:20:30.298762882 +0100
+++ gcc/cp/parser.c	2016-11-09 12:13:03.868168824 +0100
@@ -1668,6 +1668,7 @@ declarator_can_be_parameter_pack (cp_dec
 	{
 	case cdk_id:
 	case cdk_array:
+	case cdk_decomp:
 	  found = true;
 	  break;
 
@@ -1721,6 +1722,7 @@ function_declarator_p (const cp_declarat
 	  && declarator->declarator->kind == cdk_id)
 	return true;
       if (declarator->kind == cdk_id
+	  || declarator->kind == cdk_decomp
 	  || declarator->kind == cdk_error)
 	return false;
       declarator = declarator->declarator;
@@ -2200,6 +2202,8 @@ static void cp_parser_static_assert
   (cp_parser *, bool);
 static tree cp_parser_decltype
   (cp_parser *);
+static tree cp_parser_decomposition_declaration
+  (cp_parser *, cp_decl_specifier_seq *, tree *, location_t *);
 
 /* Declarators [gram.dcl.decl] */
 
@@ -11445,16 +11449,45 @@ cp_parser_range_for (cp_parser *parser,
 		     bool ivdep)
 {
   tree stmt, range_expr;
-  cxx_binding *binding = NULL;
-  tree name = NULL_TREE;
+  auto_vec <cxx_binding *, 16> bindings;
+  auto_vec <tree, 16> names;
+  tree decomp_first_name = NULL_TREE;
+  unsigned int decomp_cnt = 0;
 
   /* Get the range declaration momentarily out of the way so that
      the range expression doesn't clash with it. */
   if (range_decl != error_mark_node)
     {
-      name = DECL_NAME (range_decl);
-      binding = IDENTIFIER_BINDING (name);
-      IDENTIFIER_BINDING (name) = binding->previous;
+      if (DECL_HAS_VALUE_EXPR_P (range_decl))
+	{
+	  tree v = DECL_VALUE_EXPR (range_decl);
+	  /* For decomposition declaration get all of the corresponding
+	     declarations out of the way.  */
+	  if (TREE_CODE (v) == ARRAY_REF
+	      && VAR_P (TREE_OPERAND (v, 0))
+	      && DECL_DECOMPOSITION_P (TREE_OPERAND (v, 0)))
+	    {
+	      tree d = range_decl;
+	      range_decl = TREE_OPERAND (v, 0);
+	      decomp_cnt = tree_to_uhwi (TREE_OPERAND (v, 1)) + 1;
+	      decomp_first_name = d;
+	      for (unsigned int i = 0; i < decomp_cnt; i++, d = DECL_CHAIN (d))
+		{
+		  tree name = DECL_NAME (d);
+		  names.quick_push (name);
+		  bindings.quick_push (IDENTIFIER_BINDING (name));
+		  IDENTIFIER_BINDING (name)
+		    = IDENTIFIER_BINDING (name)->previous;
+		}
+	    }
+	}
+      if (names.is_empty ())
+	{
+	  tree name = DECL_NAME (range_decl);
+	  names.quick_push (name);
+	  bindings.quick_push (IDENTIFIER_BINDING (name));
+	  IDENTIFIER_BINDING (name) = IDENTIFIER_BINDING (name)->previous;
+	}
     }
 
   if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
@@ -11465,11 +11498,12 @@ cp_parser_range_for (cp_parser *parser,
   else
     range_expr = cp_parser_expression (parser);
 
-  /* Put the range declaration back into scope. */
-  if (range_decl != error_mark_node)
+  /* Put the range declaration(s) back into scope. */
+  for (unsigned int i = 0; i < names.length (); i++)
     {
-      binding->previous = IDENTIFIER_BINDING (name);
-      IDENTIFIER_BINDING (name) = binding;
+      cxx_binding *binding = bindings[i];
+      binding->previous = IDENTIFIER_BINDING (names[i]);
+      IDENTIFIER_BINDING (names[i]) = binding;
     }
 
   /* If in template, STMT is converted to a normal for-statement
@@ -11490,7 +11524,8 @@ cp_parser_range_for (cp_parser *parser,
   else
     {
       stmt = begin_for_stmt (scope, init);
-      stmt = cp_convert_range_for (stmt, range_decl, range_expr, ivdep);
+      stmt = cp_convert_range_for (stmt, range_decl, range_expr,
+				   decomp_first_name, decomp_cnt, ivdep);
     }
   return stmt;
 }
@@ -11582,6 +11617,7 @@ do_range_for_auto_deduction (tree decl,
 
 tree
 cp_convert_range_for (tree statement, tree range_decl, tree range_expr,
+		      tree decomp_first_name, unsigned int decomp_cnt,
 		      bool ivdep)
 {
   tree begin, end;
@@ -11655,6 +11691,8 @@ cp_convert_range_for (tree statement, tr
 					tf_warning_or_error),
 		  /*is_constant_init*/false, NULL_TREE,
 		  LOOKUP_ONLYCONVERTING);
+  if (VAR_P (range_decl) && DECL_DECOMPOSITION_P (range_decl))
+    cp_finish_decomp (range_decl, decomp_first_name, decomp_cnt);
 
   return statement;
 }
@@ -12528,6 +12566,8 @@ cp_parser_block_declaration (cp_parser *
 
    simple-declaration:
      decl-specifier-seq [opt] init-declarator-list [opt] ;
+     decl-specifier-seq ref-qualifier [opt] [ identifier-list ]
+       brace-or-equal-initializer ;
 
    init-declarator-list:
      init-declarator
@@ -12613,6 +12653,45 @@ cp_parser_simple_declaration (cp_parser*
       && !cp_parser_error_occurred (parser))
     cp_parser_commit_to_tentative_parse (parser);
 
+  /* Look for C++17 decomposition declaration.  */
+  for (size_t n = 1; ; n++)
+    if (cp_lexer_nth_token_is (parser->lexer, n, CPP_AND)
+	|| cp_lexer_nth_token_is (parser->lexer, n, CPP_AND_AND))
+      continue;
+    else if (cp_lexer_nth_token_is (parser->lexer, n, CPP_OPEN_SQUARE)
+	     && !cp_lexer_nth_token_is (parser->lexer, n + 1, CPP_OPEN_SQUARE)
+	     && decl_specifiers.any_specifiers_p)
+      {
+	tree decl
+	  = cp_parser_decomposition_declaration (parser, &decl_specifiers,
+						 maybe_range_for_decl,
+						 &init_loc);
+
+	/* The next token should be either a `,' or a `;'.  */
+	cp_token *token = cp_lexer_peek_token (parser->lexer);
+	/* If it's a `;', we are done.  */
+	if (token->type == CPP_SEMICOLON || maybe_range_for_decl)
+	  goto finish;
+	/* Anything else is an error.  */
+	else
+	  {
+	    /* If we have already issued an error message we don't need
+	       to issue another one.  */
+	    if ((decl != error_mark_node
+		 && DECL_INITIAL (decl) != error_mark_node)
+		|| cp_parser_uncommitted_to_tentative_parse_p (parser))
+	      cp_parser_error (parser, "expected %<,%> or %<;%>");
+	    /* Skip tokens until we reach the end of the statement.  */
+	    cp_parser_skip_to_end_of_statement (parser);
+	    /* If the next token is now a `;', consume it.  */
+	    if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
+	      cp_lexer_consume_token (parser->lexer);
+	    goto done;
+	  }
+      }
+    else
+      break;
+
   tree last_type;
 
   last_type = NULL_TREE;
@@ -12765,6 +12844,7 @@ cp_parser_simple_declaration (cp_parser*
     }
 
   /* Consume the `;'.  */
+ finish:
   if (!maybe_range_for_decl)
     cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
   else if (cp_lexer_next_token_is (parser->lexer, CPP_COLON))
@@ -12780,6 +12860,136 @@ cp_parser_simple_declaration (cp_parser*
   pop_deferring_access_checks ();
 }
 
+/* Helper of cp_parser_simple_declaration, parse a decomposition declaration.
+     decl-specifier-seq ref-qualifier [opt] [ identifier-list ]
+       brace-or-equal-initializer ;  */
+
+static tree
+cp_parser_decomposition_declaration (cp_parser *parser,
+				     cp_decl_specifier_seq *decl_specifiers,
+				     tree *maybe_range_for_decl,
+				     location_t *init_loc)
+{
+  cp_ref_qualifier ref_qual = cp_parser_ref_qualifier_opt (parser);
+  location_t loc = cp_lexer_peek_token (parser->lexer)->location;
+  cp_parser_require (parser, CPP_OPEN_SQUARE, RT_OPEN_SQUARE);
+  if (cxx_dialect < cxx1z)
+    pedwarn (loc, 0, "decomposition declaration only available with "
+		     "-std=c++1z or -std=gnu++1z");
+
+  /* Parse the identifier-list.  */
+  auto_vec<cp_expr, 10> v;
+  if (!cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_SQUARE))
+    while (true)
+      {
+	cp_expr e = cp_parser_identifier (parser);
+	if (e.get_value () == error_mark_node)
+	  break;
+	v.safe_push (e);
+	if (!cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
+	  break;
+	cp_lexer_consume_token (parser->lexer);
+      }
+
+  location_t end_loc = cp_lexer_peek_token (parser->lexer)->location;
+  if (!cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE))
+    {
+      end_loc = UNKNOWN_LOCATION;
+      cp_parser_skip_to_closing_parenthesis_1 (parser, true, CPP_CLOSE_SQUARE,
+					       false);
+      if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_SQUARE))
+	cp_lexer_consume_token (parser->lexer);
+      else
+	{
+	  cp_parser_skip_to_end_of_statement (parser);
+	  return error_mark_node;
+	}
+    }
+
+  tree pushed_scope;
+  cp_declarator *declarator = make_declarator (cdk_decomp);
+  loc = end_loc == UNKNOWN_LOCATION ? loc : make_location (loc, loc, end_loc);
+  declarator->id_loc = loc;
+  if (ref_qual != REF_QUAL_NONE)
+    declarator = make_reference_declarator (TYPE_UNQUALIFIED, declarator,
+					    ref_qual == REF_QUAL_RVALUE,
+					    NULL_TREE);
+  tree decl = start_decl (declarator, decl_specifiers, SD_INITIALIZED,
+			  NULL_TREE, decl_specifiers->attributes,
+			  &pushed_scope);
+
+  unsigned int i;
+  cp_expr e;
+  cp_decl_specifier_seq decl_specs;
+  clear_decl_specs (&decl_specs);
+  decl_specs.type = make_auto ();
+  tree prev = decl;
+  FOR_EACH_VEC_ELT (v, i, e)
+    {
+      if (i == 0)
+	declarator = make_id_declarator (NULL_TREE, e.get_value (), sfk_none);
+      else
+	declarator->u.id.unqualified_name = e.get_value ();
+      declarator->id_loc = e.get_location ();
+      tree decl2 = start_decl (declarator, &decl_specs, SD_INITIALIZED,
+			       NULL_TREE, NULL_TREE, &pushed_scope);
+      if (decl2 == error_mark_node)
+	decl = error_mark_node;
+      else if (decl != error_mark_node && DECL_CHAIN (decl2) != prev)
+	{
+	  /* Ensure we've diagnosed redeclaration if we aren't creating
+	     a new VAR_DECL.  */
+	  gcc_assert (errorcount);
+	  decl = error_mark_node;
+	}
+      else
+	prev = decl2;
+    }
+
+  if (v.is_empty ())
+    {
+      error_at (loc, "empty decomposition declaration");
+      decl = error_mark_node;
+    }
+
+  if (maybe_range_for_decl == NULL
+      || cp_lexer_next_token_is_not (parser->lexer, CPP_COLON))
+    {
+      bool non_constant_p = false, is_direct_init = false;
+      tree initializer;
+      *init_loc = cp_lexer_peek_token (parser->lexer)->location;
+      /* Parse the initializer.  */
+      if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
+	{
+	  initializer = cp_parser_braced_list (parser, &non_constant_p);
+	  CONSTRUCTOR_IS_DIRECT_INIT (initializer) = 1;
+	  is_direct_init = true;
+	}
+      else
+	{
+	  /* Consume the `='.  */
+	  cp_parser_require (parser, CPP_EQ, RT_EQ);
+	  initializer = cp_parser_initializer_clause (parser, &non_constant_p);
+	}
+
+      if (decl != error_mark_node)
+	{
+	  cp_finish_decl (decl, initializer, non_constant_p, NULL_TREE,
+			  is_direct_init ? LOOKUP_NORMAL : LOOKUP_IMPLICIT);
+	  cp_finish_decomp (decl, prev, v.length ());
+	}
+    }
+  else if (decl != error_mark_node)
+    {
+      *maybe_range_for_decl = prev;
+      /* Ensure DECL_VALUE_EXPR is created for all the decls but
+	 the underlying DECL.  */
+      cp_finish_decomp (decl, prev, v.length ());
+    }
+
+  return decl;
+}
+
 /* Parse a decl-specifier-seq.
 
    decl-specifier-seq:
@@ -18587,6 +18797,7 @@ strip_declarator_types (tree type, cp_de
     switch (d->kind)
       {
       case cdk_id:
+      case cdk_decomp:
       case cdk_error:
 	d = NULL;
 	break;
@@ -25447,6 +25658,7 @@ cp_parser_check_declarator_template_para
       return (cp_parser_check_declarator_template_parameters
 	      (parser, declarator->declarator, declarator_location));
 
+    case cdk_decomp:
     case cdk_error:
       return true;
 
--- gcc/cp/decl.c.jj	2016-11-07 18:20:30.299762870 +0100
+++ gcc/cp/decl.c	2016-11-09 12:12:42.372443865 +0100
@@ -6186,6 +6186,15 @@ check_initializer (tree decl, tree init,
       gcc_assert (init != NULL_TREE);
       init = NULL_TREE;
     }
+  else if (VAR_P (decl)
+	   && DECL_DECOMPOSITION_P (decl)
+	   && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
+    {
+      init_code = build2 (VEC_INIT_EXPR, type, decl, init);
+      TREE_SIDE_EFFECTS (init_code) = 1;
+      SET_EXPR_LOCATION (init_code, DECL_SOURCE_LOCATION (decl));
+      return init_code;
+    }
   else if (!init && DECL_REALLY_EXTERN (decl))
     ;
   else if (init || type_build_ctor_call (type)
@@ -6762,10 +6771,11 @@ cp_finish_decl (tree decl, tree init, bo
 	d_init = build_x_compound_expr_from_list (d_init, ELK_INIT,
 						  tf_warning_or_error);
       d_init = resolve_nondeduced_context (d_init, tf_warning_or_error);
-      type = TREE_TYPE (decl) = do_auto_deduction (type, d_init,
-						   auto_node,
-                                                   tf_warning_or_error,
-                                                   adc_variable_type);
+      enum auto_deduction_context adc = adc_variable_type;
+      if (VAR_P (decl) && DECL_DECOMPOSITION_P (decl))
+	adc = adc_decomp_type;
+      type = TREE_TYPE (decl) = do_auto_deduction (type, d_init, auto_node,
+						   tf_warning_or_error, adc);
       if (type == error_mark_node)
 	return;
       if (TREE_CODE (type) == FUNCTION_TYPE)
@@ -7129,6 +7139,281 @@ cp_finish_decl (tree decl, tree init, bo
   invoke_plugin_callbacks (PLUGIN_FINISH_DECL, decl);
 }
 
+/* For class TYPE return itself or some its bases that contain
+   any direct non-static data members.  Return error_mark_node if an
+   error has been diagnosed.  */
+
+static tree
+find_decomp_class_base (location_t loc, tree type, tree ret)
+{
+  bool member_seen = false;
+  for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
+    if (TREE_CODE (field) != FIELD_DECL || DECL_ARTIFICIAL (field))
+      continue;
+    else if (ret)
+      return type;
+    else if (ANON_AGGR_TYPE_P (TREE_TYPE (field)))
+      {
+	if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE)
+	  error_at (loc, "cannot decompose class type %qT because it has an "
+			 "anonymous struct member", type);
+	else
+	  error_at (loc, "cannot decompose class type %qT because it has an "
+			 "anonymous union member", type);
+	inform (DECL_SOURCE_LOCATION (field), "declared here");
+	return error_mark_node;
+      }
+    else if (TREE_PRIVATE (field) || TREE_PROTECTED (field))
+      {
+	error_at (loc, "cannot decompose non-public member %qD of %qT",
+		  field, type);
+	inform (DECL_SOURCE_LOCATION (field),
+		TREE_PRIVATE (field) ? "declared private here"
+		: "declared protected here");
+	return error_mark_node;
+      }
+    else
+      member_seen = true;
+
+  /* FIXME: How to deal with virtual bases etc.?  */
+  tree base_binfo, binfo;
+  tree orig_ret = ret;
+  int i;
+  if (member_seen)
+    ret = type;
+  for (binfo = TYPE_BINFO (type), i = 0;
+       BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
+    {
+      tree t = find_decomp_class_base (loc, TREE_TYPE (base_binfo), ret);
+      if (t == error_mark_node)
+	return error_mark_node;
+      if (t != NULL_TREE)
+	{
+	  if (ret == type)
+	    {
+	      error_at (loc, "cannot decompose class type %qT: both it and "
+			     "its base class %qT have non-static data members",
+			type, t);
+	      return error_mark_node;
+	    }
+	  else if (orig_ret != NULL_TREE)
+	    return t;
+	  else if (ret != NULL_TREE)
+	    {
+	      error_at (loc, "cannot decompose class type %qT: its base "
+			     "classes %qT and %qT have non-static data "
+			     "members", type, ret, t);
+	      return error_mark_node;
+	    }
+	  else
+	    /* FIXME: Check if this is thru a private base?  */
+	    ret = t;
+	}
+    }
+  return ret;
+}
+
+/* Finish a decomposition declaration.  DECL is the underlying declaration
+   "e", FIRST is the head of a chain of decls for the individual identifiers
+   chained through DECL_CHAIN in reverse order and COUNT is the number of
+   those decls.  */
+
+void
+cp_finish_decomp (tree decl, tree first, unsigned int count)
+{
+  location_t loc = DECL_SOURCE_LOCATION (decl);
+  if (error_operand_p (decl))
+    {
+     error_out:
+      while (count--)
+	{
+	  TREE_TYPE (first) = error_mark_node;
+	  if (DECL_HAS_VALUE_EXPR_P (first))
+	    {
+	      SET_DECL_VALUE_EXPR (first, NULL_TREE);
+	      DECL_HAS_VALUE_EXPR_P (first) = 0;
+	    }
+	  first = DECL_CHAIN (first);
+	}
+      return;
+    }
+
+  if (type_dependent_expression_p (decl)
+      /* This happens for range for when not in templates.
+	 Still add the DECL_VALUE_EXPRs for later processing.  */
+      || (!processing_template_decl
+	  && type_uses_auto (TREE_TYPE (decl))))
+    {
+      for (unsigned int i = 0; i < count; i++)
+	{
+	  if (!DECL_HAS_VALUE_EXPR_P (first))
+	    {
+	      tree v = build_nt (ARRAY_REF, decl,
+				 size_int (count - i - 1),
+				 NULL_TREE, NULL_TREE);
+	      SET_DECL_VALUE_EXPR (first, v);
+	      DECL_HAS_VALUE_EXPR_P (first) = 1;
+	    }
+	  if (processing_template_decl)
+	    {
+	      retrofit_lang_decl (first);
+	      SET_DECL_DECOMPOSITION_P (first);
+	    }
+	  first = DECL_CHAIN (first);
+	}
+      return;
+    }
+
+  auto_vec<tree, 16> v;
+  v.safe_grow (count);
+  tree d = first;
+  for (unsigned int i = 0; i < count; i++, d = DECL_CHAIN (d))
+    {
+      v[count - i - 1] = d;
+      if (processing_template_decl)
+	{
+	  retrofit_lang_decl (d);
+	  SET_DECL_DECOMPOSITION_P (d);
+	}
+    }
+
+  tree type = TREE_TYPE (decl);
+  tree eltype = NULL_TREE;
+  if (TREE_CODE (type) == REFERENCE_TYPE)
+    type = TREE_TYPE (type);
+
+  unsigned HOST_WIDE_INT eltscnt = 0;
+  if (TREE_CODE (type) == ARRAY_TYPE)
+    {
+      tree nelts;
+      nelts = array_type_nelts_top (type);
+      if (nelts == error_mark_node)
+	goto error_out;
+      if (!tree_fits_uhwi_p (nelts))
+	{
+	  error_at (loc, "cannot decompose variable length array %qT", type);
+	  goto error_out;
+	}
+      eltscnt = tree_to_uhwi (nelts);
+      if (count != eltscnt)
+	{
+       cnt_mismatch:
+	  if (count > eltscnt)
+	    error_at (loc, "%u names provided while %qT decomposes into "
+			   "%wu elements", count, type, eltscnt);
+	  else
+	    error_at (loc, "only %u names provided while %qT decomposes into "
+			   "%wu elements", count, type, eltscnt);
+	  goto error_out;
+	}
+      eltype = TREE_TYPE (type);
+      for (unsigned int i = 0; i < count; i++)
+	{
+	  TREE_TYPE (v[i]) = eltype;
+	  layout_decl (v[i], 0);
+	  tree t = convert_from_reference (decl);
+	  t = build4_loc (DECL_SOURCE_LOCATION (v[i]), ARRAY_REF,
+			  eltype, t, size_int (i), NULL_TREE,
+			  NULL_TREE);
+	  SET_DECL_VALUE_EXPR (v[i], t);
+	  DECL_HAS_VALUE_EXPR_P (v[i]) = 1;
+	}
+    }
+  /* 2 GNU extensions.  */
+  else if (TREE_CODE (type) == COMPLEX_TYPE)
+    {
+      eltscnt = 2;
+      if (count != eltscnt)
+	goto cnt_mismatch;
+      eltype = cp_build_qualified_type (TREE_TYPE (type), TYPE_QUALS (type));
+      for (unsigned int i = 0; i < count; i++)
+	{
+	  TREE_TYPE (v[i]) = eltype;
+	  layout_decl (v[i], 0);
+	  tree t = convert_from_reference (decl);
+	  t = build1_loc (DECL_SOURCE_LOCATION (v[i]),
+			  i ? IMAGPART_EXPR : REALPART_EXPR, eltype,
+			  t);
+	  SET_DECL_VALUE_EXPR (v[i], t);
+	  DECL_HAS_VALUE_EXPR_P (v[i]) = 1;
+	}
+    }
+  else if (TREE_CODE (type) == VECTOR_TYPE)
+    {
+      eltscnt = TYPE_VECTOR_SUBPARTS (type);
+      if (count != eltscnt)
+	goto cnt_mismatch;
+      eltype = cp_build_qualified_type (TREE_TYPE (type), TYPE_QUALS (type));
+      for (unsigned int i = 0; i < count; i++)
+	{
+	  TREE_TYPE (v[i]) = eltype;
+	  layout_decl (v[i], 0);
+	  tree t = convert_from_reference (decl);
+	  convert_vector_to_array_for_subscript (DECL_SOURCE_LOCATION (v[i]),
+						 &t, size_int (i));
+	  t = build4_loc (DECL_SOURCE_LOCATION (v[i]), ARRAY_REF,
+			  eltype, t, size_int (i), NULL_TREE,
+			  NULL_TREE);
+	  SET_DECL_VALUE_EXPR (v[i], t);
+	  DECL_HAS_VALUE_EXPR_P (v[i]) = 1;
+	}
+    }
+  else if (TREE_CODE (type) == UNION_TYPE)
+    {
+      error_at (loc, "cannot decompose union type %qT", type);
+      goto error_out;
+    }
+  else if (!CLASS_TYPE_P (type))
+    {
+      error_at (loc, "cannot decompose non-array non-class type %qT", type);
+      goto error_out;
+    }
+  else
+    {
+      /* FIXME: try to evaluate std::tuple_size<type>::size as integral
+	 constant expression and use std::tuple_element<i, type> as types
+	 and decl.get<i> or get<i>(decl) as initializer.
+	 And only if that fails fall through into this.  */
+      tree btype = find_decomp_class_base (loc, type, NULL_TREE);
+      if (btype == error_mark_node)
+	goto error_out;
+      else if (btype == NULL_TREE)
+	{
+	  error_at (loc, "cannot decompose class type %qT without non-static "
+			 "data members", type);
+	  goto error_out;
+	}
+      for (tree field = TYPE_FIELDS (btype); field; field = TREE_CHAIN (field))
+	if (TREE_CODE (field) != FIELD_DECL || DECL_ARTIFICIAL (field))
+	  continue;
+	else
+	  eltscnt++;
+      if (count != eltscnt)
+	goto cnt_mismatch;
+      tree t = convert_from_reference (decl);
+      /* FIXME: need to build_base_path or something similar here.  */
+      gcc_assert (type == btype);
+      unsigned int i = 0;
+      for (tree field = TYPE_FIELDS (btype); field; field = TREE_CHAIN (field))
+	if (TREE_CODE (field) != FIELD_DECL || DECL_ARTIFICIAL (field))
+	  continue;
+	else
+	  {
+	    tree eltype = unlowered_expr_type (field);
+	    /* FIXME: not really sure about the qualifiers here at all.  */
+	    eltype = cp_build_qualified_type (eltype, TYPE_QUALS (eltype)
+						      | TYPE_QUALS (type));
+	    TREE_TYPE (v[i]) = eltype;
+	    layout_decl (v[i], 0);
+	    tree tt = build3_loc (DECL_SOURCE_LOCATION (v[i]),
+				  COMPONENT_REF, eltype, t, field, NULL_TREE);
+	    SET_DECL_VALUE_EXPR (v[i], tt);
+	    DECL_HAS_VALUE_EXPR_P (v[i]) = 1;
+	    i++;
+	  }
+    }
+}
+
 /* Returns a declaration for a VAR_DECL as if:
 
      extern "C" TYPE NAME;
@@ -9441,7 +9726,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 parameter_pack_p = declarator ? declarator->parameter_pack_p : false;
   bool template_type_arg = false;
   bool template_parm_flag = false;
   bool typedef_p = decl_spec_seq_has_spec_p (declspecs, ds_typedef);
@@ -9637,6 +9922,10 @@ grokdeclarator (const cp_declarator *dec
 	case cdk_ptrmem:
 	  break;
 
+	case cdk_decomp:
+	  name = "decomposition";
+	  break;
+
 	case cdk_error:
 	  return error_mark_node;
 
@@ -9846,15 +10135,15 @@ grokdeclarator (const cp_declarator *dec
   if (explicit_intN)
     {
       if (! int_n_enabled_p[declspecs->int_n_idx])
-       {
-         error ("%<__int%d%> is not supported by this target",
-		int_n_data[declspecs->int_n_idx].bitsize);
-         explicit_intN = false;
-       }
+	{
+	  error ("%<__int%d%> is not supported by this target",
+		 int_n_data[declspecs->int_n_idx].bitsize);
+	  explicit_intN = false;
+	}
       else if (pedantic && ! in_system_header_at (input_location))
-       pedwarn (input_location, OPT_Wpedantic,
-                "ISO C++ does not support %<__int%d%> for %qs",
-		int_n_data[declspecs->int_n_idx].bitsize,  name);
+	pedwarn (input_location, OPT_Wpedantic,
+		 "ISO C++ does not support %<__int%d%> for %qs",
+		 int_n_data[declspecs->int_n_idx].bitsize, name);
     }
 
   /* Now process the modifiers that were specified
@@ -10070,6 +10359,79 @@ grokdeclarator (const cp_declarator *dec
       virtualp = 0;
     }
 
+  if (innermost_code == cdk_decomp)
+    {
+      location_t loc = (declarator->kind == cdk_reference
+			? declarator->declarator->id_loc : declarator->id_loc);
+      if (inlinep)
+	error_at (declspecs->locations[ds_inline],
+		  "decomposition declaration cannot be declared %<inline%>");
+      if (typedef_p)
+	error_at (declspecs->locations[ds_typedef],
+		  "decomposition declaration cannot be declared %<typedef%>");
+      if (constexpr_p)
+	error_at (declspecs->locations[ds_constexpr], "decomposition "
+		  "declaration cannot be declared %<constexpr%>");
+      if (thread_p)
+	error_at (declspecs->locations[ds_thread],
+		  "decomposition declaration cannot be declared %qs",
+		  declspecs->gnu_thread_keyword_p
+		  ? "__thread" : "thread_local");
+      if (concept_p)
+	error_at (declspecs->locations[ds_concept],
+		  "decomposition declaration cannot be declared %<concept%>");
+      switch (storage_class)
+	{
+	case sc_none:
+	  break;
+	case sc_register:
+	  error_at (loc, "decomposition declaration cannot be declared "
+		    "%<register%>");
+	  break;
+	case sc_static:
+	  error_at (loc, "decomposition declaration cannot be declared "
+		    "%<static%>");
+	  break;
+	case sc_extern:
+	  error_at (loc, "decomposition declaration cannot be declared "
+		    "%<extern%>");
+	  break;
+	case sc_mutable:
+	  error_at (loc, "decomposition declaration cannot be declared "
+		    "%<mutable%>");
+	  break;
+	case sc_auto:
+	  error_at (loc, "decomposition declaration cannot be declared "
+		    "C++98 %<auto%>");
+	  break;
+	default:
+	  gcc_unreachable ();
+	}
+      if (TREE_CODE (type) != TEMPLATE_TYPE_PARM
+	  || TYPE_IDENTIFIER (type) != get_identifier ("auto"))
+	{
+	  if (type != error_mark_node)
+	    {
+	      error_at (loc, "decomposition declaration cannot be declared "
+			"with type %qT", type);
+	      inform (loc,
+		      "type must be cv-qualified %<auto%> or reference to "
+		      "cv-qualified %<auto%>");
+	    }
+	  type = build_qualified_type (make_auto (), type_quals);
+	  declspecs->type = type;
+	}
+      inlinep = 0;
+      typedef_p = 0;
+      constexpr_p = 0;
+      thread_p = 0;
+      concept_p = 0;
+      storage_class = sc_none;
+      staticp = 0;
+      declspecs->storage_class = sc_none;
+      declspecs->locations[ds_thread] = UNKNOWN_LOCATION;
+    }
+
   /* Static anonymous unions are dealt with here.  */
   if (staticp && decl_context == TYPENAME
       && declspecs->type
@@ -10209,7 +10571,7 @@ grokdeclarator (const cp_declarator *dec
 					    attr_flags);
 	}
 
-      if (declarator->kind == cdk_id)
+      if (declarator->kind == cdk_id || declarator->kind == cdk_decomp)
 	break;
 
       inner_declarator = declarator->declarator;
@@ -10698,6 +11060,7 @@ grokdeclarator (const cp_declarator *dec
      is non-NULL, we know it is a cdk_id declarator; otherwise, we
      would not have exited the loop above.  */
   if (declarator
+      && declarator->kind == cdk_id
       && declarator->u.id.qualifying_scope
       && MAYBE_CLASS_TYPE_P (declarator->u.id.qualifying_scope))
     {
@@ -10709,13 +11072,14 @@ grokdeclarator (const cp_declarator *dec
 	{
 	  if (friendp)
 	    {
-	      permerror (input_location, "member functions are implicitly friends of their class");
+	      permerror (input_location, "member functions are implicitly "
+					 "friends of their class");
 	      friendp = 0;
 	    }
 	  else
 	    permerror (declarator->id_loc, 
-			  "extra qualification %<%T::%> on member %qs",
-			  ctype, name);
+		       "extra qualification %<%T::%> on member %qs",
+		       ctype, name);
 	}
       else if (/* If the qualifying type is already complete, then we
 		  can skip the following checks.  */
@@ -11088,7 +11452,8 @@ grokdeclarator (const cp_declarator *dec
   else if (unqualified_id == NULL_TREE && decl_context != PARM
 	   && decl_context != CATCHPARM
 	   && TREE_CODE (type) != UNION_TYPE
-	   && ! bitfield)
+	   && ! bitfield
+	   && innermost_code != cdk_decomp)
     {
       error ("abstract declarator %qT used as declaration", type);
       return error_mark_node;
@@ -11673,6 +12038,14 @@ grokdeclarator (const cp_declarator *dec
 
 	if (inlinep)
 	  mark_inline_variable (decl);
+	if (innermost_code == cdk_decomp)
+	  {
+	    gcc_assert (declarator && declarator->kind == cdk_decomp);
+	    DECL_SOURCE_LOCATION (decl) = declarator->id_loc;
+	    retrofit_lang_decl (decl);
+	    DECL_ARTIFICIAL (decl) = 1;
+	    SET_DECL_DECOMPOSITION_P (decl);
+	  }
       }
 
     if (VAR_P (decl) && !initialized)
--- gcc/cp/pt.c.jj	2016-11-07 23:28:25.990267594 +0100
+++ gcc/cp/pt.c	2016-11-09 12:13:26.057884903 +0100
@@ -15244,6 +15244,55 @@ tsubst_find_omp_teams (tree *tp, int *wa
   return NULL_TREE;
 }
 
+/* Helper function for tsubst_expr.  For decomposition declaration
+   artificial base DECL, which is tsubsted PATTERN_DECL, tsubst
+   also the corresponding decls representing the identifiers
+   of the decomposition declaration.  Return DECL if successful
+   or error_mark_node otherwise, set *FIRST to the first decl
+   in the list chained through DECL_CHAIN and *CNT to the number
+   of such decls.  */
+
+static tree
+tsubst_decomp_names (tree decl, tree pattern_decl, tree args,
+		     tsubst_flags_t complain, tree in_decl, tree *first,
+		     unsigned int *cnt)
+{
+  tree decl2, decl3, prev = decl;
+  *cnt = 0;
+  gcc_assert (DECL_NAME (decl) == NULL_TREE);
+  for (decl2 = DECL_CHAIN (pattern_decl);
+       decl2
+       && VAR_P (decl2)
+       && DECL_DECOMPOSITION_P (decl2)
+       && DECL_NAME (decl2);
+       decl2 = DECL_CHAIN (decl2))
+    {
+      (*cnt)++;
+      gcc_assert (DECL_HAS_VALUE_EXPR_P (decl2));
+      tree v = DECL_VALUE_EXPR (decl2);
+      DECL_HAS_VALUE_EXPR_P (decl2) = 0;
+      SET_DECL_VALUE_EXPR (decl2, NULL_TREE);
+      decl3 = tsubst (decl2, args, complain, in_decl);
+      SET_DECL_VALUE_EXPR (decl2, v);
+      DECL_HAS_VALUE_EXPR_P (decl2) = 1;
+      if (VAR_P (decl3))
+	DECL_TEMPLATE_INSTANTIATED (decl3) = 1;
+      maybe_push_decl (decl3);
+      if (error_operand_p (decl3))
+	decl = error_mark_node;
+      else if (decl != error_mark_node
+	       && DECL_CHAIN (decl3) != prev)
+	{
+	  gcc_assert (errorcount);
+	  decl = error_mark_node;
+	}
+      else
+	prev = decl3;
+    }
+  *first = prev;
+  return decl;
+}
+
 /* Like tsubst_copy for expressions, etc. but also does semantic
    processing.  */
 
@@ -15387,6 +15436,16 @@ tsubst_expr (tree t, tree args, tsubst_f
 		      const_init = (DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P
 				    (pattern_decl));
 		    cp_finish_decl (decl, init, const_init, NULL_TREE, 0);
+		    if (VAR_P (decl) && DECL_DECOMPOSITION_P (decl))
+		      {
+			unsigned int cnt;
+			tree first;
+			decl = tsubst_decomp_names (decl, pattern_decl, args,
+						    complain, in_decl, &first,
+						    &cnt);
+			if (decl != error_mark_node)
+			  cp_finish_decomp (decl, first, cnt);
+		      }
 		  }
 	      }
 	  }
@@ -15414,7 +15473,18 @@ tsubst_expr (tree t, tree args, tsubst_f
         decl = tsubst (decl, args, complain, in_decl);
         maybe_push_decl (decl);
         expr = RECUR (RANGE_FOR_EXPR (t));
-        stmt = cp_convert_range_for (stmt, decl, expr, RANGE_FOR_IVDEP (t));
+	if (VAR_P (decl) && DECL_DECOMPOSITION_P (decl))
+	  {
+	    unsigned int cnt;
+	    tree first;
+	    decl = tsubst_decomp_names (decl, RANGE_FOR_DECL (t), args,
+					complain, in_decl, &first, &cnt);
+	    stmt = cp_convert_range_for (stmt, decl, expr, first, cnt,
+					 RANGE_FOR_IVDEP (t));
+	  }
+	else
+	  stmt = cp_convert_range_for (stmt, decl, expr, NULL_TREE, 0,
+				       RANGE_FOR_IVDEP (t));
         RECUR (RANGE_FOR_BODY (t));
         finish_for_stmt (stmt);
       }
@@ -24610,7 +24680,15 @@ do_auto_deduction (tree type, tree init,
 
   init = resolve_nondeduced_context (init, complain);
 
-  if (AUTO_IS_DECLTYPE (auto_node))
+  if (context == adc_decomp_type
+      && auto_node == type
+      && init != error_mark_node
+      && TREE_CODE (TREE_TYPE (init)) == ARRAY_TYPE)
+    /* [dcl.decomp]/1 - if decomposition declaration has no ref-qualifiers
+       and initializer has array type, deduce cv-qualified array type.  */
+    return cp_build_qualified_type_real (TREE_TYPE (init), TYPE_QUALS (type),
+					 complain);
+  else if (AUTO_IS_DECLTYPE (auto_node))
     {
       bool id = (DECL_P (init)
 		 || ((TREE_CODE (init) == COMPONENT_REF
@@ -24694,6 +24772,7 @@ do_auto_deduction (tree type, tree init,
                     error("placeholder constraints not satisfied");
                     break;
                   case adc_variable_type:
+		  case adc_decomp_type:
                     error ("deduced initializer does not satisfy "
                            "placeholder constraints");
                     break;
@@ -24702,7 +24781,7 @@ do_auto_deduction (tree type, tree init,
                            "placeholder constraints");
                     break;
                   case adc_requirement:
-                    error ("deduced expression type does not saatisy "
+		    error ("deduced expression type does not satisfy "
                            "placeholder constraints");
                     break;
                   }
--- gcc/cp/cp-gimplify.c.jj	2016-10-31 13:28:11.000000000 +0100
+++ gcc/cp/cp-gimplify.c	2016-11-08 23:16:31.839545356 +0100
@@ -617,6 +617,14 @@ cp_gimplify_expr (tree *expr_p, gimple_s
 	int from_array = (init && TREE_CODE (TREE_TYPE (init)) == ARRAY_TYPE);
 	gcc_assert (EXPR_HAS_LOCATION (*expr_p));
 	input_location = EXPR_LOCATION (*expr_p);
+	if (VAR_P (VEC_INIT_EXPR_SLOT (*expr_p))
+	    && DECL_DECOMPOSITION_P (VEC_INIT_EXPR_SLOT (*expr_p))
+	    && init
+	    && DIRECT_LIST_INIT_P (init)
+	    && CONSTRUCTOR_NELTS (init) == 1
+	    && (TREE_CODE (TREE_TYPE (CONSTRUCTOR_ELT (init, 0)->value))
+		== ARRAY_TYPE))
+	  from_array = 1;
 	*expr_p = build_vec_init (VEC_INIT_EXPR_SLOT (*expr_p), NULL_TREE,
 				  init, VEC_INIT_EXPR_VALUE_INIT (*expr_p),
 				  from_array,
--- gcc/testsuite/g++.dg/cpp1z/decomp1.C.jj	2016-11-08 13:32:55.030786923 +0100
+++ gcc/testsuite/g++.dg/cpp1z/decomp1.C	2016-11-08 14:02:18.007080438 +0100
@@ -0,0 +1,35 @@
+// { dg-do run { target c++11 } }
+// { dg-options "" }
+
+int a[2] = { 1, 2 };
+struct S { int a; signed char b; float c; } s = { 6, 7, 8.0f };
+
+int
+main ()
+{
+  auto & [ c, d ] = a;		// { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+  auto [ e, f ] = a;		// { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+  auto [ g, h, i ] = s;		// { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+  auto & [ j, k, l ] = s;	// { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+  c++;
+  d++;
+  e += 6;
+  f += 7;
+  g++;
+  h++;
+  j += 10;
+  k += 11;
+  if (c != 2 || &c != &a[0]
+      || d != 3 || &d != &a[1]
+      || e != 7 || &e == &a[0]
+      || f != 9 || &f == &a[1]
+      || g != 7 || &g == &s.a
+      || h != 8 || &h == &s.b
+      || i != 8.0f || &i == &s.c
+      || j != 16 || &j != &s.a
+      || k != 18 || &k != &s.b
+      || l != 8.0f || &l != &s.c
+      || a[0] != 2 || a[1] != 3
+      || s.a != 16 || s.b != 18 || s.c != 8.0f)
+    __builtin_abort ();
+}
--- gcc/testsuite/g++.dg/cpp1z/decomp2.C.jj	2016-11-08 14:05:16.422804395 +0100
+++ gcc/testsuite/g++.dg/cpp1z/decomp2.C	2016-11-08 14:23:35.499806422 +0100
@@ -0,0 +1,54 @@
+// { dg-do run { target c++11 } }
+// { dg-options "" }
+
+typedef int V __attribute__((vector_size (4 * sizeof (int))));
+V a = (V) { 1, 2, 3, 4 };
+__complex__ double b = 5.0 + 6.0i;
+__complex__ int c = 7 + 8i;
+
+int
+main ()
+{
+  auto & [ d, e, f, g ] = a;	// { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+  auto [ h, i, j, k ] = a;	// { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+  auto [ l, m ] = b;		// { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+  auto & [ n, o ] = b;		// { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+  auto & [ p, q ] = c;		// { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+  auto [ r, s ] = c;		// { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+  d += 10;
+  e += 11;
+  f += 12;
+  g += 13;
+  h += 14;
+  i += 15;
+  j += 16;
+  k += 17;
+  l = l * 2.;
+  m = m * 3.;
+  n = n * 3.;
+  o = o * 2.;
+  p += 18;
+  q += 19;
+  r += 22;
+  s += 23;
+  if (d != 11 || &d != &a[0]
+      || e != 13 || &e != &a[1]
+      || f != 15 || &f != &a[2]
+      || g != 17 || &g != &a[3]
+      || h != 15 || &h == &a[0]
+      || i != 17 || &i == &a[1]
+      || j != 19 || &j == &a[2]
+      || k != 21 || &k == &a[3]
+      || l != 10.0 || &l == &__real__ b
+      || m != 18.0 || &m == &__imag__ b
+      || n != 15.0 || &n != &__real__ b
+      || o != 12.0 || &o != &__imag__ b
+      || p != 25 || &p != &__real__ c
+      || q != 27 || &q != &__imag__ c
+      || r != 29 || &r == &__real__ c
+      || s != 31 || &s == &__imag__ c
+      || a[0] != 11 || a[1] != 13 || a[2] != 15 || a[3] != 17
+      || b != 15.0 + 12.0i
+      || c != 25 + 27i)
+    __builtin_abort ();
+}
--- gcc/testsuite/g++.dg/cpp1z/decomp3.C.jj	2016-11-08 14:50:25.944303109 +0100
+++ gcc/testsuite/g++.dg/cpp1z/decomp3.C	2016-11-08 15:21:44.814703322 +0100
@@ -0,0 +1,66 @@
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+struct A { int a, b; float c; };
+A &bar ();
+struct B { int d; };
+B baz ();
+
+void
+test (A &b, B c)
+{
+  int && [ d ] = c;			// { dg-error "decomposition declaration cannot be declared with type 'int'" }
+					// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+  char & [ e, f, ff ] { b };		// { dg-error "decomposition declaration cannot be declared with type 'char'" }
+					// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+  auto&[g,h,i]=b;			// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } }
+  decltype (auto) [ j ] = c;		// { dg-error "decomposition declaration cannot be declared with type 'decltype.auto.'" "" { target c++14 } }
+					// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+					// { dg-error "expected primary-expression before 'decltype'" "" { target c++11_down } .-2 }
+  auto & & && & [ m, n, o ] = b;	// { dg-error "multiple ref-qualifiers" }
+					// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+  constexpr auto [ p ] = c;		// { dg-error "decomposition declaration cannot be declared 'constexpr'" }
+					// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+  friend auto [ q ] = c;		// { dg-error "'friend' used outside of class" }
+					// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+  typedef auto [ r ] = c;		// { dg-error "decomposition declaration cannot be declared 'typedef'" }
+					// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+  inline auto [ s ] = c;		// { dg-error "decomposition declaration cannot be declared 'inline'" }
+					// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+  __restrict auto [ t ] = c;		// { dg-error "invalid use of 'restrict'" }
+					// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+  long long auto [ u ] = c;		// { dg-error "'long long' invalid for 'decomposition'" }
+					// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+  virtual auto [ v ] = c;		// { dg-error "'virtual' outside class declaration" }
+					// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+  explicit auto [ w ] = c;		// { dg-error "'explicit' outside class declaration" }
+					// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+  static auto [ x ] = c;		// { dg-error "decomposition declaration cannot be declared 'static'" }
+					// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+  extern auto [ y ] { c };		// { dg-error "decomposition declaration cannot be declared 'extern'" }
+					// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+}
+
+void
+test2 (auto & [ p ] = bar ())		// { dg-error "'p' was not declared in this scope" }
+{
+}
+
+int arr[4];
+
+void
+test3 (A &b, B c)
+{
+  auto [ d, e, f ] = arr;		// { dg-error "only 3 names provided while 'int .4.' decomposes into 4 elements" }
+					// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+  auto & [ g, h, i, j, k ] = arr;	// { dg-error "5 names provided while 'int .4.' decomposes into 4 elements" }
+					// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+  auto [ l, m ] = b;			// { dg-error "only 2 names provided while 'A' decomposes into 3 elements" }
+					// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+  auto & [ n, o, p, q ] = b;		// { dg-error "4 names provided while 'A' decomposes into 3 elements" }
+					// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+  auto [] { c };			// { dg-error "empty decomposition declaration" }
+					// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+  auto [ r, s ] = c;			// { dg-error "2 names provided while 'B' decomposes into 1 elements" }
+					// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+}
--- gcc/testsuite/g++.dg/cpp1z/decomp4.C.jj	2016-11-08 15:29:24.769896964 +0100
+++ gcc/testsuite/g++.dg/cpp1z/decomp4.C	2016-11-08 15:50:58.262587786 +0100
@@ -0,0 +1,32 @@
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+struct A { int a; struct { int b; }; };
+struct B { int a; union { int c; long d; }; };
+struct C { int a; private: int b; };
+struct D { int a; private: static int b; };
+struct E { protected: int a; };
+struct F { int a; };
+struct G : public F { int b; };
+struct H { int b; };
+struct I : public F, H {};
+
+void
+test (A &a, B &b, C &c, D &d, E &e, F &f, G &g, H &h, I &i)
+{
+  auto [ j ] = a;			// { dg-error "cannot decompose class type 'A' because it has an anonymous struct member" }
+					// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+  auto [ k ] { b };			// { dg-error "cannot decompose class type 'B' because it has an anonymous union member" }
+					// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+  auto [ l ] = c;			// { dg-error "cannot decompose non-public member 'C::b' of 'C'" }
+					// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+  auto [ m ] = d;			// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } }
+  auto [ n ] { e };			// { dg-error "cannot decompose non-public member 'E::a' of 'E'" }
+					// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+  auto [ o ] { f };			// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } }
+  auto & [ p ] { g };			// { dg-error "cannot decompose class type 'G': both it and its base class 'F' have non-static data members" }
+					// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+  auto [ q ] { h };			// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } }
+  auto [ r ] { i };			// { dg-error "cannot decompose class type 'I': its base classes 'F' and 'H' have non-static data members" }
+					// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
+}
--- gcc/testsuite/g++.dg/cpp1z/decomp5.C.jj	2016-11-08 17:18:24.312329106 +0100
+++ gcc/testsuite/g++.dg/cpp1z/decomp5.C	2016-11-08 17:18:18.000000000 +0100
@@ -0,0 +1,40 @@
+// { dg-do run { target c++11 } }
+// { dg-options "" }
+
+struct A { int i; long long j; } a[64];
+
+int
+main ()
+{
+  int i = 0;
+  for (auto &x : a)
+    {
+      x.i = i;
+      x.j = 2 * i++;
+    }
+  for (auto & [ x, y ] : a)	// { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+    {
+      x += 2;
+      y += 3;
+    }
+  i = 0;
+  for (const auto [ u, v ] : a)	// { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+    {
+      if (u != i + 2 || v != 2 * i++ + 3)
+	__builtin_abort ();
+    }
+  i = 0;
+  for (auto [ x, y ] : a)	// { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+    {
+      x += 4;
+      y += 5;
+      if (x != i + 6 || y != 2 * i++ + 8)
+	__builtin_abort ();
+    }
+  i = 0;
+  for (const auto x : a)
+    {
+      if (x.i != i + 2 || x.j != 2 * i++ + 3)
+	__builtin_abort ();
+    }
+}
--- gcc/testsuite/g++.dg/cpp1z/decomp6.C.jj	2016-11-08 18:04:20.612695454 +0100
+++ gcc/testsuite/g++.dg/cpp1z/decomp6.C	2016-11-09 11:19:15.100450569 +0100
@@ -0,0 +1,103 @@
+// { dg-do run { target c++11 } }
+// { dg-options "" }
+
+int ccnt, dcnt, cccnt, tccnt;
+
+struct A
+{
+  A () : a (6) { ccnt++; }
+  ~A () { dcnt++; }
+  explicit A (const A &x) : a (x.a) { cccnt++; }
+  template <typename T>
+  A (const T &x) : a (x.a) { tccnt++; }
+  int a;
+};
+
+// FIXME: without this dummy function the testcase fails to link.
+void
+fixme ()
+{
+  A x1;
+  A x2 = x1;
+  A x3 { x1 };
+}
+
+int
+main ()
+{
+  if (ccnt || dcnt || cccnt || tccnt)
+    __builtin_abort ();
+  {
+    A a[6];
+    if (ccnt != 6 || dcnt || cccnt || tccnt)
+      __builtin_abort ();
+    {
+      auto [b,c,d,e,f,g] = a;		// { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+      if (ccnt != 6 || dcnt || cccnt || tccnt != 6)
+	__builtin_abort ();
+      b.a++;
+      c.a += 2;
+      f.a += 3;
+      if (b.a != 7 || c.a != 8 || d.a != 6 || e.a != 6 || f.a != 9 || g.a != 6)
+	__builtin_abort ();
+      if (&b == &a[0] || &c == &a[1] || &d == &a[2] || &e == &a[3] || &f == &a[4] || &g == &a[5])
+	__builtin_abort ();
+      {
+	auto&[ h, i, j, k, l, m ] = a;	// { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+	if (ccnt != 6 || dcnt || cccnt || tccnt != 6)
+	  __builtin_abort ();
+	j.a += 4;
+	k.a += 5;
+	m.a += 6;
+	if (a[0].a != 6 || a[1].a != 6 || a[2].a != 10 || a[3].a != 11 || a[4].a != 6 || a[5].a != 12)
+	  __builtin_abort ();
+	if (&h != &a[0] || &i != &a[1] || &j != &a[2] || &k != &a[3] || &l != &a[4] || &m != &a[5])
+	  __builtin_abort ();
+      }
+      if (ccnt != 6 || dcnt || cccnt || tccnt != 6)
+	__builtin_abort ();
+    }
+    if (ccnt != 6 || dcnt != 6 || cccnt || tccnt != 6)
+      __builtin_abort ();
+  }
+  if (ccnt != 6 || dcnt != 12 || cccnt || tccnt != 6)
+    __builtin_abort ();
+#if 0
+  // FIXME
+  {
+    A a[6];
+    if (ccnt != 12 || dcnt != 12 || cccnt || tccnt != 6)
+      __builtin_abort ();
+    {
+      auto [b,c,d,e,f,g] { a };		// { dag-warning "decomposition declaration only available with" "" { target c++14_down } }
+      if (ccnt != 12 || dcnt != 12 || cccnt != 6 || tccnt != 6)
+	__builtin_abort ();
+      b.a++;
+      c.a += 2;
+      f.a += 3;
+      if (b.a != 7 || c.a != 8 || d.a != 6 || e.a != 6 || f.a != 9 || g.a != 6)
+	__builtin_abort ();
+      if (&b == &a[0] || &c == &a[1] || &d == &a[2] || &e == &a[3] || &f == &a[4] || &g == &a[5])
+	__builtin_abort ();
+      {
+	auto&[ h, i, j, k, l, m ] {a};	// { dag-warning "decomposition declaration only available with" "" { target c++14_down } }
+	if (ccnt != 12 || dcnt != 12 || cccnt != 6 || tccnt != 6)
+	  __builtin_abort ();
+	j.a += 4;
+	k.a += 5;
+	m.a += 6;
+	if (a[0].a != 6 || a[1].a != 6 || a[2].a != 10 || a[3].a != 11 || a[4].a != 6 || a[5].a != 12)
+	  __builtin_abort ();
+	if (&h != &a[0] || &i != &a[1] || &j != &a[2] || &k != &a[3] || &l != &a[4] || &m != &a[5])
+	  __builtin_abort ();
+      }
+      if (ccnt != 12 || dcnt != 12 || cccnt != 6 || tccnt != 6)
+	__builtin_abort ();
+    }
+    if (ccnt != 12 || dcnt != 18 || cccnt != 6 || tccnt != 6)
+      __builtin_abort ();
+  }
+  if (ccnt != 12 || dcnt != 24 || cccnt != 6 || tccnt != 6)
+    __builtin_abort ();
+#endif
+}
--- gcc/testsuite/g++.dg/cpp1z/decomp7.C.jj	2016-11-09 11:19:33.521215800 +0100
+++ gcc/testsuite/g++.dg/cpp1z/decomp7.C	2016-11-09 11:32:12.191544355 +0100
@@ -0,0 +1,60 @@
+// { dg-do run { target c++11 } }
+// { dg-options "" }
+
+int a[2] = { 1, 2 };
+int b[2] = { 4, 5 };
+struct S { int a; signed char b; float c; } sa = { 6, 7, 8.0f };
+S sb = { 9, 10, 11.0f };
+
+template <typename T, typename U>
+void
+foo (T &x, U &y)
+{
+  auto & [ c, d ] = a;		// { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+  auto [ e, f ] = a;		// { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+  auto [ g, h, i ] = sa;	// { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+  auto & [ j, k, l ] = sa;	// { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+  auto & [ m, n ] = x;		// { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+  auto [ o, p ] = x;		// { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+  auto [ q, r, s ] = y;		// { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+  auto & [ t, u, v ] = y;	// { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+  c += 1;
+  e += 2;
+  g += 3;
+  j += 4;
+  m += 5;
+  o += 6;
+  q += 7;
+  t += 8;
+  if (c != 2 || &c != &a[0]
+      || d != 2 || &d != &a[1]
+      || e != 3 || &e == &a[0]
+      || f != 2 || &f == &a[1]
+      || g != 9 || &g == &sa.a
+      || h != 7 || &h == &sa.b
+      || i != 8.0f || &i == &sa.c
+      || j != 10 || &j != &sa.a
+      || k != 7 || &k != &sa.b
+      || l != 8.0f || &l != &sa.c
+      || m != 9 || &m != &b[0]
+      || n != 5 || &n != &b[1]
+      || o != 10 || &o == &b[0]
+      || p != 5 || &p == &b[1]
+      || q != 16 || &q == &sb.a
+      || r != 10 || &r == &sb.b
+      || s != 11.0f || &s == &sb.c
+      || t != 17 || &t != &sb.a
+      || u != 10 || &u != &sb.b
+      || v != 11.0f || &v != &sb.c
+      || a[0] != 2 || a[1] != 2
+      || sa.a != 10 || sa.b != 7 || sa.c != 8.0f
+      || b[0] != 9 || b[1] != 5
+      || sb.a != 17 || sb.b != 10 || sb.c != 11.0f)
+    __builtin_abort ();
+}
+
+int
+main ()
+{
+  foo (b, sb);
+}
--- gcc/testsuite/g++.dg/cpp1z/decomp8.C.jj	2016-11-09 12:11:07.222661321 +0100
+++ gcc/testsuite/g++.dg/cpp1z/decomp8.C	2016-11-09 12:10:56.000000000 +0100
@@ -0,0 +1,88 @@
+// { dg-do run { target c++11 } }
+// { dg-options "" }
+
+struct A { int i; long long j; } a[64];
+A b[32];
+
+template <typename T>
+void
+foo (T &b)
+{
+  int i = 0;
+  for (auto &x : a)
+    {
+      x.i = i;
+      x.j = 2 * i++;
+    }
+  for (auto & [ x, y ] : a)	// { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+    {
+      x += 2;
+      y += 3;
+    }
+  i = 0;
+  for (const auto [ u, v ] : a)	// { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+    {
+      if (u != i + 2 || v != 2 * i++ + 3)
+	__builtin_abort ();
+    }
+  i = 0;
+  for (auto [ x, y ] : a)	// { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+    {
+      x += 4;
+      y += 5;
+      if (x != i + 6 || y != 2 * i++ + 8)
+	__builtin_abort ();
+    }
+  i = 0;
+  for (const auto x : a)
+    {
+      if (x.i != i + 2 || x.j != 2 * i++ + 3)
+	__builtin_abort ();
+    }
+  i = 0;
+  for (auto &x : b)
+    {
+      x.i = i;
+      x.j = 2 * i++;
+    }
+  for (auto & [ x, y ] : b)	// { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+    {
+      x -= 2;
+      y -= 3;
+    }
+  i = 0;
+  for (const auto [ u, v ] : b)	// { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+    {
+      if (u != i - 2 || v != 2 * i++ - 3)
+	__builtin_abort ();
+    }
+  i = 0;
+  for (auto [ x, y ] : b)	// { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
+    {
+      x -= 4;
+      y -= 5;
+      if (x != i - 6 || y != 2 * i++ - 8)
+	__builtin_abort ();
+    }
+  i = 0;
+  for (const auto x : b)
+    {
+      if (x.i != i - 2 || x.j != 2 * i++ - 3)
+	__builtin_abort ();
+    }
+}
+
+int
+main ()
+{
+  foo (b);
+  for (int i = 0; i < 64; i++)
+    {
+      if (a[i].i != i + 2 || a[i].j != 2 * i + 3)
+	__builtin_abort ();
+      if (i >= 32)
+	continue;
+      if (b[i].i != i - 2 || b[i].j != 2 * i - 3)
+	__builtin_abort ();
+    }
+}
