aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/init.c
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2010-07-14 13:00:51 -0400
committerJason Merrill <jason@gcc.gnu.org>2010-07-14 13:00:51 -0400
commit57ece2583335d663e2787df4f6fe3804ec921ea9 (patch)
tree152c38c98a68f7f49ca34046d6b08f92764dea84 /gcc/cp/init.c
parenta9c5db803f4921a59f8a97307df66bd0f546ff42 (diff)
downloadgcc-57ece2583335d663e2787df4f6fe3804ec921ea9.zip
gcc-57ece2583335d663e2787df4f6fe3804ec921ea9.tar.gz
gcc-57ece2583335d663e2787df4f6fe3804ec921ea9.tar.bz2
Implement C++0x unrestricted unions (N2544)
Implement C++0x unrestricted unions (N2544) * class.c (check_field_decl): Loosen union handling in C++0x. * method.c (walk_field_subobs): Split out from... (synthesized_method_walk): ...here. Set msg before loops. (process_subob_fn): Check for triviality in union members. * init.c (sort_mem_initializers): Splice out uninitialized anonymous unions and union members. (push_base_cleanups): Don't automatically destroy anonymous unions and union members. From-SVN: r162187
Diffstat (limited to 'gcc/cp/init.c')
-rw-r--r--gcc/cp/init.c53
1 files changed, 41 insertions, 12 deletions
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 20f921d..4e7cab3 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -708,23 +708,34 @@ sort_mem_initializers (tree t, tree mem_inits)
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. */
+ anonymous unions), the ctor-initializer is ill-formed.
+
+ Here we also splice out uninitialized union members. */
if (uses_unions_p)
{
tree last_field = NULL_TREE;
- for (init = sorted_inits; init; init = TREE_CHAIN (init))
+ tree *p;
+ for (p = &sorted_inits; *p; )
{
tree field;
tree field_type;
int done;
- /* Skip uninitialized members and base classes. */
- if (!TREE_VALUE (init)
- || TREE_CODE (TREE_PURPOSE (init)) != FIELD_DECL)
- continue;
+ init = *p;
+
+ field = TREE_PURPOSE (init);
+
+ /* Skip base classes. */
+ if (TREE_CODE (field) != FIELD_DECL)
+ goto next;
+
+ /* If this is an anonymous union with no explicit initializer,
+ splice it out. */
+ if (!TREE_VALUE (init) && ANON_UNION_TYPE_P (TREE_TYPE (field)))
+ goto splice;
+
/* 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))
@@ -732,14 +743,19 @@ sort_mem_initializers (tree t, tree mem_inits)
break;
/* If this field is not a member of a union, skip it. */
if (TREE_CODE (field_type) != UNION_TYPE)
- continue;
+ goto next;
+
+ /* If this union member has no explicit initializer, splice
+ it out. */
+ if (!TREE_VALUE (init))
+ goto splice;
/* It's only an error if we have two initializers for the same
union type. */
if (!last_field)
{
last_field = field;
- continue;
+ goto next;
}
/* See if LAST_FIELD and the field initialized by INIT are
@@ -785,6 +801,13 @@ sort_mem_initializers (tree t, tree mem_inits)
while (!done);
last_field = field;
+
+ next:
+ p = &TREE_CHAIN (*p);
+ continue;
+ splice:
+ *p = TREE_CHAIN (*p);
+ continue;
}
}
@@ -3353,21 +3376,27 @@ push_base_cleanups (void)
finish_decl_cleanup (NULL_TREE, expr);
}
+ /* Don't automatically destroy union members. */
+ if (TREE_CODE (current_class_type) == UNION_TYPE)
+ return;
+
for (member = TYPE_FIELDS (current_class_type); member;
member = TREE_CHAIN (member))
{
- if (TREE_TYPE (member) == error_mark_node
+ tree this_type = TREE_TYPE (member);
+ if (this_type == error_mark_node
|| TREE_CODE (member) != FIELD_DECL
|| DECL_ARTIFICIAL (member))
continue;
- if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (member)))
+ if (ANON_UNION_TYPE_P (this_type))
+ continue;
+ if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (this_type))
{
tree this_member = (build_class_member_access_expr
(current_class_ref, member,
/*access_path=*/NULL_TREE,
/*preserve_reference=*/false,
tf_warning_or_error));
- tree this_type = TREE_TYPE (member);
expr = build_delete (this_type, this_member,
sfk_complete_destructor,
LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_NORMAL,