diff options
Diffstat (limited to 'gcc/cp/method.c')
-rw-r--r-- | gcc/cp/method.c | 269 |
1 files changed, 151 insertions, 118 deletions
diff --git a/gcc/cp/method.c b/gcc/cp/method.c index ad41e9acc57..b9511f5a628 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -103,7 +103,7 @@ make_thunk (tree function, bool this_adjusting, /* See if we already have the thunk in question. For this_adjusting thunks VIRTUAL_OFFSET will be an INTEGER_CST, for covariant thunks it will be a BINFO. */ - for (thunk = DECL_THUNKS (function); thunk; thunk = TREE_CHAIN (thunk)) + for (thunk = DECL_THUNKS (function); thunk; thunk = DECL_CHAIN (thunk)) if (DECL_THIS_THUNK_P (thunk) == this_adjusting && THUNK_FIXED_OFFSET (thunk) == d && !virtual_offset == !THUNK_VIRTUAL_OFFSET (thunk) @@ -156,7 +156,7 @@ make_thunk (tree function, bool this_adjusting, DECL_TEMPLATE_INFO (thunk) = NULL; /* Add it to the list of thunks associated with FUNCTION. */ - TREE_CHAIN (thunk) = DECL_THUNKS (function); + DECL_CHAIN (thunk) = DECL_THUNKS (function); DECL_THUNKS (function) = thunk; return thunk; @@ -188,7 +188,7 @@ finish_thunk (tree thunk) tree cov_probe; for (cov_probe = DECL_THUNKS (function); - cov_probe; cov_probe = TREE_CHAIN (cov_probe)) + cov_probe; cov_probe = DECL_CHAIN (cov_probe)) if (DECL_NAME (cov_probe) == name) { gcc_assert (!DECL_THUNKS (thunk)); @@ -364,10 +364,10 @@ use_thunk (tree thunk_fndecl, bool emit_p) /* Set up cloned argument trees for the thunk. */ t = NULL_TREE; - for (a = DECL_ARGUMENTS (function); a; a = TREE_CHAIN (a)) + for (a = DECL_ARGUMENTS (function); a; a = DECL_CHAIN (a)) { tree x = copy_node (a); - TREE_CHAIN (x) = t; + DECL_CHAIN (x) = t; DECL_CONTEXT (x) = thunk_fndecl; SET_DECL_RTL (x, NULL); DECL_HAS_VALUE_EXPR_P (x) = 0; @@ -529,7 +529,7 @@ do_build_copy_constructor (tree fndecl) member_init_list); } - for (; fields; fields = TREE_CHAIN (fields)) + for (; fields; fields = DECL_CHAIN (fields)) { tree field = fields; tree expr_type; @@ -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; @@ -578,7 +579,7 @@ do_build_copy_constructor (tree fndecl) static void do_build_copy_assign (tree fndecl) { - tree parm = TREE_CHAIN (DECL_ARGUMENTS (fndecl)); + tree parm = DECL_CHAIN (DECL_ARGUMENTS (fndecl)); tree compound_stmt; bool move_p = move_fn_p (fndecl); bool trivial = trivial_fn_p (fndecl); @@ -629,7 +630,7 @@ do_build_copy_assign (tree fndecl) /* Assign to each of the non-static data members. */ for (fields = TYPE_FIELDS (current_class_type); fields; - fields = TREE_CHAIN (fields)) + fields = DECL_CHAIN (fields)) { tree comp = current_class_ref; tree init = parm; @@ -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 = DECL_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; @@ -1004,6 +1110,7 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p, #endif assign_p = false; + check_vdtor = false; switch (sfk) { case sfk_move_assignment: @@ -1051,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) { @@ -1059,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)); @@ -1093,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); @@ -1399,7 +1432,7 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p) } /* Add the "this" parameter. */ this_parm = build_this_parm (fn_type, TYPE_UNQUALIFIED); - TREE_CHAIN (this_parm) = DECL_ARGUMENTS (fn); + DECL_CHAIN (this_parm) = DECL_ARGUMENTS (fn); DECL_ARGUMENTS (fn) = this_parm; grokclassfn (type, fn, kind == sfk_destructor ? DTOR_FLAG : NO_SPECIAL); @@ -1592,7 +1625,7 @@ lazily_declare_fn (special_function_kind sfk, tree type) "and may change in a future version of GCC due to " "implicit virtual destructor", type); - TREE_CHAIN (fn) = TYPE_METHODS (type); + DECL_CHAIN (fn) = TYPE_METHODS (type); TYPE_METHODS (type) = fn; } maybe_add_class_template_decl_list (type, fn, /*friend_p=*/0); |