diff mbox

[WIP,C++] P0217R3 - C++17 structured bindings

Message ID CADzB+2kza_iUfpFC-sG_Gbwvjp2jX4VFUJd6HXy5Vy54aSrkPg@mail.gmail.com
State New
Headers show

Commit Message

Jason Merrill Nov. 14, 2016, 4:53 a.m. UTC
On Wed, Nov 9, 2016 at 8:05 AM, Jakub Jelinek <jakub@redhat.com> wrote:
> On Wed, Nov 09, 2016 at 01:24:22PM +0100, Jakub Jelinek wrote:
>> The following patch is a WIP on P0217R3 - decomposition declarations.
>> It contains various FIXMEs, Jason, do you think you could finish it up?

Here's what I'm checking in, as a delta from from your patch.  More
testcases would still be welcome.
commit cb763ca9dafb0aa6847bcfcc8ee776dcd78e1abb
Author: Jason Merrill <jason@redhat.com>
Date:   Sat Nov 12 00:15:35 2016 -0800

            Implement P0217R3 - C++17 structured bindings
    
    gcc/cp/
            * cp-tree.h (struct lang_decl_base): Add decomposition_p.
            (DECL_DECOMPOSITION_P): New
            (enum auto_deduction_context): Add adc_decomp_type.
            (enum cp_declarator_kind): Add cdk_decomp.
            * constexpr.c (cxx_eval_constant_expression): Look through
            DECL_VALUE_EXPR.
            (potential_constant_expression_1): Likewise.
            * decl.c (reshape_init): Preserve CONSTRUCTOR_IS_DIRECT_INIT.
            (check_initializer): Use build_aggr_init for DECL_DECOMPOSITION_P.
            (cp_finish_decl): Pass adc_decomp_type for decomposition.
            (find_decomp_class_base, get_tuple_size, get_tuple_element_type)
            (get_tuple_decomp_init, cp_finish_decomp): New.
            (grokdeclarator): Handle decomposition.
            * init.c (build_aggr_init): Handle decomposition array.
            (build_vec_init): Handle initialization from { array }.
            * name-lookup.c (add_function): Always wrap TEMPLATE_DECL in
            OVERLOAD.
            * parser.c (declarator_can_be_parameter_pack): Handle cdk_decomp.
            (function_declarator_p, strip_declarator_types)
            (cp_parser_check_declarator_template_parameters): Likewise.
            (cp_parser_range_for, cp_convert_range_for): Handle decomposition.
            (cp_parser_simple_declaration): Parse decomposition.
            (cp_parser_decomposition_declaration): New.
            * pt.c (tsubst_decomp_names): New.
            (subst_expr) [DECL_EXPR, RANGE_FOR_STMT]: Handle decomposition.
            (do_auto_deduction): Handle adc_decomp_type.
            * semantics.c (finish_decltype_type): Look through DECL_VALUE_EXPR.
            * typeck.c (is_bitfield_expr_with_lowered_type): Likewise.
            * tree.c (lvalue_kind): Likewise.
            (cp_build_reference_type): Handle reference collapsing.

Comments

Jakub Jelinek Nov. 14, 2016, 7:11 a.m. UTC | #1
On Sun, Nov 13, 2016 at 11:53:10PM -0500, Jason Merrill wrote:
> On Wed, Nov 9, 2016 at 8:05 AM, Jakub Jelinek <jakub@redhat.com> wrote:
> > On Wed, Nov 09, 2016 at 01:24:22PM +0100, Jakub Jelinek wrote:
> >> The following patch is a WIP on P0217R3 - decomposition declarations.
> >> It contains various FIXMEs, Jason, do you think you could finish it up?
> 
> Here's what I'm checking in, as a delta from from your patch.  More
> testcases would still be welcome.

Thanks, I'll try to add some more testsuite coverage in stage3.
But, it seems you haven't checked the testcases (except for the modification
of existing one).

	Jakub
Jakub Jelinek Nov. 14, 2016, 7:55 a.m. UTC | #2
On Mon, Nov 14, 2016 at 08:11:25AM +0100, Jakub Jelinek wrote:
> On Sun, Nov 13, 2016 at 11:53:10PM -0500, Jason Merrill wrote:
> > On Wed, Nov 9, 2016 at 8:05 AM, Jakub Jelinek <jakub@redhat.com> wrote:
> > > On Wed, Nov 09, 2016 at 01:24:22PM +0100, Jakub Jelinek wrote:
> > >> The following patch is a WIP on P0217R3 - decomposition declarations.
> > >> It contains various FIXMEs, Jason, do you think you could finish it up?
> > 
> > Here's what I'm checking in, as a delta from from your patch.  More
> > testcases would still be welcome.
> 
> Thanks, I'll try to add some more testsuite coverage in stage3.
> But, it seems you haven't checked the testcases (except for the modification
> of existing one).

I've checked them in now after retesting them.

	Jakub
diff mbox

Patch

diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 739e902..e8c7702 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -3770,7 +3770,7 @@  cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
       return (*ctx->values->get (t));
 
     case VAR_DECL:
-      if (is_capture_proxy (t))
+      if (DECL_HAS_VALUE_EXPR_P (t))
 	return cxx_eval_constant_expression (ctx, DECL_VALUE_EXPR (t),
 					     lval, non_constant_p, overflow_p);
       /* fall through */
@@ -5037,6 +5037,8 @@  potential_constant_expression_1 (tree t, bool want_rval, bool strict,
       return RECUR (TREE_OPERAND (t, 0), rval);
 
     case VAR_DECL:
+      if (DECL_HAS_VALUE_EXPR_P (t))
+	return RECUR (DECL_VALUE_EXPR (t), rval);
       if (want_rval
 	  && !var_in_maybe_constexpr_fn (t)
 	  && !type_dependent_expression_p (t)
diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c
index f44bd32..9b9b511 100644
--- a/gcc/cp/cp-gimplify.c
+++ b/gcc/cp/cp-gimplify.c
@@ -617,14 +617,6 @@  cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
 	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,
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index e684996..f142c1f 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -6074,6 +6074,10 @@  reshape_init (tree type, tree init, tsubst_flags_t complain)
 	return error_mark_node;
     }
 
+  if (CONSTRUCTOR_IS_DIRECT_INIT (init)
+      && BRACE_ENCLOSED_INITIALIZER_P (new_init))
+    CONSTRUCTOR_IS_DIRECT_INIT (new_init) = true;
+
   return new_init;
 }
 
@@ -6194,15 +6198,6 @@  check_initializer (tree decl, tree init, int flags, vec<tree, va_gc> **cleanups)
       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)
@@ -6263,7 +6258,8 @@  check_initializer (tree decl, tree init, int flags, vec<tree, va_gc> **cleanups)
       if (type == error_mark_node)
 	return NULL_TREE;
 
-      if ((type_build_ctor_call (type) || CLASS_TYPE_P (type))
+      if ((type_build_ctor_call (type) || CLASS_TYPE_P (type)
+	   || (DECL_DECOMPOSITION_P (decl) && TREE_CODE (type) == ARRAY_TYPE))
 	  && !(flags & LOOKUP_ALREADY_DIGESTED)
 	  && !(init && BRACE_ENCLOSED_INITIALIZER_P (init)
 	       && CP_AGGREGATE_TYPE_P (type)
@@ -7183,7 +7179,6 @@  find_decomp_class_base (location_t loc, tree type, tree ret)
     else
       member_seen = true;
 
-  /* FIXME: How to deal with virtual bases etc.?  */
   tree base_binfo, binfo;
   tree orig_ret = ret;
   int i;
@@ -7206,6 +7201,9 @@  find_decomp_class_base (location_t loc, tree type, tree ret)
 	    }
 	  else if (orig_ret != NULL_TREE)
 	    return t;
+	  else if (ret == t)
+	    /* OK, found the same base along another path.  We'll complain
+	       in convert_to_base if it's ambiguous.  */;
 	  else if (ret != NULL_TREE)
 	    {
 	      error_at (loc, "cannot decompose class type %qT: its base "
@@ -7214,13 +7212,87 @@  find_decomp_class_base (location_t loc, tree type, tree ret)
 	      return error_mark_node;
 	    }
 	  else
-	    /* FIXME: Check if this is thru a private base?  */
 	    ret = t;
 	}
     }
   return ret;
 }
 
+/* Return std::tuple_size<TYPE>::value.  */
+
+tree
+get_tuple_size (tree type)
+{
+  tree args = make_tree_vec (1);
+  TREE_VEC_ELT (args, 0) = type;
+  tree inst = lookup_template_class (get_identifier ("tuple_size"), args,
+				     /*in_decl*/NULL_TREE,
+				     /*context*/std_node,
+				     /*entering_scope*/false, tf_none);
+  tree val = lookup_qualified_name (inst, get_identifier ("value"),
+				    /*type*/false, /*complain*/false);
+  if (TREE_CODE (val) == VAR_DECL || TREE_CODE (val) == CONST_DECL)
+    val = maybe_constant_value (val);
+  if (TREE_CODE (val) == INTEGER_CST)
+    return val;
+  else
+    return NULL_TREE;
+}
+
+/* Return std::tuple_element<I,TYPE>::type.  */
+
+tree
+get_tuple_element_type (tree type, unsigned i)
+{
+  tree args = make_tree_vec (2);
+  TREE_VEC_ELT (args, 0) = build_int_cst (integer_type_node, i);
+  TREE_VEC_ELT (args, 1) = type;
+  tree inst = lookup_template_class (get_identifier ("tuple_element"), args,
+				     /*in_decl*/NULL_TREE,
+				     /*context*/std_node,
+				     /*entering_scope*/false,
+				     tf_warning_or_error);
+  return make_typename_type (inst, get_identifier ("type"),
+			     none_type, tf_warning_or_error);
+}
+
+/* Return e.get<i>() or get<i>(e).  */
+
+tree
+get_tuple_decomp_init (tree decl, unsigned i)
+{
+  tree get_id = get_identifier ("get");
+  tree targs = make_tree_vec (1);
+  TREE_VEC_ELT (targs, 0) = build_int_cst (integer_type_node, i);
+
+  tree etype = TREE_TYPE (decl);
+  tree e = convert_from_reference (decl);
+
+  /* [The id-expression] e is an lvalue if the type of the entity e is an
+     lvalue reference and an xvalue otherwise.  */
+  if (TREE_CODE (etype) != REFERENCE_TYPE
+      || TYPE_REF_IS_RVALUE (etype))
+    e = move (e);
+
+  tree fns = lookup_qualified_name (TREE_TYPE (e), get_id,
+				    /*type*/false, /*complain*/false);
+  if (fns != error_mark_node)
+    {
+      fns = lookup_template_function (fns, targs);
+      return build_new_method_call (e, fns, /*args*/NULL,
+				    /*path*/NULL_TREE, LOOKUP_NORMAL,
+				    /*fn_p*/NULL, tf_warning_or_error);
+    }
+  else
+    {
+      vec<tree,va_gc> *args = make_tree_vector_single (e);
+      fns = lookup_template_function (get_id, targs);
+      fns = perform_koenig_lookup (fns, args, tf_warning_or_error);
+      return finish_call_expr (fns, &args, /*novirt*/false,
+			       /*koenig*/true, tf_warning_or_error);
+    }
+}
+
 /* 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
@@ -7366,6 +7438,41 @@  cp_finish_decomp (tree decl, tree first, unsigned int count)
 	  DECL_HAS_VALUE_EXPR_P (v[i]) = 1;
 	}
     }
+  else if (tree tsize = get_tuple_size (type))
+    {
+      eltscnt = tree_to_uhwi (tsize);
+      if (count != eltscnt)
+	goto cnt_mismatch;
+      for (unsigned i = 0; i < count; ++i)
+	{
+	  location_t sloc = input_location;
+	  location_t dloc = DECL_SOURCE_LOCATION (v[i]);
+
+	  input_location = dloc;
+	  tree init = get_tuple_decomp_init (decl, i);
+	  tree eltype = (init == error_mark_node ? error_mark_node
+			 : get_tuple_element_type (type, i));
+	  input_location = sloc;
+
+	  if (init == error_mark_node || eltype == error_mark_node)
+	    {
+	      inform (dloc, "in initialization of decomposition variable %qD",
+		      v[i]);
+	      goto error_out;
+	    }
+	  eltype = cp_build_reference_type (eltype, !lvalue_p (init));
+	  TREE_TYPE (v[i]) = eltype;
+	  layout_decl (v[i], 0);
+	  if (DECL_HAS_VALUE_EXPR_P (v[i]))
+	    {
+	      /* In this case the names are variables, not just proxies.  */
+	      SET_DECL_VALUE_EXPR (v[i], NULL_TREE);
+	      DECL_HAS_VALUE_EXPR_P (v[i]) = 0;
+	    }
+	  cp_finish_decl (v[i], init, /*constexpr*/false,
+			  /*asm*/NULL_TREE, LOOKUP_NORMAL);
+	}
+    }
   else if (TREE_CODE (type) == UNION_TYPE)
     {
       error_at (loc, "cannot decompose union type %qT", type);
@@ -7378,10 +7485,6 @@  cp_finish_decomp (tree decl, tree first, unsigned int count)
     }
   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;
@@ -7399,22 +7502,24 @@  cp_finish_decomp (tree decl, tree first, unsigned int count)
       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);
+      if (type != btype)
+	{
+	  t = convert_to_base (t, btype, /*check_access*/true,
+			       /*nonnull*/false, tf_warning_or_error);
+	  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;
+	    tree tt = finish_non_static_data_member (field, t, NULL_TREE);
+	    tree probe = tt;
+	    if (REFERENCE_REF_P (probe))
+	      probe = TREE_OPERAND (probe, 0);
+	    TREE_TYPE (v[i]) = TREE_TYPE (probe);
 	    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++;
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 5eba4c3..1fad79c 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -1575,27 +1575,34 @@  build_aggr_init (tree exp, tree init, int flags, tsubst_flags_t complain)
 
   if (TREE_CODE (type) == ARRAY_TYPE)
     {
-      tree itype;
+      tree itype = init ? TREE_TYPE (init) : NULL_TREE;
+      int from_array = 0;
 
-      /* An array may not be initialized use the parenthesized
-	 initialization form -- unless the initializer is "()".  */
-      if (init && TREE_CODE (init) == TREE_LIST)
+      if (VAR_P (exp) && DECL_DECOMPOSITION_P (exp))
+	from_array = 1;
+      else
 	{
-          if (complain & tf_error)
-            error ("bad array initializer");
-	  return error_mark_node;
+	  /* An array may not be initialized use the parenthesized
+	     initialization form -- unless the initializer is "()".  */
+	  if (init && TREE_CODE (init) == TREE_LIST)
+	    {
+	      if (complain & tf_error)
+		error ("bad array initializer");
+	      return error_mark_node;
+	    }
+	  /* Must arrange to initialize each element of EXP
+	     from elements of INIT.  */
+	  if (cv_qualified_p (type))
+	    TREE_TYPE (exp) = cv_unqualified (type);
+	  if (itype && cv_qualified_p (itype))
+	    TREE_TYPE (init) = cv_unqualified (itype);
+	  from_array = (itype && same_type_p (TREE_TYPE (init),
+					      TREE_TYPE (exp)));
 	}
-      /* Must arrange to initialize each element of EXP
-	 from elements of INIT.  */
-      itype = init ? TREE_TYPE (init) : NULL_TREE;
-      if (cv_qualified_p (type))
-	TREE_TYPE (exp) = cv_unqualified (type);
-      if (itype && cv_qualified_p (itype))
-	TREE_TYPE (init) = cv_unqualified (itype);
+
       stmt_expr = build_vec_init (exp, NULL_TREE, init,
 				  /*explicit_value_init_p=*/false,
-				  itype && same_type_p (TREE_TYPE (init),
-							TREE_TYPE (exp)),
+				  from_array,
                                   complain);
       TREE_READONLY (exp) = was_const;
       TREE_THIS_VOLATILE (exp) = was_volatile;
@@ -3891,6 +3898,18 @@  build_vec_init (tree base, tree maxindex, tree init,
   base = get_temp_regvar (ptype, rval);
   iterator = get_temp_regvar (ptrdiff_type_node, maxindex);
 
+  bool direct_init = false;
+  if (from_array && init && BRACE_ENCLOSED_INITIALIZER_P (init)
+      && CONSTRUCTOR_NELTS (init) == 1)
+    {
+      tree elt = CONSTRUCTOR_ELT (init, 0)->value;
+      if (TREE_CODE (TREE_TYPE (elt)) == ARRAY_TYPE)
+	{
+	  direct_init = DIRECT_LIST_INIT_P (init);
+	  init = elt;
+	}
+    }
+
   /* If initializing one array from another, initialize element by
      element.  We rely upon the below calls to do the argument
      checking.  Evaluate the initializer before entering the try block.  */
@@ -4115,6 +4134,8 @@  build_vec_init (tree base, tree maxindex, tree init,
 	      from = build1 (INDIRECT_REF, itype, base2);
 	      if (xvalue)
 		from = move (from);
+	      if (direct_init)
+		from = build_tree_list (NULL_TREE, from);
 	    }
 	  else
 	    from = NULL_TREE;
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index 172ec82..7ad65b8 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -5393,7 +5393,7 @@  add_function (struct arg_lookup *k, tree fn)
        function templates are ignored.  */;
   else if (k->fn_set && k->fn_set->add (fn))
     /* It's already in the list.  */;
-  else if (!k->functions)
+  else if (!k->functions && TREE_CODE (fn) != TEMPLATE_DECL)
     k->functions = fn;
   else if (fn == k->functions)
     ;
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 6033a13..978245b 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -12876,9 +12876,6 @@  cp_parser_decomposition_declaration (cp_parser *parser,
   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;
@@ -12909,6 +12906,10 @@  cp_parser_decomposition_declaration (cp_parser *parser,
 	}
     }
 
+  if (cxx_dialect < cxx1z)
+    pedwarn (loc, 0, "decomposition declaration only available with "
+		     "-std=c++1z or -std=gnu++1z");
+
   tree pushed_scope;
   cp_declarator *declarator = make_declarator (cdk_decomp);
   loc = end_loc == UNKNOWN_LOCATION ? loc : make_location (loc, loc, end_loc);
@@ -12934,8 +12935,9 @@  cp_parser_decomposition_declaration (cp_parser *parser,
       else
 	declarator->u.id.unqualified_name = e.get_value ();
       declarator->id_loc = e.get_location ();
+      tree elt_pushed_scope;
       tree decl2 = start_decl (declarator, &decl_specs, SD_INITIALIZED,
-			       NULL_TREE, NULL_TREE, &pushed_scope);
+			       NULL_TREE, NULL_TREE, &elt_pushed_scope);
       if (decl2 == error_mark_node)
 	decl = error_mark_node;
       else if (decl != error_mark_node && DECL_CHAIN (decl2) != prev)
@@ -12947,6 +12949,8 @@  cp_parser_decomposition_declaration (cp_parser *parser,
 	}
       else
 	prev = decl2;
+      if (elt_pushed_scope)
+	pop_scope (elt_pushed_scope);
     }
 
   if (v.is_empty ())
@@ -12990,6 +12994,9 @@  cp_parser_decomposition_declaration (cp_parser *parser,
       cp_finish_decomp (decl, prev, v.length ());
     }
 
+  if (pushed_scope)
+    pop_scope (pushed_scope);
+
   return decl;
 }
 
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index d390bf4..0164f2e 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -8873,6 +8873,9 @@  finish_decltype_type (tree expr, bool id_expression_or_member_access_p,
       if (identifier_p (expr))
         expr = lookup_name (expr);
 
+      if (VAR_P (expr) && DECL_HAS_VALUE_EXPR_P (expr))
+	expr = DECL_VALUE_EXPR (expr);
+
       if (INDIRECT_REF_P (expr))
         /* This can happen when the expression is, e.g., "a.b". Just
            look at the underlying operand.  */
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 7872dd2..c595437 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -142,6 +142,9 @@  lvalue_kind (const_tree ref)
 	return clk_none;
       /* FALLTHRU */
     case VAR_DECL:
+      if (DECL_HAS_VALUE_EXPR_P (ref))
+	return lvalue_kind (DECL_VALUE_EXPR (CONST_CAST_TREE (ref)));
+
       if (TREE_READONLY (ref) && ! TREE_STATIC (ref)
 	  && DECL_LANG_SPECIFIC (ref)
 	  && DECL_IN_AGGR_P (ref))
@@ -1012,6 +1015,13 @@  tree
 cp_build_reference_type (tree to_type, bool rval)
 {
   tree lvalue_ref, t;
+
+  if (TREE_CODE (to_type) == REFERENCE_TYPE)
+    {
+      rval = rval && TYPE_REF_IS_RVALUE (to_type);
+      to_type = TREE_TYPE (to_type);
+    }
+
   lvalue_ref = build_reference_type (to_type);
   if (!rval)
     return lvalue_ref;
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 24ca1b5..2d8b7b1 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -1885,6 +1885,12 @@  is_bitfield_expr_with_lowered_type (const_tree exp)
 	return DECL_BIT_FIELD_TYPE (field);
       }
 
+    case VAR_DECL:
+      if (DECL_HAS_VALUE_EXPR_P (exp))
+	return is_bitfield_expr_with_lowered_type (DECL_VALUE_EXPR
+						   (CONST_CAST_TREE (exp)));
+      return NULL_TREE;
+
     CASE_CONVERT:
       if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (exp, 0)))
 	  == TYPE_MAIN_VARIANT (TREE_TYPE (exp)))
diff --git a/gcc/testsuite/g++.dg/cpp1z/decomp10.C b/gcc/testsuite/g++.dg/cpp1z/decomp10.C
new file mode 100644
index 0000000..316cea9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/decomp10.C
@@ -0,0 +1,48 @@ 
+// { dg-options -std=c++1z }
+
+namespace std {
+  template<typename T> struct tuple_size;
+  template<int, typename> struct tuple_element;
+}
+
+struct A1 { int i,j; } a1;
+template<> struct std::tuple_size<A1> {  };
+void f1() { auto [ x ] = a1; }	// { dg-error "decomposes into 2" }
+
+struct A2 { int i,j; } a2;
+template<> struct std::tuple_size<A2> { enum { value = 5 }; };
+void f2() { auto [ x ] = a2; }	// { dg-error "decomposes into 5" }
+
+struct A3 { int i,j; } a3;
+template<> struct std::tuple_size<A3> { enum { value = 1 }; };
+void f3() { auto [ x ] = a3; }	// { dg-error "get" }
+
+struct A3a { int i,j; int get(); } a3a;
+template<> struct std::tuple_size<A3a> { enum { value = 1 }; };
+void f3a() { auto [ x ] = a3a; }	// { dg-error "get<0>" }
+
+struct A3b { int i,j; } a3b;
+int get(A3b&&);
+template<> struct std::tuple_size<A3b> { enum { value = 1 }; };
+void f3b() { auto [ x ] = a3b; }	// { dg-error "get<0>" }
+
+struct A4 {
+  int ar[3];
+  template <int I> int& get() { return ar[I]; }
+} a4;
+template<> struct std::tuple_size<A4> { enum { value = 3 }; };
+template <int I> 
+void f4() { auto [ x, y, z ] = a4; }	// { dg-error "tuple_element" }
+
+struct A5 { } a5;
+template <int I> int& get(A5&& a);
+template<> struct std::tuple_size<A5> { enum { value = 3 }; };
+template <int I> 
+void f5() { auto [ x, y, z ] = a5; }	// { dg-error "tuple_element" }
+
+struct A6 { } a6;
+template <int I> int& get(A6&& a);
+template<> struct std::tuple_size<A6> { enum { value = 3 }; };
+template<> struct std::tuple_element<0, A6> { };
+template <int I> 
+void f6() { auto [ x, y, z ] = a6; }	// { dg-error "no type named .type" }
diff --git a/gcc/testsuite/g++.dg/cpp1z/decomp6.C b/gcc/testsuite/g++.dg/cpp1z/decomp6.C
index b2ab657..ed6fce4 100644
--- a/gcc/testsuite/g++.dg/cpp1z/decomp6.C
+++ b/gcc/testsuite/g++.dg/cpp1z/decomp6.C
@@ -13,15 +13,6 @@  struct A
   int a;
 };
 
-// FIXME: without this dummy function the testcase fails to link.
-void
-fixme ()
-{
-  A x1;
-  A x2 = x1;
-  A x3 { x1 };
-}
-
 int
 main ()
 {
@@ -62,14 +53,13 @@  main ()
   }
   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 } }
+      auto [b,c,d,e,f,g] { a };		// { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
       if (ccnt != 12 || dcnt != 12 || cccnt != 6 || tccnt != 6)
 	__builtin_abort ();
       b.a++;
@@ -80,7 +70,7 @@  main ()
       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 } }
+	auto&[ h, i, j, k, l, m ] {a};	// { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
 	if (ccnt != 12 || dcnt != 12 || cccnt != 6 || tccnt != 6)
 	  __builtin_abort ();
 	j.a += 4;
@@ -99,5 +89,4 @@  main ()
   }
   if (ccnt != 12 || dcnt != 24 || cccnt != 6 || tccnt != 6)
     __builtin_abort ();
-#endif
 }
diff --git a/gcc/testsuite/g++.dg/cpp1z/decomp9.C b/gcc/testsuite/g++.dg/cpp1z/decomp9.C
new file mode 100644
index 0000000..f7c6f56
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/decomp9.C
@@ -0,0 +1,47 @@ 
+// { dg-do run }
+// { dg-options -std=c++1z }
+
+#define assert(X) do { if (!(X)) __builtin_abort(); } while (0)
+
+namespace std {
+  template<typename T> struct tuple_size;
+  template<int, typename> struct tuple_element;
+}
+
+struct A {
+  int i;
+  template <int I> int& get() { return i; }
+};
+
+template<> struct std::tuple_size<A> { static const int value = 2; };
+template<int I> struct std::tuple_element<I,A> { using type = int; };
+
+struct B {
+  int i;
+};
+template <int I> int& get(B&& b) { return b.i; }
+template <int I> int& get(B& b) { return b.i; }
+
+template<> struct std::tuple_size<B> { static const int value = 2; };
+template<int I> struct std::tuple_element<I,B> { using type = int; };
+
+int main()
+{
+  {
+    A a = { 42 };
+    auto& [ x, y ] = a;
+    assert (&x == &y && &x == &a.i && x == 42);
+
+    auto [ x2, y2 ] = a;
+    assert (&x2 == &y2 && &x2 != &a.i && x2 == 42);
+  }
+
+  {
+    B b = { 42 };
+    auto& [ x, y ] = b;
+    assert (&x == &y && &x == &b.i && x == 42);
+
+    auto [ x2, y2 ] = b;
+    assert (&x2 == &y2 && &x2 != &b.i && x2 == 42);
+  }
+}
diff --git a/gcc/testsuite/g++.dg/parse/parser-pr14875-2.C b/gcc/testsuite/g++.dg/parse/parser-pr14875-2.C
index 3510aac..d2e5382 100644
--- a/gcc/testsuite/g++.dg/parse/parser-pr14875-2.C
+++ b/gcc/testsuite/g++.dg/parse/parser-pr14875-2.C
@@ -15,7 +15,7 @@ 
   CHECK (xor_eq);   // { dg-error "before .xor_eq. token" }
 #undef CHECK
 #define CHECK(x)  int x
-  CHECK (<:);     // { dg-error "before .<:. token" }
+  CHECK (<:);     // { dg-error "" }
   CHECK (:>);     // { dg-error "before .:>. token" }
 #undef CHECK
 #define CHECK(x)  x