@@ -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)
@@ -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);
@@ -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;
@@ -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)
@@ -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;
}
@@ -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,
@@ -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 ();
+}
@@ -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 ();
+}
@@ -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 }
+}
@@ -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 }
+}
@@ -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 ();
+ }
+}
@@ -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
+}
@@ -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);
+}
@@ -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 ();
+ }
+}