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