diff options
author | Jason Merrill <jason@redhat.com> | 2010-07-14 13:00:51 -0400 |
---|---|---|
committer | Jason Merrill <jason@gcc.gnu.org> | 2010-07-14 13:00:51 -0400 |
commit | 57ece2583335d663e2787df4f6fe3804ec921ea9 (patch) | |
tree | 152c38c98a68f7f49ca34046d6b08f92764dea84 /gcc/cp/method.c | |
parent | a9c5db803f4921a59f8a97307df66bd0f546ff42 (diff) | |
download | gcc-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.c | 248 |
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); |