Implement P0217R3 - C++17 structured bindings
gcc/ * match.pd: Don't try to compare addresses of variables with DECL_VALUE_EXPR. 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. Co-Authored-By: Jason Merrill <jason@redhat.com> From-SVN: r242377
This commit is contained in:
parent
e7555e42d0
commit
70f40fea6a
@ -1,3 +1,8 @@
|
||||
2016-11-13 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* match.pd: Don't try to compare addresses of variables with
|
||||
DECL_VALUE_EXPR.
|
||||
|
||||
2016-11-13 Kugan Vivekanandarajah <kuganv@linaro.org>
|
||||
|
||||
* ipa-cp.c (ipa_get_jf_pass_through_result): Skip unary expressions.
|
||||
|
@ -1,3 +1,38 @@
|
||||
2016-11-13 Jakub Jelinek <jakub@redhat.com>
|
||||
Jason Merrill <jason@redhat.com>
|
||||
|
||||
Implement P0217R3 - C++17 structured bindings
|
||||
* 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.
|
||||
|
||||
2016-11-13 Jason Merrill <jason@redhat.com>
|
||||
|
||||
* call.c (build_new_method_call_1): Include template arguments in
|
||||
|
@ -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)
|
||||
|
@ -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_init_expr_arg_iterator *iter)
|
||||
(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) \
|
||||
@ -5165,7 +5176,8 @@ enum auto_deduction_context
|
||||
adc_variable_type, /* Variable initializer deduction */
|
||||
adc_return_type, /* Return type deduction */
|
||||
adc_unify, /* Template argument deduction */
|
||||
adc_requirement /* Argument dedution constraint */
|
||||
adc_requirement, /* Argument deduction constraint */
|
||||
adc_decomp_type /* Decomposition declaration initializer deduction */
|
||||
};
|
||||
|
||||
/* True iff this TEMPLATE_TYPE_PARM represents decltype(auto). */
|
||||
@ -5382,6 +5394,7 @@ enum cp_declarator_kind {
|
||||
cdk_pointer,
|
||||
cdk_reference,
|
||||
cdk_ptrmem,
|
||||
cdk_decomp,
|
||||
cdk_error
|
||||
};
|
||||
|
||||
@ -5412,7 +5425,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. */
|
||||
@ -5421,8 +5435,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. */
|
||||
@ -5794,6 +5808,7 @@ extern tree start_decl (const cp_declarator *, cp_decl_specifier_seq *, int,
|
||||
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);
|
||||
@ -6066,7 +6081,7 @@ extern tree implicitly_declare_fn (special_function_kind, tree,
|
||||
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);
|
||||
|
||||
|
516
gcc/cp/decl.c
516
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;
|
||||
}
|
||||
|
||||
@ -6254,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)
|
||||
@ -6770,10 +6775,11 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
|
||||
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)
|
||||
@ -7137,6 +7143,390 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
|
||||
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;
|
||||
|
||||
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 == 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 "
|
||||
"classes %qT and %qT have non-static data "
|
||||
"members", type, ret, t);
|
||||
return error_mark_node;
|
||||
}
|
||||
else
|
||||
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
|
||||
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 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);
|
||||
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
|
||||
{
|
||||
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);
|
||||
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 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);
|
||||
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;
|
||||
@ -9449,7 +9839,7 @@ grokdeclarator (const cp_declarator *declarator,
|
||||
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);
|
||||
@ -9650,6 +10040,10 @@ grokdeclarator (const cp_declarator *declarator,
|
||||
case cdk_ptrmem:
|
||||
break;
|
||||
|
||||
case cdk_decomp:
|
||||
name = "decomposition";
|
||||
break;
|
||||
|
||||
case cdk_error:
|
||||
return error_mark_node;
|
||||
|
||||
@ -9859,15 +10253,15 @@ grokdeclarator (const cp_declarator *declarator,
|
||||
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
|
||||
@ -10093,6 +10487,79 @@ grokdeclarator (const cp_declarator *declarator,
|
||||
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
|
||||
@ -10232,7 +10699,7 @@ grokdeclarator (const cp_declarator *declarator,
|
||||
attr_flags);
|
||||
}
|
||||
|
||||
if (declarator->kind == cdk_id)
|
||||
if (declarator->kind == cdk_id || declarator->kind == cdk_decomp)
|
||||
break;
|
||||
|
||||
inner_declarator = declarator->declarator;
|
||||
@ -10743,6 +11210,7 @@ grokdeclarator (const cp_declarator *declarator,
|
||||
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))
|
||||
{
|
||||
@ -10754,13 +11222,14 @@ grokdeclarator (const cp_declarator *declarator,
|
||||
{
|
||||
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. */
|
||||
@ -11133,7 +11602,8 @@ grokdeclarator (const cp_declarator *declarator,
|
||||
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;
|
||||
@ -11719,6 +12189,14 @@ grokdeclarator (const cp_declarator *declarator,
|
||||
|
||||
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)
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
;
|
||||
|
239
gcc/cp/parser.c
239
gcc/cp/parser.c
@ -1668,6 +1668,7 @@ declarator_can_be_parameter_pack (cp_declarator *declarator)
|
||||
{
|
||||
case cdk_id:
|
||||
case cdk_array:
|
||||
case cdk_decomp:
|
||||
found = true;
|
||||
break;
|
||||
|
||||
@ -1721,6 +1722,7 @@ function_declarator_p (const cp_declarator *declarator)
|
||||
&& 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] */
|
||||
|
||||
@ -11471,16 +11475,45 @@ cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl,
|
||||
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))
|
||||
@ -11491,11 +11524,12 @@ cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl,
|
||||
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
|
||||
@ -11516,7 +11550,8 @@ cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl,
|
||||
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;
|
||||
}
|
||||
@ -11608,6 +11643,7 @@ do_range_for_auto_deduction (tree decl, tree range_expr)
|
||||
|
||||
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;
|
||||
@ -11681,6 +11717,8 @@ cp_convert_range_for (tree statement, tree range_decl, tree range_expr,
|
||||
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;
|
||||
}
|
||||
@ -12554,6 +12592,8 @@ cp_parser_block_declaration (cp_parser *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
|
||||
@ -12639,6 +12679,45 @@ cp_parser_simple_declaration (cp_parser* 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;
|
||||
@ -12791,6 +12870,7 @@ cp_parser_simple_declaration (cp_parser* 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))
|
||||
@ -12806,6 +12886,143 @@ cp_parser_simple_declaration (cp_parser* 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);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
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 elt_pushed_scope;
|
||||
tree decl2 = start_decl (declarator, &decl_specs, SD_INITIALIZED,
|
||||
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)
|
||||
{
|
||||
/* 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 (elt_pushed_scope)
|
||||
pop_scope (elt_pushed_scope);
|
||||
}
|
||||
|
||||
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 ());
|
||||
}
|
||||
|
||||
if (pushed_scope)
|
||||
pop_scope (pushed_scope);
|
||||
|
||||
return decl;
|
||||
}
|
||||
|
||||
/* Parse a decl-specifier-seq.
|
||||
|
||||
decl-specifier-seq:
|
||||
@ -18628,6 +18845,7 @@ strip_declarator_types (tree type, cp_declarator *declarator)
|
||||
switch (d->kind)
|
||||
{
|
||||
case cdk_id:
|
||||
case cdk_decomp:
|
||||
case cdk_error:
|
||||
d = NULL;
|
||||
break;
|
||||
@ -25502,6 +25720,7 @@ cp_parser_check_declarator_template_parameters (cp_parser* parser,
|
||||
return (cp_parser_check_declarator_template_parameters
|
||||
(parser, declarator->declarator, declarator_location));
|
||||
|
||||
case cdk_decomp:
|
||||
case cdk_error:
|
||||
return true;
|
||||
|
||||
|
85
gcc/cp/pt.c
85
gcc/cp/pt.c
@ -15311,6 +15311,55 @@ tsubst_find_omp_teams (tree *tp, int *walk_subtrees, void *)
|
||||
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. */
|
||||
|
||||
@ -15454,6 +15503,16 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -15481,7 +15540,18 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
|
||||
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);
|
||||
}
|
||||
@ -24800,7 +24870,15 @@ do_auto_deduction (tree type, tree init, tree auto_node,
|
||||
|
||||
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
|
||||
@ -24885,6 +24963,7 @@ do_auto_deduction (tree type, tree init, tree auto_node,
|
||||
error("placeholder constraints not satisfied");
|
||||
break;
|
||||
case adc_variable_type:
|
||||
case adc_decomp_type:
|
||||
error ("deduced initializer does not satisfy "
|
||||
"placeholder constraints");
|
||||
break;
|
||||
@ -24893,7 +24972,7 @@ do_auto_deduction (tree type, tree init, tree auto_node,
|
||||
"placeholder constraints");
|
||||
break;
|
||||
case adc_requirement:
|
||||
error ("deduced expression type does not saatisy "
|
||||
error ("deduced expression type does not satisfy "
|
||||
"placeholder constraints");
|
||||
break;
|
||||
}
|
||||
|
@ -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. */
|
||||
|
@ -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;
|
||||
|
@ -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)))
|
||||
|
11
gcc/match.pd
11
gcc/match.pd
@ -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)
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user