diff options
author | Jason Merrill <jason@redhat.com> | 2010-06-29 20:50:57 -0400 |
---|---|---|
committer | Jason Merrill <jason@gcc.gnu.org> | 2010-06-29 20:50:57 -0400 |
commit | ac1774315cb7ebc781ade2f9fd99de1c258b9221 (patch) | |
tree | 0e8e64d29daa126b9fc1f87bfe35a0967270da6d /gcc/cp/method.c | |
parent | 4640884658bae7ba9ff09068efcbe4b7e94baf8d (diff) | |
download | gcc-ac1774315cb7ebc781ade2f9fd99de1c258b9221.zip gcc-ac1774315cb7ebc781ade2f9fd99de1c258b9221.tar.gz gcc-ac1774315cb7ebc781ade2f9fd99de1c258b9221.tar.bz2 |
Machinery to support implicit delete/move.
* cp-tree.h: (struct lang_type_class): Add lazy_move_assign,
has_complex_move_ctor, has_complex_move_assign bitfields.
(CLASSTYPE_LAZY_MOVE_ASSIGN): New.
(TYPE_HAS_COMPLEX_MOVE_ASSIGN): New.
(TYPE_HAS_COMPLEX_MOVE_CTOR): New.
(enum special_function_kind): Add sfk_move_assignment.
(LOOKUP_SPECULATIVE): New.
* call.c (build_over_call): Return early if it's set.
(build_over_call): Use trivial_fn_p.
* class.c (check_bases): If the base has no default constructor,
the derived one is non-trivial. Handle move ctor/op=.
(check_field_decl): Likewise.
(check_bases_and_members): Handle move ctor/op=.
(add_implicitly_declared_members): Handle CLASSTYPE_LAZY_MOVE_ASSIGN.
(type_has_move_constructor, type_has_move_assign): New.
* decl.c (grok_special_member_properties): Handle move ctor/op=.
* method.c (type_has_trivial_fn, type_set_nontrivial_flag): New.
(trivial_fn_p): New.
(do_build_copy_constructor): Use it.
(do_build_assign_ref): Likewise. Handle move assignment.
(build_stub_type, build_stub_object, locate_fn_flags): New.
(locate_ctor): Use locate_fn_flags.
(locate_copy, locate_dtor): Remove.
(get_dtor, get_default_ctor, get_copy_ctor, get_copy_assign): New.
(process_subob_fn, synthesized_method_walk): New.
(maybe_explain_implicit_delete): New.
(implicitly_declare_fn): Use synthesized_method_walk,
type_has_trivial_fn, and type_set_nontrivial_flag.
(defaulted_late_check): Set DECL_DELETED_FN.
(defaultable_fn_check): Handle sfk_move_assignment.
(lazily_declare_fn): Clear CLASSTYPE_LAZY_* early. Don't declare
implicitly deleted move ctor/op=.
* search.c (lookup_fnfields_1): Handle sfk_move_assignment.
(lookup_fnfields_slot): New.
* semantics.c (omp_clause_info_fndecl): Remove.
(cxx_omp_create_clause_info): Use get_default_ctor, get_copy_ctor,
get_copy_assign, trivial_fn_p.
(trait_expr_value): Adjust call to locate_ctor.
* tree.c (special_function_p): Handle sfk_move_assignment.
From-SVN: r161579
Diffstat (limited to 'gcc/cp/method.c')
-rw-r--r-- | gcc/cp/method.c | 757 |
1 files changed, 598 insertions, 159 deletions
diff --git a/gcc/cp/method.c b/gcc/cp/method.c index 96a1d54..64f7b7f 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -59,7 +59,6 @@ typedef enum mangling_flags mangling_flags; static void do_build_copy_assign (tree); static void do_build_copy_constructor (tree); -static tree synthesize_exception_spec (tree, tree (*) (tree, void *), void *); static tree make_alias_for_thunk (tree); /* Called once to initialize method.c. */ @@ -400,6 +399,74 @@ use_thunk (tree thunk_fndecl, bool emit_p) /* Code for synthesizing methods which have default semantics defined. */ +/* True iff CTYPE has a trivial SFK. */ + +static bool +type_has_trivial_fn (tree ctype, special_function_kind sfk) +{ + switch (sfk) + { + case sfk_constructor: + return !TYPE_HAS_COMPLEX_DFLT (ctype); + case sfk_copy_constructor: + return !TYPE_HAS_COMPLEX_COPY_CTOR (ctype); + case sfk_move_constructor: + return !TYPE_HAS_COMPLEX_MOVE_CTOR (ctype); + case sfk_copy_assignment: + return !TYPE_HAS_COMPLEX_COPY_ASSIGN (ctype); + case sfk_move_assignment: + return !TYPE_HAS_COMPLEX_MOVE_ASSIGN (ctype); + case sfk_destructor: + return !TYPE_HAS_NONTRIVIAL_DESTRUCTOR (ctype); + default: + gcc_unreachable (); + } +} + +/* Note that CTYPE has a non-trivial SFK even though we previously thought + it was trivial. */ + +static void +type_set_nontrivial_flag (tree ctype, special_function_kind sfk) +{ + switch (sfk) + { + case sfk_constructor: + TYPE_HAS_COMPLEX_DFLT (ctype) = true; + return; + case sfk_copy_constructor: + TYPE_HAS_COMPLEX_COPY_CTOR (ctype) = true; + return; + case sfk_move_constructor: + TYPE_HAS_COMPLEX_MOVE_CTOR (ctype) = true; + return; + case sfk_copy_assignment: + TYPE_HAS_COMPLEX_COPY_ASSIGN (ctype) = true; + return; + case sfk_move_assignment: + TYPE_HAS_COMPLEX_MOVE_ASSIGN (ctype) = true; + return; + case sfk_destructor: + TYPE_HAS_NONTRIVIAL_DESTRUCTOR (ctype) = true; + return; + default: + gcc_unreachable (); + } +} + +/* True iff FN is a trivial defaulted member function ([cd]tor, op=). */ + +bool +trivial_fn_p (tree fn) +{ + if (!DECL_DEFAULTED_FN (fn)) + return false; + + /* If fn is a clone, get the primary variant. */ + fn = DECL_ORIGIN (fn); + return type_has_trivial_fn (DECL_CONTEXT (fn), special_function_p (fn)); +} + /* Generate code for default X(X&) or X(X&&) constructor. */ static void @@ -407,14 +474,15 @@ do_build_copy_constructor (tree fndecl) { tree parm = FUNCTION_FIRST_USER_PARM (fndecl); bool move_p = DECL_MOVE_CONSTRUCTOR_P (fndecl); + bool trivial = trivial_fn_p (fndecl); parm = convert_from_reference (parm); - if (TYPE_HAS_TRIVIAL_COPY_CTOR (current_class_type) + if (trivial && is_empty_class (current_class_type)) /* Don't copy the padding byte; it might not have been allocated if *this is a base subobject. */; - else if (TYPE_HAS_TRIVIAL_COPY_CTOR (current_class_type)) + else if (trivial) { tree t = build2 (INIT_EXPR, void_type_node, current_class_ref, parm); finish_expr_stmt (t); @@ -512,15 +580,17 @@ do_build_copy_assign (tree fndecl) { tree parm = TREE_CHAIN (DECL_ARGUMENTS (fndecl)); tree compound_stmt; + bool move_p = move_fn_p (fndecl); + bool trivial = trivial_fn_p (fndecl); compound_stmt = begin_compound_stmt (0); parm = convert_from_reference (parm); - if (TYPE_HAS_TRIVIAL_COPY_ASSIGN (current_class_type) + if (trivial && is_empty_class (current_class_type)) /* Don't copy the padding byte; it might not have been allocated if *this is a base subobject. */; - else if (TYPE_HAS_TRIVIAL_COPY_ASSIGN (current_class_type)) + else if (trivial) { tree t = build2 (MODIFY_EXPR, void_type_node, current_class_ref, parm); finish_expr_stmt (t); @@ -542,6 +612,8 @@ do_build_copy_assign (tree fndecl) /* We must convert PARM directly to the base class explicitly since the base class may be ambiguous. */ converted_parm = build_base_path (PLUS_EXPR, parm, base_binfo, 1); + if (move_p) + converted_parm = move (converted_parm); /* Call the base class assignment operator. */ parmvec = make_tree_vector_single (converted_parm); finish_expr_stmt @@ -604,6 +676,8 @@ do_build_copy_assign (tree fndecl) expr_type = cp_build_qualified_type (expr_type, quals); init = build3 (COMPONENT_REF, expr_type, init, field, NULL_TREE); + if (move_p && TREE_CODE (expr_type) != REFERENCE_TYPE) + init = move (init); if (DECL_NAME (field)) init = cp_build_modify_expr (comp, NOP_EXPR, init, @@ -695,163 +769,505 @@ synthesize_method (tree fndecl) fndecl); } -/* Use EXTRACTOR to locate the relevant function called for each base & - class field of TYPE. CLIENT allows additional information to be passed - to EXTRACTOR. Generates the union of all exceptions generated by those - functions. Note that we haven't updated TYPE_FIELDS and such of any - variants yet, so we need to look at the main one. */ +/* Build a reference to type TYPE with cv-quals QUALS, which is an + rvalue if RVALUE is true. */ static tree -synthesize_exception_spec (tree type, tree (*extractor) (tree, void*), - void *client) +build_stub_type (tree type, int quals, bool rvalue) { - tree raises = empty_except_spec; - tree fields = TYPE_FIELDS (type); - tree binfo, base_binfo; - int i; + tree argtype = cp_build_qualified_type (type, quals); + return cp_build_reference_type (argtype, rvalue); +} - for (binfo = TYPE_BINFO (type), i = 0; - BINFO_BASE_ITERATE (binfo, i, base_binfo); i++) - { - tree fn = (*extractor) (BINFO_TYPE (base_binfo), client); - if (fn) - { - tree fn_raises = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn)); +/* Build a dummy glvalue from dereferencing a dummy reference of type + REFTYPE. */ - raises = merge_exception_specifiers (raises, fn_raises); - } - } - for (; fields; fields = TREE_CHAIN (fields)) - { - tree type = TREE_TYPE (fields); - tree fn; +static tree +build_stub_object (tree reftype) +{ + tree stub = build1 (NOP_EXPR, reftype, integer_one_node); + return convert_from_reference (stub); +} - if (TREE_CODE (fields) != FIELD_DECL || DECL_ARTIFICIAL (fields)) - continue; - while (TREE_CODE (type) == ARRAY_TYPE) - type = TREE_TYPE (type); - if (!CLASS_TYPE_P (type)) - continue; +/* Determine which function will be called when looking up NAME in TYPE, + called with a single ARGTYPE argument, or no argument if ARGTYPE is + null. FLAGS and COMPLAIN are as for build_new_method_call. - fn = (*extractor) (type, client); - if (fn) - { - tree fn_raises = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn)); + Returns a FUNCTION_DECL if all is well. + Returns NULL_TREE if overload resolution failed. + Returns error_mark_node if the chosen function cannot be called. */ - raises = merge_exception_specifiers (raises, fn_raises); - } +static tree +locate_fn_flags (tree type, tree name, tree argtype, int flags, + tsubst_flags_t complain) +{ + tree ob, fn, fns, binfo, rval; + VEC(tree,gc) *args; + + if (TYPE_P (type)) + binfo = TYPE_BINFO (type); + else + { + binfo = type; + type = BINFO_TYPE (binfo); + } + + ob = build_stub_object (cp_build_reference_type (type, false)); + args = make_tree_vector (); + if (argtype) + { + tree arg = build_stub_object (argtype); + VEC_quick_push (tree, args, arg); } - return raises; + + fns = lookup_fnfields (binfo, name, 0); + rval = build_new_method_call (ob, fns, &args, binfo, flags, &fn, complain); + + release_tree_vector (args); + if (fn && rval == error_mark_node) + return rval; + else + return fn; } /* Locate the dtor of TYPE. */ tree -locate_dtor (tree type, void *client ATTRIBUTE_UNUSED) +get_dtor (tree type) { - return CLASSTYPE_DESTRUCTORS (type); + tree fn = locate_fn_flags (type, complete_dtor_identifier, NULL_TREE, + LOOKUP_NORMAL, tf_warning_or_error); + if (fn == error_mark_node) + return NULL_TREE; + return fn; } /* Locate the default ctor of TYPE. */ tree -locate_ctor (tree type, void *client ATTRIBUTE_UNUSED) +locate_ctor (tree type) { - tree fns; + tree fn = locate_fn_flags (type, complete_ctor_identifier, NULL_TREE, + LOOKUP_SPECULATIVE, tf_none); + if (fn == error_mark_node) + return NULL_TREE; + return fn; +} + +/* Likewise, but give any appropriate errors. */ - if (!TYPE_HAS_DEFAULT_CONSTRUCTOR (type)) +tree +get_default_ctor (tree type) +{ + tree fn = locate_fn_flags (type, complete_ctor_identifier, NULL_TREE, + LOOKUP_NORMAL, tf_warning_or_error); + if (fn == error_mark_node) + return NULL_TREE; + return fn; +} + +/* Locate the copy ctor of TYPE. */ + +tree +get_copy_ctor (tree type) +{ + int quals = (TYPE_HAS_CONST_COPY_CTOR (type) + ? TYPE_QUAL_CONST : TYPE_UNQUALIFIED); + tree argtype = build_stub_type (type, quals, false); + tree fn = locate_fn_flags (type, complete_ctor_identifier, argtype, + LOOKUP_NORMAL, tf_warning_or_error); + if (fn == error_mark_node) return NULL_TREE; + return fn; +} - /* Call lookup_fnfields_1 to create the constructor declarations, if - necessary. */ - if (CLASSTYPE_LAZY_DEFAULT_CTOR (type)) - return lazily_declare_fn (sfk_constructor, type); +/* Locate the copy assignment operator of TYPE. */ - for (fns = CLASSTYPE_CONSTRUCTORS (type); fns; fns = OVL_NEXT (fns)) +tree +get_copy_assign (tree type) +{ + int quals = (TYPE_HAS_CONST_COPY_ASSIGN (type) + ? TYPE_QUAL_CONST : TYPE_UNQUALIFIED); + tree argtype = build_stub_type (type, quals, false); + tree fn = locate_fn_flags (type, ansi_assopname (NOP_EXPR), argtype, + LOOKUP_NORMAL, tf_warning_or_error); + if (fn == error_mark_node) + return NULL_TREE; + return fn; +} + +/* Subroutine of synthesized_method_walk. Update SPEC_P, TRIVIAL_P and + DELETED_P or give an error message MSG with argument ARG. */ + +static void +process_subob_fn (tree fn, bool move_p, tree *spec_p, bool *trivial_p, + bool *deleted_p, const char *msg, tree arg) +{ + if (!fn || fn == error_mark_node) + goto bad; + + if (spec_p) { - tree fn = OVL_CURRENT (fns); - tree parms = TYPE_ARG_TYPES (TREE_TYPE (fn)); + tree raises = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn)); + *spec_p = merge_exception_specifiers (*spec_p, raises); + } - parms = skip_artificial_parms_for (fn, parms); + if (trivial_p && !trivial_fn_p (fn)) + *trivial_p = false; - if (sufficient_parms_p (parms)) - return fn; + if (move_p && !move_fn_p (fn) && !trivial_fn_p (fn)) + { + if (msg) + error (msg, arg); + goto bad; } - gcc_unreachable (); + + return; + + bad: + if (deleted_p) + *deleted_p = true; } -struct copy_data +/* 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 + true, we're being called from maybe_explain_implicit_delete to give + errors. */ + +static void +synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p, + tree *spec_p, bool *trivial_p, bool *deleted_p, + bool diag) { - tree name; - int quals; -}; + tree binfo, base_binfo, field, scope, fnname, rval, argtype; + bool move_p, copy_arg_p, assign_p, expected_trivial, check_vdtor; + VEC(tree,gc) *vbases; + int i, quals, flags; + tsubst_flags_t complain; + const char *msg; + + if (spec_p) + *spec_p = (cxx_dialect >= cxx0x + ? noexcept_true_spec : empty_except_spec); + + if (deleted_p) + { + /* "The closure type associated with a lambda-expression has a deleted + default constructor and a deleted copy assignment operator." + This is diagnosed in maybe_explain_implicit_delete. */ + if (LAMBDA_TYPE_P (ctype) + && (sfk == sfk_constructor + || sfk == sfk_copy_assignment)) + { + *deleted_p = true; + return; + } -/* Locate the copy ctor or copy assignment of TYPE. CLIENT_ - points to a COPY_DATA holding the name (NULL for the ctor) - and desired qualifiers of the source operand. */ + *deleted_p = false; + } -tree -locate_copy (tree type, void *client_) -{ - struct copy_data *client = (struct copy_data *)client_; - tree fns; - tree best = NULL_TREE; - bool excess_p = false; + move_p = false; + switch (sfk) + { + case sfk_constructor: + case sfk_destructor: + copy_arg_p = false; + break; + + case sfk_move_constructor: + case sfk_move_assignment: + move_p = true; + case sfk_copy_constructor: + case sfk_copy_assignment: + copy_arg_p = true; + break; + + default: + gcc_unreachable (); + } + + expected_trivial = type_has_trivial_fn (ctype, sfk); + if (trivial_p) + *trivial_p = expected_trivial; + +#ifndef ENABLE_CHECKING + /* The TYPE_HAS_COMPLEX_* flags tell us about constraints from base + class versions and other properties of the type. But a subobject + class can be trivially copyable and yet have overload resolution + choose a template constructor for initialization, depending on + rvalueness and cv-quals. So we can't exit early for copy/move + methods in C++0x. */ + if (expected_trivial + && (!copy_arg_p || cxx_dialect < cxx0x)) + return; +#endif - if (client->name) + assign_p = false; + switch (sfk) { - int ix; - ix = lookup_fnfields_1 (type, client->name); - if (ix < 0) - return NULL_TREE; - fns = VEC_index (tree, CLASSTYPE_METHOD_VEC (type), ix); + case sfk_move_assignment: + case sfk_copy_assignment: + assign_p = true; + fnname = ansi_assopname (NOP_EXPR); + break; + + case sfk_destructor: + check_vdtor = true; + /* The synthesized method will call base dtors, but check complete + here to avoid having to deal with VTT. */ + fnname = complete_dtor_identifier; + break; + + case sfk_constructor: + case sfk_move_constructor: + case sfk_copy_constructor: + fnname = complete_ctor_identifier; + break; + + default: + gcc_unreachable (); } - else if (TYPE_HAS_COPY_CTOR (type)) + + ++cp_unevaluated_operand; + ++c_inhibit_evaluation_warnings; + + scope = push_scope (ctype); + + if (diag) { - /* If construction of the copy constructor was postponed, create - it now. */ - if (CLASSTYPE_LAZY_COPY_CTOR (type)) - lazily_declare_fn (sfk_copy_constructor, type); - if (CLASSTYPE_LAZY_MOVE_CTOR (type)) - lazily_declare_fn (sfk_move_constructor, type); - fns = CLASSTYPE_CONSTRUCTORS (type); + flags = LOOKUP_NORMAL|LOOKUP_SPECULATIVE; + complain = tf_warning_or_error; } else - return NULL_TREE; - for (; fns; fns = OVL_NEXT (fns)) { - tree fn = OVL_CURRENT (fns); - tree parms = TYPE_ARG_TYPES (TREE_TYPE (fn)); - tree src_type; - int excess; - int quals; - - parms = skip_artificial_parms_for (fn, parms); - if (!parms) - continue; - src_type = non_reference (TREE_VALUE (parms)); + flags = LOOKUP_PROTECT|LOOKUP_SPECULATIVE; + complain = tf_none; + } - if (src_type == error_mark_node) - return NULL_TREE; + if (const_p) + quals = TYPE_QUAL_CONST; + else + quals = TYPE_UNQUALIFIED; + argtype = NULL_TREE; - if (!same_type_ignoring_top_level_qualifiers_p (src_type, type)) - continue; - if (!sufficient_parms_p (TREE_CHAIN (parms))) + for (binfo = TYPE_BINFO (ctype), i = 0; + BINFO_BASE_ITERATE (binfo, i, base_binfo); ++i) + { + tree basetype = BINFO_TYPE (base_binfo); + if (copy_arg_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)); + + if (check_vdtor && type_has_virtual_destructor (basetype)) + { + rval = locate_fn_flags (ctype, ansi_opname (DELETE_EXPR), + ptr_type_node, flags, complain); + /* Unlike for base ctor/op=/dtor, for operator delete it's fine + to have a null rval (no class-specific op delete). */ + if (rval && rval == error_mark_node && deleted_p) + *deleted_p = true; + } + } + + vbases = CLASSTYPE_VBASECLASSES (ctype); + if (vbases && assign_p && move_p) + { + /* Should the spec be changed to allow vbases that only occur once? */ + if (diag) + error ("%qT has virtual bases, default move assignment operator " + "cannot be generated", ctype); + else if (deleted_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; - quals = cp_type_quals (src_type); - if (client->quals & ~quals) + + 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 (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 (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 (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; - excess = quals & ~client->quals; - if (!best || (excess_p && !excess)) + + if (copy_arg_p) { - best = fn; - excess_p = excess; + 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 - /* Ambiguous */ - return NULL_TREE; + 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); } - return best; + + pop_scope (scope); + + --cp_unevaluated_operand; + --c_inhibit_evaluation_warnings; + +#ifdef ENABLE_CHECKING + /* If we expected this to be trivial but it isn't, then either we're in + C++0x mode and this is a copy/move ctor/op= or there's an error. */ + gcc_assert (!(trivial_p && expected_trivial && !*trivial_p) + || (copy_arg_p && cxx_dialect >= cxx0x) + || errorcount); +#endif +} + +/* DECL is a deleted function. If it's implicitly deleted, explain why and + return true; else return false. */ + +bool +maybe_explain_implicit_delete (tree decl) +{ + /* If decl is a clone, get the primary variant. */ + decl = DECL_ORIGIN (decl); + gcc_assert (DECL_DELETED_FN (decl)); + if (DECL_DEFAULTED_FN (decl) + && DECL_INITIAL (decl) == NULL_TREE) + { + /* Not marked GTY; it doesn't need to be GC'd or written to PCH. */ + static htab_t explained_htab; + void **slot; + + special_function_kind sfk; + location_t loc; + bool informed; + tree ctype; + + if (!explained_htab) + explained_htab = htab_create (37, htab_hash_pointer, + htab_eq_pointer, NULL); + slot = htab_find_slot (explained_htab, decl, INSERT); + if (*slot) + return true; + *slot = decl; + + sfk = special_function_p (decl); + ctype = DECL_CONTEXT (decl); + loc = input_location; + input_location = DECL_SOURCE_LOCATION (decl); + + informed = false; + if (LAMBDA_TYPE_P (ctype)) + { + informed = true; + if (sfk == sfk_constructor) + error ("a lambda closure type has a deleted default constructor"); + else if (sfk == sfk_copy_assignment) + error ("a lambda closure type has a deleted copy assignment operator"); + else + informed = false; + } + if (!informed) + { + tree parm_type = TREE_VALUE (FUNCTION_FIRST_USER_PARMTYPE (decl)); + bool const_p = CP_TYPE_CONST_P (non_reference (parm_type)); + tree scope = push_scope (ctype); + error ("%qD is implicitly deleted because the default " + "definition would be ill-formed:", decl); + pop_scope (scope); + synthesized_method_walk (ctype, sfk, const_p, + NULL, NULL, NULL, true); + } + + input_location = loc; + return true; + } + return false; } /* Implicitly declare the special function indicated by KIND, as a @@ -872,6 +1288,8 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p) tree this_parm; tree name; HOST_WIDE_INT saved_processing_template_decl; + bool deleted_p; + bool trivial_p; /* Because we create declarations for implicitly declared functions lazily, we may be creating the declaration for a member of TYPE @@ -903,50 +1321,49 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p) case sfk_destructor: /* Destructor. */ name = constructor_name (type); - raises = synthesize_exception_spec (type, &locate_dtor, 0); break; case sfk_constructor: /* Default constructor. */ name = constructor_name (type); - raises = synthesize_exception_spec (type, &locate_ctor, 0); break; case sfk_copy_constructor: case sfk_copy_assignment: case sfk_move_constructor: + case sfk_move_assignment: { - struct copy_data data; - - data.name = NULL; - data.quals = 0; - if (kind == sfk_copy_assignment) + bool move_p; + if (kind == sfk_copy_assignment + || kind == sfk_move_assignment) { return_type = build_reference_type (type); name = ansi_assopname (NOP_EXPR); - data.name = name; } else name = constructor_name (type); if (const_p) - { - data.quals = TYPE_QUAL_CONST; - rhs_parm_type = cp_build_qualified_type (type, TYPE_QUAL_CONST); - } + rhs_parm_type = cp_build_qualified_type (type, TYPE_QUAL_CONST); else rhs_parm_type = type; - rhs_parm_type - = cp_build_reference_type (rhs_parm_type, - kind == sfk_move_constructor); + move_p = (kind == sfk_move_assignment + || kind == sfk_move_constructor); + rhs_parm_type = cp_build_reference_type (rhs_parm_type, move_p); + parameter_types = tree_cons (NULL_TREE, rhs_parm_type, parameter_types); - raises = synthesize_exception_spec (type, &locate_copy, &data); break; } default: gcc_unreachable (); } + synthesized_method_walk (type, kind, const_p, &raises, &trivial_p, + &deleted_p, false); + + if (!trivial_p && type_has_trivial_fn (type, kind)) + type_set_nontrivial_flag (type, kind); + /* Create the function. */ fn_type = build_method_type_directly (type, return_type, parameter_types); if (raises) @@ -1031,6 +1448,9 @@ defaulted_late_check (tree fn) tree eh_spec = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (implicit_fn)); TREE_TYPE (fn) = build_exception_variant (TREE_TYPE (fn), eh_spec); } + + if (DECL_DELETED_FN (implicit_fn)) + DECL_DELETED_FN (fn) = 1; } /* Returns true iff FN can be explicitly defaulted, and gives any @@ -1055,9 +1475,13 @@ defaultable_fn_check (tree fn) else if (DECL_DESTRUCTOR_P (fn)) kind = sfk_destructor; else if (DECL_ASSIGNMENT_OPERATOR_P (fn) - && DECL_OVERLOADED_OPERATOR_P (fn) == NOP_EXPR - && copy_fn_p (fn)) - kind = sfk_copy_assignment; + && DECL_OVERLOADED_OPERATOR_P (fn) == NOP_EXPR) + { + if (copy_fn_p (fn)) + kind = sfk_copy_assignment; + else if (move_fn_p (fn)) + kind = sfk_move_assignment; + } if (kind == sfk_none) { @@ -1103,21 +1527,48 @@ tree lazily_declare_fn (special_function_kind sfk, tree type) { tree fn; - bool const_p; - - /* Figure out whether or not the argument has a const reference - type. */ - if (sfk == sfk_copy_constructor) - const_p = TYPE_HAS_CONST_COPY_CTOR (type); - else if (sfk == sfk_copy_assignment) - const_p = TYPE_HAS_CONST_COPY_ASSIGN (type); - else - /* In this case, CONST_P will be ignored. */ - const_p = false; + /* Whether or not the argument has a const reference type. */ + bool const_p = false; + + switch (sfk) + { + case sfk_constructor: + CLASSTYPE_LAZY_DEFAULT_CTOR (type) = 0; + break; + case sfk_copy_constructor: + const_p = TYPE_HAS_CONST_COPY_CTOR (type); + CLASSTYPE_LAZY_COPY_CTOR (type) = 0; + break; + case sfk_move_constructor: + CLASSTYPE_LAZY_MOVE_CTOR (type) = 0; + break; + case sfk_copy_assignment: + const_p = TYPE_HAS_CONST_COPY_ASSIGN (type); + CLASSTYPE_LAZY_COPY_ASSIGN (type) = 0; + break; + case sfk_move_assignment: + CLASSTYPE_LAZY_MOVE_ASSIGN (type) = 0; + break; + case sfk_destructor: + CLASSTYPE_LAZY_DESTRUCTOR (type) = 0; + break; + default: + gcc_unreachable (); + } + /* Declare the function. */ fn = implicitly_declare_fn (sfk, type, const_p); + + /* For move variants, rather than declare them as deleted we just + don't declare them at all. */ + if (DECL_DELETED_FN (fn) + && (sfk == sfk_move_constructor + || sfk == sfk_move_assignment)) + return NULL_TREE; + /* A destructor may be virtual. */ if (sfk == sfk_destructor + || sfk == sfk_move_assignment || sfk == sfk_copy_assignment) check_for_override (fn, type); /* Add it to CLASSTYPE_METHOD_VEC. */ @@ -1143,22 +1594,10 @@ lazily_declare_fn (special_function_kind sfk, tree type) TYPE_METHODS (type) = fn; } maybe_add_class_template_decl_list (type, fn, /*friend_p=*/0); - if (sfk == sfk_copy_assignment) - CLASSTYPE_LAZY_COPY_ASSIGN (type) = 0; - else - { - /* Remember that the function has been created. */ - if (sfk == sfk_constructor) - CLASSTYPE_LAZY_DEFAULT_CTOR (type) = 0; - else if (sfk == sfk_copy_constructor) - CLASSTYPE_LAZY_COPY_CTOR (type) = 0; - else if (sfk == sfk_move_constructor) - CLASSTYPE_LAZY_MOVE_CTOR (type) = 0; - else if (sfk == sfk_destructor) - CLASSTYPE_LAZY_DESTRUCTOR (type) = 0; - /* Create appropriate clones. */ - clone_function_decl (fn, /*update_method_vec=*/true); - } + if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (fn) + || DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (fn)) + /* Create appropriate clones. */ + clone_function_decl (fn, /*update_method_vec=*/true); return fn; } |