static void expand_aggr_init_1 PARAMS ((tree, tree, tree, tree, int));
static void expand_default_init PARAMS ((tree, tree, tree, tree, int));
static tree build_vec_delete_1 PARAMS ((tree, tree, tree, tree, int));
-static void perform_member_init PARAMS ((tree, tree, tree, int));
+static void perform_member_init PARAMS ((tree, tree, int));
static void sort_base_init PARAMS ((tree, tree *, tree *));
static tree build_builtin_delete_call PARAMS ((tree));
static int member_init_ok_or_else PARAMS ((tree, tree, const char *));
static tree build_new_1 PARAMS ((tree));
static tree get_cookie_size PARAMS ((tree));
static tree build_dtor_call PARAMS ((tree, tree, int));
+static tree build_field_list PARAMS ((tree, tree, int *));
/* Set up local variable for this file. MUST BE CALLED AFTER
INIT_DECL_PROCESSING. */
/* Subroutine of emit_base_init. */
static void
-perform_member_init (member, name, init, explicit)
- tree member, name, init;
+perform_member_init (member, init, explicit)
+ tree member, init;
int explicit;
{
tree decl;
tree type = TREE_TYPE (member);
- decl = build_component_ref (current_class_ref, name, NULL_TREE, explicit);
+ decl = build_component_ref (current_class_ref, member, NULL_TREE, explicit);
if (decl == error_mark_node)
return;
synthesized copy constructor. */
if (ANON_AGGR_TYPE_P (type))
{
- init = build (INIT_EXPR, type, decl, TREE_VALUE (init));
- finish_expr_stmt (init);
+ if (init)
+ {
+ init = build (INIT_EXPR, type, decl, TREE_VALUE (init));
+ finish_expr_stmt (init);
+ }
}
else if (TYPE_NEEDS_CONSTRUCTING (type)
|| (init && TYPE_HAS_CONSTRUCTOR (type)))
{
tree expr;
- expr = build_component_ref (current_class_ref, name, NULL_TREE,
+ expr = build_component_ref (current_class_ref, member, NULL_TREE,
explicit);
expr = build_delete (type, expr, integer_zero_node,
LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0);
}
}
+/* Returns a TREE_LIST containing (as the TREE_PURPOSE of each node) all
+ the FIELD_DECLs on the TYPE_FIELDS list for T, in reverse order. */
+
+static tree
+build_field_list (t, list, uses_unions_p)
+ tree t;
+ tree list;
+ int *uses_unions_p;
+{
+ tree fields;
+
+ /* Note whether or not T is a union. */
+ if (TREE_CODE (t) == UNION_TYPE)
+ *uses_unions_p = 1;
+
+ for (fields = TYPE_FIELDS (t); fields; fields = TREE_CHAIN (fields))
+ {
+ /* Skip CONST_DECLs for enumeration constants and so forth. */
+ if (TREE_CODE (fields) != FIELD_DECL)
+ continue;
+
+ /* Keep track of whether or not any fields are unions. */
+ if (TREE_CODE (TREE_TYPE (fields)) == UNION_TYPE)
+ *uses_unions_p = 1;
+
+ /* For an anonymous struct or union, we must recursively
+ consider the fields of the anonymous type. They can be
+ directly initialized from the constructor. */
+ if (ANON_AGGR_TYPE_P (TREE_TYPE (fields)))
+ {
+ /* Add this field itself. Synthesized copy constructors
+ initialize the entire aggregate. */
+ list = tree_cons (fields, NULL_TREE, list);
+ /* And now add the fields in the anonymous aggregate. */
+ list = build_field_list (TREE_TYPE (fields), list,
+ uses_unions_p);
+ }
+ /* Add this field. */
+ else if (DECL_NAME (fields))
+ list = tree_cons (fields, NULL_TREE, list);
+ }
+
+ return list;
+}
+
/* Subroutine of emit_member_init. */
static tree
sort_member_init (t)
tree t;
{
- tree x, member, name, field;
- tree init_list = NULL_TREE;
- int last_pos = 0;
- tree last_field = NULL_TREE;
+ tree init_list;
+ tree last_field;
+ tree init;
+ int uses_unions_p;
+
+ /* Build up a list of the various fields, in sorted order. */
+ init_list = nreverse (build_field_list (t, NULL_TREE, &uses_unions_p));
+
+ /* Go through the explicit initializers, adding them to the
+ INIT_LIST. */
+ last_field = init_list;
+ for (init = current_member_init_list; init; init = TREE_CHAIN (init))
+ {
+ tree f;
+ tree initialized_field;
+
+ initialized_field = TREE_PURPOSE (init);
+ my_friendly_assert (TREE_CODE (initialized_field) == FIELD_DECL,
+ 20000516);
+
+ /* If the explicit initializers are in sorted order, then the
+ INITIALIZED_FIELD will be for a field following the
+ LAST_FIELD. */
+ for (f = last_field; f; f = TREE_CHAIN (f))
+ if (TREE_PURPOSE (f) == initialized_field)
+ break;
+
+ /* Give a warning, if appropriate. */
+ if (warn_reorder && !f)
+ {
+ cp_warning_at ("member initializers for `%#D'", last_field);
+ cp_warning_at (" and `%#D'", initialized_field);
+ warning (" will be re-ordered to match declaration order");
+ }
- for (member = TYPE_FIELDS (t); member ; member = TREE_CHAIN (member))
- {
- int pos;
+ /* Look again, from the beginning of the list. We must find the
+ field on this loop. */
+ if (!f)
+ {
+ f = init_list;
+ while (TREE_PURPOSE (f) != initialized_field)
+ f = TREE_CHAIN (f);
+ }
- /* member could be, for example, a CONST_DECL for an enumerated
- tag; we don't want to try to initialize that, since it already
- has a value. */
- if (TREE_CODE (member) != FIELD_DECL || !DECL_NAME (member))
- continue;
+ /* If there was already an explicit initializer for this field,
+ issue an error. */
+ if (TREE_TYPE (f))
+ cp_error ("multiple initializations given for member `%D'",
+ initialized_field);
+ else
+ {
+ /* Mark the field as explicitly initialized. */
+ TREE_TYPE (f) = error_mark_node;
+ /* And insert the initializer. */
+ TREE_VALUE (f) = TREE_VALUE (init);
+ }
+
+ /* Remember the location of the last explicitly initialized
+ field. */
+ last_field = f;
+ }
+
+ /* [class.base.init]
- for (x = current_member_init_list, pos = 0; x; x = TREE_CHAIN (x), ++pos)
+ If a ctor-initializer specifies more than one mem-initializer for
+ multiple members of the same union (including members of
+ anonymous unions), the ctor-initializer is ill-formed. */
+ if (uses_unions_p)
+ {
+ last_field = NULL_TREE;
+ for (init = init_list; init; init = TREE_CHAIN (init))
{
- /* If we cleared this out, then pay no attention to it. */
- if (TREE_PURPOSE (x) == NULL_TREE)
+ tree field;
+ tree field_type;
+ int done;
+
+ /* Skip uninitialized members. */
+ if (!TREE_TYPE (init))
+ continue;
+ /* See if this field is a member of a union, or a member of a
+ structure contained in a union, etc. */
+ field = TREE_PURPOSE (init);
+ for (field_type = DECL_CONTEXT (field);
+ !same_type_p (field_type, t);
+ field_type = TYPE_CONTEXT (field_type))
+ if (TREE_CODE (field_type) == UNION_TYPE)
+ break;
+ /* If this field is not a member of a union, skip it. */
+ if (TREE_CODE (field_type) != UNION_TYPE)
continue;
- name = TREE_PURPOSE (x);
- if (TREE_CODE (name) == IDENTIFIER_NODE)
- field = IDENTIFIER_CLASS_VALUE (name);
- else
+ /* It's only an error if we have two initializers for the same
+ union type. */
+ if (!last_field)
{
- my_friendly_assert (TREE_CODE (name) == FIELD_DECL, 348);
- field = name;
+ last_field = field;
+ continue;
}
- /* If one member shadows another, get the outermost one. */
- if (TREE_CODE (field) == TREE_LIST)
- field = TREE_VALUE (field);
+ /* See if LAST_FIELD and the field initialized by INIT are
+ members of the same union. If so, there's a problem,
+ unless they're actually members of the same structure
+ which is itself a member of a union. For example, given:
- if (field == member)
+ union { struct { int i; int j; }; };
+
+ initializing both `i' and `j' makes sense. */
+ field_type = DECL_CONTEXT (field);
+ done = 0;
+ do
{
- if (warn_reorder)
+ tree last_field_type;
+
+ last_field_type = DECL_CONTEXT (last_field);
+ while (1)
{
- if (pos < last_pos)
+ if (same_type_p (last_field_type, field_type))
{
- cp_warning_at ("member initializers for `%#D'", last_field);
- cp_warning_at (" and `%#D'", field);
- warning (" will be re-ordered to match declaration order");
+ if (TREE_CODE (field_type) == UNION_TYPE)
+ cp_error ("initializations for multiple members of `%T'",
+ last_field_type);
+ done = 1;
+ break;
}
- last_pos = pos;
- last_field = field;
- }
- /* Make sure we won't try to work on this init again. */
- TREE_PURPOSE (x) = NULL_TREE;
- x = build_tree_list (name, TREE_VALUE (x));
- goto got_it;
- }
- }
+ if (same_type_p (last_field_type, t))
+ break;
- /* If we didn't find MEMBER in the list, create a dummy entry
- so the two lists (INIT_LIST and the list of members) will be
- symmetrical. */
- x = build_tree_list (NULL_TREE, NULL_TREE);
- got_it:
- init_list = chainon (init_list, x);
- }
+ last_field_type = TYPE_CONTEXT (last_field_type);
+ }
+
+ /* If we've reached the outermost class, then we're
+ done. */
+ if (same_type_p (field_type, t))
+ break;
- /* Initializers for base members go at the end. */
- for (x = current_member_init_list ; x ; x = TREE_CHAIN (x))
- {
- name = TREE_PURPOSE (x);
- if (name)
- {
- if (purpose_member (name, init_list))
- {
- cp_error ("multiple initializations given for member `%D'",
- IDENTIFIER_CLASS_VALUE (name));
- continue;
+ field_type = TYPE_CONTEXT (field_type);
}
-
- init_list = chainon (init_list,
- build_tree_list (name, TREE_VALUE (x)));
- TREE_PURPOSE (x) = NULL_TREE;
+ while (!done);
+
+ last_field = field;
}
}
/* Initialize the vtable pointers for the class. */
initialize_vtbl_ptrs (t, current_class_ptr);
- for (member = TYPE_FIELDS (t); member; member = TREE_CHAIN (member))
+ while (mem_init_list)
{
- tree init, name;
+ tree init;
+ tree member;
int from_init_list;
- /* member could be, for example, a CONST_DECL for an enumerated
- tag; we don't want to try to initialize that, since it already
- has a value. */
- if (TREE_CODE (member) != FIELD_DECL || !DECL_NAME (member))
- continue;
+ member = TREE_PURPOSE (mem_init_list);
/* See if we had a user-specified member initialization. */
- if (TREE_PURPOSE (mem_init_list))
+ if (TREE_TYPE (mem_init_list))
{
- name = TREE_PURPOSE (mem_init_list);
init = TREE_VALUE (mem_init_list);
from_init_list = 1;
-
- my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE
- || TREE_CODE (name) == FIELD_DECL, 349);
}
else
{
- name = DECL_NAME (member);
init = DECL_INITIAL (member);
-
from_init_list = 0;
/* Effective C++ rule 12. */
cp_warning ("`%D' should be initialized in the member initialization list", member);
}
- perform_member_init (member, name, init, from_init_list);
- mem_init_list = TREE_CHAIN (mem_init_list);
- }
-
- /* Now initialize any members from our bases. */
- while (mem_init_list)
- {
- tree name, init, field;
-
- if (TREE_PURPOSE (mem_init_list))
- {
- name = TREE_PURPOSE (mem_init_list);
- init = TREE_VALUE (mem_init_list);
-
- if (TREE_CODE (name) == IDENTIFIER_NODE)
- field = IDENTIFIER_CLASS_VALUE (name);
- else
- field = name;
-
- /* If one member shadows another, get the outermost one. */
- if (TREE_CODE (field) == TREE_LIST)
- {
- field = TREE_VALUE (field);
- if (decl_type_context (field) != current_class_type)
- cp_error ("field `%D' not in immediate context", field);
- }
-
- perform_member_init (field, name, init, 1);
- }
+ perform_member_init (member, init, from_init_list);
mem_init_list = TREE_CHAIN (mem_init_list);
}
}
return;
}
- member_init = build_tree_list (name, init);
+ member_init = build_tree_list (field, init);
current_member_init_list = chainon (current_member_init_list, member_init);
}
}