On Wed, Nov 9, 2016 at 8:05 AM, Jakub Jelinek <ja...@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 <ja...@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.

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

Reply via email to