+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.
+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
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 */
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)
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. */
(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) \
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). */
cdk_pointer,
cdk_reference,
cdk_ptrmem,
+ cdk_decomp,
cdk_error
};
/* 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. */
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. */
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);
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);
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;
}
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)
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)
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;
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);
case cdk_ptrmem:
break;
+ case cdk_decomp:
+ name = "decomposition";
+ break;
+
case cdk_error:
return error_mark_node;
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
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
attr_flags);
}
- if (declarator->kind == cdk_id)
+ if (declarator->kind == cdk_id || declarator->kind == cdk_decomp)
break;
inner_declarator = 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))
{
{
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. */
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;
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)
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;
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. */
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;
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)
;
{
case cdk_id:
case cdk_array:
+ case cdk_decomp:
found = true;
break;
&& 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;
(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] */
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))
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
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;
}
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;
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;
}
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
&& !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;
}
/* 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))
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:
switch (d->kind)
{
case cdk_id:
+ case cdk_decomp:
case cdk_error:
d = NULL;
break;
return (cp_parser_check_declarator_template_parameters
(parser, declarator->declarator, declarator_location));
+ case cdk_decomp:
case cdk_error:
return true;
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. */
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);
+ }
}
}
}
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);
}
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
error("placeholder constraints not satisfied");
break;
case adc_variable_type:
+ case adc_decomp_type:
error ("deduced initializer does not satisfy "
"placeholder constraints");
break;
"placeholder constraints");
break;
case adc_requirement:
- error ("deduced expression type does not saatisy "
+ error ("deduced expression type does not satisfy "
"placeholder constraints");
break;
}
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. */
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))
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;
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)))
(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)
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