aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/method.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/method.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/method.c')
-rw-r--r--gcc/cp/method.c248
1 files changed, 140 insertions, 108 deletions
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index b09064b..9876af2 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -545,7 +545,8 @@ do_build_copy_constructor (tree fndecl)
}
else if (ANON_AGGR_TYPE_P (expr_type) && TYPE_FIELDS (expr_type))
/* Just use the field; anonymous types can't have
- nontrivial copy ctors or assignment ops. */;
+ nontrivial copy ctors or assignment ops or this
+ function would be deleted. */;
else
continue;
@@ -663,7 +664,8 @@ do_build_copy_assign (tree fndecl)
else if (ANON_AGGR_TYPE_P (expr_type)
&& TYPE_FIELDS (expr_type) != NULL_TREE)
/* Just use the field; anonymous types can't have
- nontrivial copy ctors or assignment ops. */;
+ nontrivial copy ctors or assignment ops or this
+ function would be deleted. */;
else
continue;
@@ -912,8 +914,19 @@ process_subob_fn (tree fn, bool move_p, tree *spec_p, bool *trivial_p,
*spec_p = merge_exception_specifiers (*spec_p, raises);
}
- if (trivial_p && !trivial_fn_p (fn))
- *trivial_p = false;
+ if (!trivial_fn_p (fn))
+ {
+ if (trivial_p)
+ *trivial_p = false;
+ if (TREE_CODE (arg) == FIELD_DECL
+ && TREE_CODE (DECL_CONTEXT (arg)) == UNION_TYPE)
+ {
+ if (deleted_p)
+ *deleted_p = true;
+ if (msg)
+ error ("union member %q+D with non-trivial %qD", arg, fn);
+ }
+ }
if (move_p && !move_fn_p (fn) && !trivial_fn_p (fn))
{
@@ -929,6 +942,99 @@ process_subob_fn (tree fn, bool move_p, tree *spec_p, bool *trivial_p,
*deleted_p = true;
}
+/* Subroutine of synthesized_method_walk to allow recursion into anonymous
+ aggregates. */
+
+static void
+walk_field_subobs (tree fields, tree fnname, special_function_kind sfk,
+ int quals, bool copy_arg_p, bool move_p,
+ bool assign_p, tree *spec_p, bool *trivial_p,
+ bool *deleted_p, const char *msg,
+ int flags, tsubst_flags_t complain)
+{
+ tree field;
+ for (field = fields; field; field = TREE_CHAIN (field))
+ {
+ tree mem_type, argtype, rval;
+
+ if (TREE_CODE (field) != FIELD_DECL
+ || DECL_ARTIFICIAL (field))
+ continue;
+
+ mem_type = strip_array_types (TREE_TYPE (field));
+ if (assign_p)
+ {
+ bool bad = true;
+ if (CP_TYPE_CONST_P (mem_type) && !CLASS_TYPE_P (mem_type))
+ {
+ if (msg)
+ error ("non-static const member %q#D, can't use default "
+ "assignment operator", field);
+ }
+ else if (TREE_CODE (mem_type) == REFERENCE_TYPE)
+ {
+ if (msg)
+ error ("non-static reference member %q#D, can't use "
+ "default assignment operator", field);
+ }
+ else
+ bad = false;
+
+ if (bad && deleted_p)
+ *deleted_p = true;
+ }
+ else if (sfk == sfk_constructor)
+ {
+ bool bad = true;
+ if (CP_TYPE_CONST_P (mem_type)
+ && (!CLASS_TYPE_P (mem_type)
+ || !type_has_user_provided_default_constructor (mem_type)))
+ {
+ if (msg)
+ error ("uninitialized non-static const member %q#D",
+ field);
+ }
+ else if (TREE_CODE (mem_type) == REFERENCE_TYPE)
+ {
+ if (msg)
+ error ("uninitialized non-static reference member %q#D",
+ field);
+ }
+ else
+ bad = false;
+
+ if (bad && deleted_p)
+ *deleted_p = true;
+ }
+
+ if (!CLASS_TYPE_P (mem_type))
+ continue;
+
+ if (ANON_AGGR_TYPE_P (mem_type))
+ {
+ walk_field_subobs (TYPE_FIELDS (mem_type), fnname, sfk, quals,
+ copy_arg_p, move_p, assign_p, spec_p, trivial_p,
+ deleted_p, msg, flags, complain);
+ continue;
+ }
+
+ if (copy_arg_p)
+ {
+ int mem_quals = cp_type_quals (mem_type) | quals;
+ if (DECL_MUTABLE_P (field))
+ mem_quals &= ~TYPE_QUAL_CONST;
+ argtype = build_stub_type (mem_type, mem_quals, move_p);
+ }
+ else
+ argtype = NULL_TREE;
+
+ rval = locate_fn_flags (mem_type, fnname, argtype, flags, complain);
+
+ process_subob_fn (rval, move_p, spec_p, trivial_p, deleted_p,
+ msg, field);
+ }
+}
+
/* The caller wants to generate an implicit declaration of SFK for CTYPE
which is const if relevant and CONST_P is set. If spec_p, trivial_p and
deleted_p are non-null, set their referent appropriately. If diag is
@@ -940,7 +1046,7 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
tree *spec_p, bool *trivial_p, bool *deleted_p,
bool diag)
{
- tree binfo, base_binfo, field, scope, fnname, rval, argtype;
+ tree binfo, base_binfo, scope, fnname, rval, argtype;
bool move_p, copy_arg_p, assign_p, expected_trivial, check_vdtor;
VEC(tree,gc) *vbases;
int i, quals, flags;
@@ -1052,6 +1158,15 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
quals = TYPE_UNQUALIFIED;
argtype = NULL_TREE;
+ if (!diag)
+ msg = NULL;
+ else if (assign_p)
+ msg = ("base %qT does not have a move assignment operator or trivial "
+ "copy assignment operator");
+ else
+ msg = ("base %qT does not have a move constructor or trivial "
+ "copy constructor");
+
for (binfo = TYPE_BINFO (ctype), i = 0;
BINFO_BASE_ITERATE (binfo, i, base_binfo); ++i)
{
@@ -1060,15 +1175,6 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
argtype = build_stub_type (basetype, quals, move_p);
rval = locate_fn_flags (base_binfo, fnname, argtype, flags, complain);
- if (!diag)
- msg = NULL;
- else if (assign_p)
- msg = ("base %qT does not have a move assignment operator or trivial "
- "copy assignment operator");
- else
- msg = ("base %qT does not have a move constructor or trivial "
- "copy constructor");
-
process_subob_fn (rval, move_p, spec_p, trivial_p, deleted_p,
msg, BINFO_TYPE (base_binfo));
@@ -1094,105 +1200,31 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
*deleted_p = true;
}
else if (!assign_p)
- for (i = 0; VEC_iterate (tree, vbases, i, base_binfo); ++i)
- {
- if (copy_arg_p)
- argtype = build_stub_type (BINFO_TYPE (base_binfo), quals, move_p);
- rval = locate_fn_flags (base_binfo, fnname, argtype, flags, complain);
-
- if (!diag)
- msg = NULL;
- else if (assign_p)
- msg = ("virtual base %qT does not have a move assignment "
- "operator or trivial copy assignment operator");
- else
- msg = ("virtual base %qT does not have a move constructor "
- "or trivial copy constructor");
-
- process_subob_fn (rval, move_p, spec_p, trivial_p, deleted_p,
- msg, BINFO_TYPE (base_binfo));
- }
-
- for (field = TYPE_FIELDS (ctype); field; field = TREE_CHAIN (field))
{
- tree mem_type;
-
- if (TREE_CODE (field) != FIELD_DECL
- || DECL_ARTIFICIAL (field))
- continue;
-
- mem_type = strip_array_types (TREE_TYPE (field));
- if (assign_p)
+ if (diag)
+ msg = ("virtual base %qT does not have a move constructor "
+ "or trivial copy constructor");
+ for (i = 0; VEC_iterate (tree, vbases, i, base_binfo); ++i)
{
- bool bad = true;
- if (CP_TYPE_CONST_P (mem_type) && !CLASS_TYPE_P (mem_type))
- {
- if (diag)
- error ("non-static const member %q#D, can't use default "
- "assignment operator", field);
- }
- else if (TREE_CODE (mem_type) == REFERENCE_TYPE)
- {
- if (diag)
- error ("non-static reference member %q#D, can't use "
- "default assignment operator", field);
- }
- else
- bad = false;
+ if (copy_arg_p)
+ argtype = build_stub_type (BINFO_TYPE (base_binfo), quals, move_p);
+ rval = locate_fn_flags (base_binfo, fnname, argtype, flags, complain);
- if (bad && deleted_p)
- *deleted_p = true;
+ process_subob_fn (rval, move_p, spec_p, trivial_p, deleted_p,
+ msg, BINFO_TYPE (base_binfo));
}
- else if (sfk == sfk_constructor)
- {
- bool bad = true;
- if (CP_TYPE_CONST_P (mem_type)
- && (!CLASS_TYPE_P (mem_type)
- || !type_has_user_provided_default_constructor (mem_type)))
- {
- if (diag)
- error ("uninitialized non-static const member %q#D",
- field);
- }
- else if (TREE_CODE (mem_type) == REFERENCE_TYPE)
- {
- if (diag)
- error ("uninitialized non-static reference member %q#D",
- field);
- }
- else
- bad = false;
-
- if (bad && deleted_p)
- *deleted_p = true;
- }
-
- if (!CLASS_TYPE_P (mem_type)
- || ANON_AGGR_TYPE_P (mem_type))
- continue;
-
- if (copy_arg_p)
- {
- int mem_quals = cp_type_quals (mem_type) | quals;
- if (DECL_MUTABLE_P (field))
- mem_quals &= ~TYPE_QUAL_CONST;
- argtype = build_stub_type (mem_type, mem_quals, move_p);
- }
-
- rval = locate_fn_flags (mem_type, fnname, argtype, flags, complain);
-
- if (!diag)
- msg = NULL;
- else if (assign_p)
- msg = ("non-static data member %qD does not have a move "
- "assignment operator or trivial copy assignment operator");
- else
- msg = ("non-static data member %qD does not have a move "
- "constructor or trivial copy constructor");
-
- process_subob_fn (rval, move_p, spec_p, trivial_p, deleted_p,
- msg, field);
}
+ if (!diag)
+ /* Leave msg null. */;
+ else if (assign_p)
+ msg = ("non-static data member %qD does not have a move "
+ "assignment operator or trivial copy assignment operator");
+ else
+ msg = ("non-static data member %qD does not have a move "
+ "constructor or trivial copy constructor");
+ walk_field_subobs (TYPE_FIELDS (ctype), fnname, sfk, quals,
+ copy_arg_p, move_p, assign_p, spec_p, trivial_p,
+ deleted_p, msg, flags, complain);
pop_scope (scope);