Commit ac177431 by Jason Merrill Committed by Jason Merrill

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
parent 46408846
2010-06-29 Jason Merrill <jason@redhat.com> 2010-06-29 Jason Merrill <jason@redhat.com>
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.
* class.c (type_has_virtual_destructor): New. * class.c (type_has_virtual_destructor): New.
* cp-tree.h: Declare it. * cp-tree.h: Declare it.
* semantics.c (trait_expr_value): Use it. * semantics.c (trait_expr_value): Use it.
......
...@@ -5613,6 +5613,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) ...@@ -5613,6 +5613,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
if (DECL_FUNCTION_MEMBER_P (fn)) if (DECL_FUNCTION_MEMBER_P (fn))
{ {
tree access_fn;
/* If FN is a template function, two cases must be considered. /* If FN is a template function, two cases must be considered.
For example: For example:
...@@ -5640,10 +5641,41 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) ...@@ -5640,10 +5641,41 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
different access. */ different access. */
if (DECL_TEMPLATE_INFO (fn) if (DECL_TEMPLATE_INFO (fn)
&& DECL_MEMBER_TEMPLATE_P (DECL_TI_TEMPLATE (fn))) && DECL_MEMBER_TEMPLATE_P (DECL_TI_TEMPLATE (fn)))
perform_or_defer_access_check (cand->access_path, access_fn = DECL_TI_TEMPLATE (fn);
DECL_TI_TEMPLATE (fn), fn);
else else
perform_or_defer_access_check (cand->access_path, fn, fn); access_fn = fn;
if (flags & LOOKUP_SPECULATIVE)
{
/* If we're checking for implicit delete, we don't want access
control errors. */
if (!accessible_p (cand->access_path, access_fn, true))
{
/* Unless we're under maybe_explain_implicit_delete. */
if (flags & LOOKUP_COMPLAIN)
enforce_access (cand->access_path, access_fn, fn);
return error_mark_node;
}
}
else
perform_or_defer_access_check (cand->access_path, access_fn, fn);
}
/* If we're checking for implicit delete, don't bother with argument
conversions. */
if (flags & LOOKUP_SPECULATIVE)
{
if (DECL_DELETED_FN (fn))
{
if (flags & LOOKUP_COMPLAIN)
mark_used (fn);
return error_mark_node;
}
if (cand->viable == 1)
return fn;
else if (!(flags & LOOKUP_COMPLAIN))
/* Reject bad conversions now. */
return error_mark_node;
/* else continue to get conversion error. */
} }
/* Find maximum size of vector to hold converted arguments. */ /* Find maximum size of vector to hold converted arguments. */
...@@ -5824,6 +5856,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) ...@@ -5824,6 +5856,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
tree targ; tree targ;
tree arg = argarray[num_artificial_parms_for (fn)]; tree arg = argarray[num_artificial_parms_for (fn)];
tree fa; tree fa;
bool trivial = trivial_fn_p (fn);
/* Pull out the real argument, disregarding const-correctness. */ /* Pull out the real argument, disregarding const-correctness. */
targ = arg; targ = arg;
...@@ -5848,13 +5881,12 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) ...@@ -5848,13 +5881,12 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
if (TREE_CODE (arg) == TARGET_EXPR if (TREE_CODE (arg) == TARGET_EXPR
&& TARGET_EXPR_LIST_INIT_P (arg)) && TARGET_EXPR_LIST_INIT_P (arg))
{ {
/* Copy-list-initialization doesn't require the copy constructor /* Copy-list-initialization doesn't require the constructor
to be defined. */ to be defined. */
} }
/* [class.copy]: the copy constructor is implicitly defined even if /* [class.copy]: the copy constructor is implicitly defined even if
the implementation elided its use. */ the implementation elided its use. */
else if (TYPE_HAS_COMPLEX_COPY_CTOR (DECL_CONTEXT (fn)) else if (!trivial)
|| move_fn_p (fn))
{ {
mark_used (fn); mark_used (fn);
already_used = true; already_used = true;
...@@ -5872,13 +5904,10 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) ...@@ -5872,13 +5904,10 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
{ {
if (TREE_CODE (arg) == TARGET_EXPR) if (TREE_CODE (arg) == TARGET_EXPR)
return arg; return arg;
else if (TYPE_HAS_TRIVIAL_COPY_CTOR (DECL_CONTEXT (fn)) else if (trivial)
&& !move_fn_p (fn))
return build_target_expr_with_type (arg, DECL_CONTEXT (fn)); return build_target_expr_with_type (arg, DECL_CONTEXT (fn));
} }
else if (TREE_CODE (arg) == TARGET_EXPR else if (TREE_CODE (arg) == TARGET_EXPR || trivial)
|| (TYPE_HAS_TRIVIAL_COPY_CTOR (DECL_CONTEXT (fn))
&& !move_fn_p (fn)))
{ {
tree to = stabilize_reference (cp_build_indirect_ref (fa, RO_NULL, tree to = stabilize_reference (cp_build_indirect_ref (fa, RO_NULL,
complain)); complain));
...@@ -5888,8 +5917,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) ...@@ -5888,8 +5917,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
} }
} }
else if (DECL_OVERLOADED_OPERATOR_P (fn) == NOP_EXPR else if (DECL_OVERLOADED_OPERATOR_P (fn) == NOP_EXPR
&& copy_fn_p (fn) && trivial_fn_p (fn))
&& TYPE_HAS_TRIVIAL_COPY_ASSIGN (DECL_CONTEXT (fn)))
{ {
tree to = stabilize_reference tree to = stabilize_reference
(cp_build_indirect_ref (argarray[0], RO_NULL, complain)); (cp_build_indirect_ref (argarray[0], RO_NULL, complain));
......
...@@ -1314,10 +1314,14 @@ check_bases (tree t, ...@@ -1314,10 +1314,14 @@ check_bases (tree t,
TYPE_HAS_COMPLEX_COPY_ASSIGN (t) TYPE_HAS_COMPLEX_COPY_ASSIGN (t)
|= TYPE_HAS_COMPLEX_COPY_ASSIGN (basetype); |= TYPE_HAS_COMPLEX_COPY_ASSIGN (basetype);
TYPE_HAS_COMPLEX_COPY_CTOR (t) |= TYPE_HAS_COMPLEX_COPY_CTOR (basetype); TYPE_HAS_COMPLEX_COPY_CTOR (t) |= TYPE_HAS_COMPLEX_COPY_CTOR (basetype);
TYPE_HAS_COMPLEX_MOVE_ASSIGN (t)
|= TYPE_HAS_COMPLEX_MOVE_ASSIGN (basetype);
TYPE_HAS_COMPLEX_MOVE_CTOR (t) |= TYPE_HAS_COMPLEX_MOVE_CTOR (basetype);
TYPE_POLYMORPHIC_P (t) |= TYPE_POLYMORPHIC_P (basetype); TYPE_POLYMORPHIC_P (t) |= TYPE_POLYMORPHIC_P (basetype);
CLASSTYPE_CONTAINS_EMPTY_CLASS_P (t) CLASSTYPE_CONTAINS_EMPTY_CLASS_P (t)
|= CLASSTYPE_CONTAINS_EMPTY_CLASS_P (basetype); |= CLASSTYPE_CONTAINS_EMPTY_CLASS_P (basetype);
TYPE_HAS_COMPLEX_DFLT (t) |= TYPE_HAS_COMPLEX_DFLT (basetype); TYPE_HAS_COMPLEX_DFLT (t) |= (!TYPE_HAS_DEFAULT_CONSTRUCTOR (basetype)
|| TYPE_HAS_COMPLEX_DFLT (basetype));
/* A standard-layout class is a class that: /* A standard-layout class is a class that:
... ...
...@@ -2670,6 +2674,7 @@ add_implicitly_declared_members (tree t, ...@@ -2670,6 +2674,7 @@ add_implicitly_declared_members (tree t,
a virtual function from a base class. */ a virtual function from a base class. */
if (TYPE_POLYMORPHIC_P (t) if (TYPE_POLYMORPHIC_P (t)
&& (CLASSTYPE_LAZY_COPY_ASSIGN (t) && (CLASSTYPE_LAZY_COPY_ASSIGN (t)
|| CLASSTYPE_LAZY_MOVE_ASSIGN (t)
|| CLASSTYPE_LAZY_DESTRUCTOR (t))) || CLASSTYPE_LAZY_DESTRUCTOR (t)))
{ {
tree binfo = TYPE_BINFO (t); tree binfo = TYPE_BINFO (t);
...@@ -2686,6 +2691,8 @@ add_implicitly_declared_members (tree t, ...@@ -2686,6 +2691,8 @@ add_implicitly_declared_members (tree t,
{ {
if (CLASSTYPE_LAZY_COPY_ASSIGN (t)) if (CLASSTYPE_LAZY_COPY_ASSIGN (t))
lazily_declare_fn (sfk_copy_assignment, t); lazily_declare_fn (sfk_copy_assignment, t);
if (CLASSTYPE_LAZY_MOVE_ASSIGN (t))
lazily_declare_fn (sfk_move_assignment, t);
} }
else if (DECL_DESTRUCTOR_P (fn) else if (DECL_DESTRUCTOR_P (fn)
&& CLASSTYPE_LAZY_DESTRUCTOR (t)) && CLASSTYPE_LAZY_DESTRUCTOR (t))
...@@ -2848,6 +2855,8 @@ check_field_decl (tree field, ...@@ -2848,6 +2855,8 @@ check_field_decl (tree field,
if (TYPE_HAS_COMPLEX_COPY_ASSIGN (type)) if (TYPE_HAS_COMPLEX_COPY_ASSIGN (type))
error ("member %q+#D with copy assignment operator not allowed in union", error ("member %q+#D with copy assignment operator not allowed in union",
field); field);
/* Don't bother diagnosing move assop now; C++0x has more
flexible unions. */
} }
else else
{ {
...@@ -2856,7 +2865,10 @@ check_field_decl (tree field, ...@@ -2856,7 +2865,10 @@ check_field_decl (tree field,
|= TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type); |= TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type);
TYPE_HAS_COMPLEX_COPY_ASSIGN (t) |= TYPE_HAS_COMPLEX_COPY_ASSIGN (type); TYPE_HAS_COMPLEX_COPY_ASSIGN (t) |= TYPE_HAS_COMPLEX_COPY_ASSIGN (type);
TYPE_HAS_COMPLEX_COPY_CTOR (t) |= TYPE_HAS_COMPLEX_COPY_CTOR (type); TYPE_HAS_COMPLEX_COPY_CTOR (t) |= TYPE_HAS_COMPLEX_COPY_CTOR (type);
TYPE_HAS_COMPLEX_DFLT (t) |= TYPE_HAS_COMPLEX_DFLT (type); TYPE_HAS_COMPLEX_MOVE_ASSIGN (t) |= TYPE_HAS_COMPLEX_MOVE_ASSIGN (type);
TYPE_HAS_COMPLEX_MOVE_CTOR (t) |= TYPE_HAS_COMPLEX_MOVE_CTOR (type);
TYPE_HAS_COMPLEX_DFLT (t) |= (!TYPE_HAS_DEFAULT_CONSTRUCTOR (type)
|| TYPE_HAS_COMPLEX_DFLT (type));
} }
if (!TYPE_HAS_CONST_COPY_CTOR (type)) if (!TYPE_HAS_CONST_COPY_CTOR (type))
...@@ -3022,6 +3034,7 @@ check_field_decls (tree t, tree *access_decls, ...@@ -3022,6 +3034,7 @@ check_field_decls (tree t, tree *access_decls,
only way to initialize nonstatic const and reference only way to initialize nonstatic const and reference
members. */ members. */
TYPE_HAS_COMPLEX_COPY_ASSIGN (t) = 1; TYPE_HAS_COMPLEX_COPY_ASSIGN (t) = 1;
TYPE_HAS_COMPLEX_MOVE_ASSIGN (t) = 1;
} }
type = strip_array_types (type); type = strip_array_types (type);
...@@ -3108,6 +3121,7 @@ check_field_decls (tree t, tree *access_decls, ...@@ -3108,6 +3121,7 @@ check_field_decls (tree t, tree *access_decls,
only way to initialize nonstatic const and reference only way to initialize nonstatic const and reference
members. */ members. */
TYPE_HAS_COMPLEX_COPY_ASSIGN (t) = 1; TYPE_HAS_COMPLEX_COPY_ASSIGN (t) = 1;
TYPE_HAS_COMPLEX_MOVE_ASSIGN (t) = 1;
} }
/* A field that is pseudo-const makes the structure likewise. */ /* A field that is pseudo-const makes the structure likewise. */
else if (CLASS_TYPE_P (type)) else if (CLASS_TYPE_P (type))
...@@ -4277,6 +4291,50 @@ type_has_virtual_destructor (tree type) ...@@ -4277,6 +4291,50 @@ type_has_virtual_destructor (tree type)
return (dtor && DECL_VIRTUAL_P (dtor)); return (dtor && DECL_VIRTUAL_P (dtor));
} }
/* Returns true iff class T has a move constructor. */
bool
type_has_move_constructor (tree t)
{
tree fns;
if (CLASSTYPE_LAZY_MOVE_CTOR (t))
{
gcc_assert (COMPLETE_TYPE_P (t));
lazily_declare_fn (sfk_move_constructor, t);
}
if (!CLASSTYPE_METHOD_VEC (t))
return false;
for (fns = CLASSTYPE_CONSTRUCTORS (t); fns; fns = OVL_NEXT (fns))
if (move_fn_p (OVL_CURRENT (fns)))
return true;
return false;
}
/* Returns true iff class T has a move assignment operator. */
bool
type_has_move_assign (tree t)
{
tree fns;
if (CLASSTYPE_LAZY_MOVE_ASSIGN (t))
{
gcc_assert (COMPLETE_TYPE_P (t));
lazily_declare_fn (sfk_move_assignment, t);
}
for (fns = lookup_fnfields_slot (t, ansi_assopname (NOP_EXPR));
fns; fns = OVL_NEXT (fns))
if (move_fn_p (OVL_CURRENT (fns)))
return true;
return false;
}
/* Remove all zero-width bit-fields from T. */ /* Remove all zero-width bit-fields from T. */
static void static void
...@@ -4411,6 +4469,7 @@ check_bases_and_members (tree t) ...@@ -4411,6 +4469,7 @@ check_bases_and_members (tree t)
/* Do some bookkeeping that will guide the generation of implicitly /* Do some bookkeeping that will guide the generation of implicitly
declared member functions. */ declared member functions. */
TYPE_HAS_COMPLEX_COPY_CTOR (t) |= TYPE_CONTAINS_VPTR_P (t); TYPE_HAS_COMPLEX_COPY_CTOR (t) |= TYPE_CONTAINS_VPTR_P (t);
TYPE_HAS_COMPLEX_MOVE_CTOR (t) |= TYPE_CONTAINS_VPTR_P (t);
/* We need to call a constructor for this class if it has a /* We need to call a constructor for this class if it has a
user-provided constructor, or if the default constructor is going user-provided constructor, or if the default constructor is going
to initialize the vptr. (This is not an if-and-only-if; to initialize the vptr. (This is not an if-and-only-if;
...@@ -4434,6 +4493,7 @@ check_bases_and_members (tree t) ...@@ -4434,6 +4493,7 @@ check_bases_and_members (tree t)
|| saved_nontrivial_dtor || saved_complex_asn_ref); || saved_nontrivial_dtor || saved_complex_asn_ref);
CLASSTYPE_NON_STD_LAYOUT (t) |= TYPE_CONTAINS_VPTR_P (t); CLASSTYPE_NON_STD_LAYOUT (t) |= TYPE_CONTAINS_VPTR_P (t);
TYPE_HAS_COMPLEX_COPY_ASSIGN (t) |= TYPE_CONTAINS_VPTR_P (t); TYPE_HAS_COMPLEX_COPY_ASSIGN (t) |= TYPE_CONTAINS_VPTR_P (t);
TYPE_HAS_COMPLEX_MOVE_ASSIGN (t) |= TYPE_CONTAINS_VPTR_P (t);
TYPE_HAS_COMPLEX_DFLT (t) |= TYPE_CONTAINS_VPTR_P (t); TYPE_HAS_COMPLEX_DFLT (t) |= TYPE_CONTAINS_VPTR_P (t);
/* If the class has no user-declared constructor, but does have /* If the class has no user-declared constructor, but does have
......
...@@ -1307,10 +1307,13 @@ struct GTY(()) lang_type_class { ...@@ -1307,10 +1307,13 @@ struct GTY(()) lang_type_class {
unsigned has_complex_dflt : 1; unsigned has_complex_dflt : 1;
unsigned has_list_ctor : 1; unsigned has_list_ctor : 1;
unsigned non_std_layout : 1; unsigned non_std_layout : 1;
unsigned lazy_move_ctor : 1;
unsigned is_literal : 1; unsigned is_literal : 1;
unsigned lazy_move_ctor : 1;
unsigned lazy_move_assign : 1;
unsigned has_complex_move_ctor : 1;
unsigned has_complex_move_assign : 1;
/* When adding a flag here, consider whether or not it ought to /* When adding a flag here, consider whether or not it ought to
apply to a template instance if it applies to the template. If apply to a template instance if it applies to the template. If
so, make sure to copy it in instantiate_class_template! */ so, make sure to copy it in instantiate_class_template! */
...@@ -1318,7 +1321,7 @@ struct GTY(()) lang_type_class { ...@@ -1318,7 +1321,7 @@ struct GTY(()) lang_type_class {
/* There are some bits left to fill out a 32-bit word. Keep track /* There are some bits left to fill out a 32-bit word. Keep track
of this by updating the size of this bitfield whenever you add or of this by updating the size of this bitfield whenever you add or
remove a flag. */ remove a flag. */
unsigned dummy : 7; unsigned dummy : 4;
tree primary_base; tree primary_base;
VEC(tree_pair_s,gc) *vcall_indices; VEC(tree_pair_s,gc) *vcall_indices;
...@@ -1416,6 +1419,11 @@ struct GTY((variable_size)) lang_type { ...@@ -1416,6 +1419,11 @@ struct GTY((variable_size)) lang_type {
#define CLASSTYPE_LAZY_COPY_ASSIGN(NODE) \ #define CLASSTYPE_LAZY_COPY_ASSIGN(NODE) \
(LANG_TYPE_CLASS_CHECK (NODE)->lazy_copy_assign) (LANG_TYPE_CLASS_CHECK (NODE)->lazy_copy_assign)
/* Nonzero means that NODE (a class type) has an assignment operator
-- but that it has not yet been declared. */
#define CLASSTYPE_LAZY_MOVE_ASSIGN(NODE) \
(LANG_TYPE_CLASS_CHECK (NODE)->lazy_move_assign)
/* Nonzero means that NODE (a class type) has a destructor -- but that /* Nonzero means that NODE (a class type) has a destructor -- but that
it has not yet been declared. */ it has not yet been declared. */
#define CLASSTYPE_LAZY_DESTRUCTOR(NODE) \ #define CLASSTYPE_LAZY_DESTRUCTOR(NODE) \
...@@ -3166,6 +3174,12 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) ...@@ -3166,6 +3174,12 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
/* Nonzero if there is a non-trivial X::X(cv X&) for this class. */ /* Nonzero if there is a non-trivial X::X(cv X&) for this class. */
#define TYPE_HAS_COMPLEX_COPY_CTOR(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->has_complex_copy_ctor) #define TYPE_HAS_COMPLEX_COPY_CTOR(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->has_complex_copy_ctor)
/* Nonzero if there is a non-trivial X::op=(X&&) for this class. */
#define TYPE_HAS_COMPLEX_MOVE_ASSIGN(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->has_complex_move_assign)
/* Nonzero if there is a non-trivial X::X(X&&) for this class. */
#define TYPE_HAS_COMPLEX_MOVE_CTOR(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->has_complex_move_ctor)
/* Nonzero if there is a non-trivial default constructor for this class. */ /* Nonzero if there is a non-trivial default constructor for this class. */
#define TYPE_HAS_COMPLEX_DFLT(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->has_complex_dflt) #define TYPE_HAS_COMPLEX_DFLT(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->has_complex_dflt)
...@@ -3869,6 +3883,7 @@ typedef enum special_function_kind { ...@@ -3869,6 +3883,7 @@ typedef enum special_function_kind {
sfk_copy_constructor, /* A copy constructor. */ sfk_copy_constructor, /* A copy constructor. */
sfk_move_constructor, /* A move constructor. */ sfk_move_constructor, /* A move constructor. */
sfk_copy_assignment, /* A copy assignment operator. */ sfk_copy_assignment, /* A copy assignment operator. */
sfk_move_assignment, /* A move assignment operator. */
sfk_destructor, /* A destructor. */ sfk_destructor, /* A destructor. */
sfk_complete_destructor, /* A destructor for complete objects. */ sfk_complete_destructor, /* A destructor for complete objects. */
sfk_base_destructor, /* A destructor for base subobjects. */ sfk_base_destructor, /* A destructor for base subobjects. */
...@@ -4163,12 +4178,21 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, TYPENAME_FLAG }; ...@@ -4163,12 +4178,21 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, TYPENAME_FLAG };
/* We're inside an init-list, so narrowing conversions are ill-formed. */ /* We're inside an init-list, so narrowing conversions are ill-formed. */
#define LOOKUP_NO_NARROWING (LOOKUP_PREFER_RVALUE << 1) #define LOOKUP_NO_NARROWING (LOOKUP_PREFER_RVALUE << 1)
/* Avoid user-defined conversions for the first parameter of a copy /* Avoid user-defined conversions for the first parameter of a copy
constructor. */ constructor (or move constructor). */
#define LOOKUP_NO_COPY_CTOR_CONVERSION (LOOKUP_NO_NARROWING << 1) #define LOOKUP_NO_COPY_CTOR_CONVERSION (LOOKUP_NO_NARROWING << 1)
/* This is the first parameter of a copy constructor. */ /* This is the first parameter of a copy constructor. */
#define LOOKUP_COPY_PARM (LOOKUP_NO_COPY_CTOR_CONVERSION << 1) #define LOOKUP_COPY_PARM (LOOKUP_NO_COPY_CTOR_CONVERSION << 1)
/* We only want to consider list constructors. */ /* We only want to consider list constructors. */
#define LOOKUP_LIST_ONLY (LOOKUP_COPY_PARM << 1) #define LOOKUP_LIST_ONLY (LOOKUP_COPY_PARM << 1)
/* Return after determining which function to call and checking access.
Used by sythesized_method_walk to determine which functions will
be called to initialize subobjects, in order to determine exception
specification and possible implicit delete.
This is kind of a hack, but since access control doesn't respect SFINAE
we can't just use tf_none to avoid access control errors, we need
another mechanism. Exiting early also avoids problems with trying
to perform argument conversions when the class isn't complete yet. */
#define LOOKUP_SPECULATIVE (LOOKUP_LIST_ONLY << 1)
#define LOOKUP_NAMESPACES_ONLY(F) \ #define LOOKUP_NAMESPACES_ONLY(F) \
(((F) & LOOKUP_PREFER_NAMESPACES) && !((F) & LOOKUP_PREFER_TYPES)) (((F) & LOOKUP_PREFER_NAMESPACES) && !((F) & LOOKUP_PREFER_TYPES))
...@@ -4656,6 +4680,8 @@ extern bool user_provided_p (tree); ...@@ -4656,6 +4680,8 @@ extern bool user_provided_p (tree);
extern bool type_has_user_provided_constructor (tree); extern bool type_has_user_provided_constructor (tree);
extern bool type_has_user_provided_default_constructor (tree); extern bool type_has_user_provided_default_constructor (tree);
extern bool type_has_virtual_destructor (tree); extern bool type_has_virtual_destructor (tree);
extern bool type_has_move_constructor (tree);
extern bool type_has_move_assign (tree);
extern void defaulted_late_check (tree); extern void defaulted_late_check (tree);
extern bool defaultable_fn_check (tree); extern bool defaultable_fn_check (tree);
extern void fixup_type_variants (tree); extern void fixup_type_variants (tree);
...@@ -4921,15 +4947,19 @@ extern void init_method (void); ...@@ -4921,15 +4947,19 @@ extern void init_method (void);
extern tree make_thunk (tree, bool, tree, tree); extern tree make_thunk (tree, bool, tree, tree);
extern void finish_thunk (tree); extern void finish_thunk (tree);
extern void use_thunk (tree, bool); extern void use_thunk (tree, bool);
extern bool trivial_fn_p (tree);
extern bool maybe_explain_implicit_delete (tree);
extern void synthesize_method (tree); extern void synthesize_method (tree);
extern tree lazily_declare_fn (special_function_kind, extern tree lazily_declare_fn (special_function_kind,
tree); tree);
extern tree skip_artificial_parms_for (const_tree, tree); extern tree skip_artificial_parms_for (const_tree, tree);
extern int num_artificial_parms_for (const_tree); extern int num_artificial_parms_for (const_tree);
extern tree make_alias_for (tree, tree); extern tree make_alias_for (tree, tree);
extern tree locate_copy (tree, void *); extern tree get_copy_ctor (tree);
extern tree locate_ctor (tree, void *); extern tree get_copy_assign (tree);
extern tree locate_dtor (tree, void *); extern tree get_default_ctor (tree);
extern tree get_dtor (tree);
extern tree locate_ctor (tree);
/* In optimize.c */ /* In optimize.c */
extern bool maybe_clone_body (tree); extern bool maybe_clone_body (tree);
...@@ -5070,6 +5100,7 @@ extern int accessible_p (tree, tree, bool); ...@@ -5070,6 +5100,7 @@ extern int accessible_p (tree, tree, bool);
extern tree lookup_field_1 (tree, tree, bool); extern tree lookup_field_1 (tree, tree, bool);
extern tree lookup_field (tree, tree, int, bool); extern tree lookup_field (tree, tree, int, bool);
extern int lookup_fnfields_1 (tree, tree); extern int lookup_fnfields_1 (tree, tree);
extern tree lookup_fnfields_slot (tree, tree);
extern int class_method_index_for_fn (tree, tree); extern int class_method_index_for_fn (tree, tree);
extern tree lookup_fnfields (tree, tree, int); extern tree lookup_fnfields (tree, tree, int);
extern tree lookup_member (tree, tree, int, bool); extern tree lookup_member (tree, tree, int, bool);
......
...@@ -10273,6 +10273,8 @@ grok_special_member_properties (tree decl) ...@@ -10273,6 +10273,8 @@ grok_special_member_properties (tree decl)
if (user_provided_p (decl)) if (user_provided_p (decl))
TYPE_HAS_COMPLEX_DFLT (class_type) = 1; TYPE_HAS_COMPLEX_DFLT (class_type) = 1;
} }
else if (move_fn_p (decl) && user_provided_p (decl))
TYPE_HAS_COMPLEX_MOVE_CTOR (class_type) = 1;
else if (is_list_ctor (decl)) else if (is_list_ctor (decl))
TYPE_HAS_LIST_CTOR (class_type) = 1; TYPE_HAS_LIST_CTOR (class_type) = 1;
} }
...@@ -10294,6 +10296,8 @@ grok_special_member_properties (tree decl) ...@@ -10294,6 +10296,8 @@ grok_special_member_properties (tree decl)
if (assop != 1) if (assop != 1)
TYPE_HAS_CONST_COPY_ASSIGN (class_type) = 1; TYPE_HAS_CONST_COPY_ASSIGN (class_type) = 1;
} }
else if (move_fn_p (decl) && user_provided_p (decl))
TYPE_HAS_COMPLEX_MOVE_ASSIGN (class_type) = 1;
} }
/* Destructors are handled in check_methods. */ /* Destructors are handled in check_methods. */
} }
......
...@@ -59,7 +59,6 @@ typedef enum mangling_flags mangling_flags; ...@@ -59,7 +59,6 @@ typedef enum mangling_flags mangling_flags;
static void do_build_copy_assign (tree); static void do_build_copy_assign (tree);
static void do_build_copy_constructor (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); static tree make_alias_for_thunk (tree);
/* Called once to initialize method.c. */ /* Called once to initialize method.c. */
...@@ -400,6 +399,74 @@ use_thunk (tree thunk_fndecl, bool emit_p) ...@@ -400,6 +399,74 @@ use_thunk (tree thunk_fndecl, bool emit_p)
/* Code for synthesizing methods which have default semantics defined. */ /* 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. */ /* Generate code for default X(X&) or X(X&&) constructor. */
static void static void
...@@ -407,14 +474,15 @@ do_build_copy_constructor (tree fndecl) ...@@ -407,14 +474,15 @@ do_build_copy_constructor (tree fndecl)
{ {
tree parm = FUNCTION_FIRST_USER_PARM (fndecl); tree parm = FUNCTION_FIRST_USER_PARM (fndecl);
bool move_p = DECL_MOVE_CONSTRUCTOR_P (fndecl); bool move_p = DECL_MOVE_CONSTRUCTOR_P (fndecl);
bool trivial = trivial_fn_p (fndecl);
parm = convert_from_reference (parm); parm = convert_from_reference (parm);
if (TYPE_HAS_TRIVIAL_COPY_CTOR (current_class_type) if (trivial
&& is_empty_class (current_class_type)) && is_empty_class (current_class_type))
/* Don't copy the padding byte; it might not have been allocated /* Don't copy the padding byte; it might not have been allocated
if *this is a base subobject. */; 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); tree t = build2 (INIT_EXPR, void_type_node, current_class_ref, parm);
finish_expr_stmt (t); finish_expr_stmt (t);
...@@ -512,15 +580,17 @@ do_build_copy_assign (tree fndecl) ...@@ -512,15 +580,17 @@ do_build_copy_assign (tree fndecl)
{ {
tree parm = TREE_CHAIN (DECL_ARGUMENTS (fndecl)); tree parm = TREE_CHAIN (DECL_ARGUMENTS (fndecl));
tree compound_stmt; tree compound_stmt;
bool move_p = move_fn_p (fndecl);
bool trivial = trivial_fn_p (fndecl);
compound_stmt = begin_compound_stmt (0); compound_stmt = begin_compound_stmt (0);
parm = convert_from_reference (parm); parm = convert_from_reference (parm);
if (TYPE_HAS_TRIVIAL_COPY_ASSIGN (current_class_type) if (trivial
&& is_empty_class (current_class_type)) && is_empty_class (current_class_type))
/* Don't copy the padding byte; it might not have been allocated /* Don't copy the padding byte; it might not have been allocated
if *this is a base subobject. */; 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); tree t = build2 (MODIFY_EXPR, void_type_node, current_class_ref, parm);
finish_expr_stmt (t); finish_expr_stmt (t);
...@@ -542,6 +612,8 @@ do_build_copy_assign (tree fndecl) ...@@ -542,6 +612,8 @@ do_build_copy_assign (tree fndecl)
/* We must convert PARM directly to the base class /* We must convert PARM directly to the base class
explicitly since the base class may be ambiguous. */ explicitly since the base class may be ambiguous. */
converted_parm = build_base_path (PLUS_EXPR, parm, base_binfo, 1); 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. */ /* Call the base class assignment operator. */
parmvec = make_tree_vector_single (converted_parm); parmvec = make_tree_vector_single (converted_parm);
finish_expr_stmt finish_expr_stmt
...@@ -604,6 +676,8 @@ do_build_copy_assign (tree fndecl) ...@@ -604,6 +676,8 @@ do_build_copy_assign (tree fndecl)
expr_type = cp_build_qualified_type (expr_type, quals); expr_type = cp_build_qualified_type (expr_type, quals);
init = build3 (COMPONENT_REF, expr_type, init, field, NULL_TREE); 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)) if (DECL_NAME (field))
init = cp_build_modify_expr (comp, NOP_EXPR, init, init = cp_build_modify_expr (comp, NOP_EXPR, init,
...@@ -695,163 +769,505 @@ synthesize_method (tree fndecl) ...@@ -695,163 +769,505 @@ synthesize_method (tree fndecl)
fndecl); fndecl);
} }
/* Use EXTRACTOR to locate the relevant function called for each base & /* Build a reference to type TYPE with cv-quals QUALS, which is an
class field of TYPE. CLIENT allows additional information to be passed rvalue if RVALUE is true. */
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. */
static tree static tree
synthesize_exception_spec (tree type, tree (*extractor) (tree, void*), build_stub_type (tree type, int quals, bool rvalue)
void *client)
{ {
tree raises = empty_except_spec; tree argtype = cp_build_qualified_type (type, quals);
tree fields = TYPE_FIELDS (type); return cp_build_reference_type (argtype, rvalue);
tree binfo, base_binfo; }
int i;
for (binfo = TYPE_BINFO (type), i = 0; /* Build a dummy glvalue from dereferencing a dummy reference of type
BINFO_BASE_ITERATE (binfo, i, base_binfo); i++) REFTYPE. */
{
tree fn = (*extractor) (BINFO_TYPE (base_binfo), client);
if (fn)
{
tree fn_raises = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn));
raises = merge_exception_specifiers (raises, fn_raises); static tree
} build_stub_object (tree reftype)
} {
for (; fields; fields = TREE_CHAIN (fields)) tree stub = build1 (NOP_EXPR, reftype, integer_one_node);
{ return convert_from_reference (stub);
tree type = TREE_TYPE (fields); }
tree fn;
if (TREE_CODE (fields) != FIELD_DECL || DECL_ARTIFICIAL (fields)) /* Determine which function will be called when looking up NAME in TYPE,
continue; called with a single ARGTYPE argument, or no argument if ARGTYPE is
while (TREE_CODE (type) == ARRAY_TYPE) null. FLAGS and COMPLAIN are as for build_new_method_call.
type = TREE_TYPE (type);
if (!CLASS_TYPE_P (type))
continue;
fn = (*extractor) (type, client); Returns a FUNCTION_DECL if all is well.
if (fn) Returns NULL_TREE if overload resolution failed.
{ Returns error_mark_node if the chosen function cannot be called. */
tree fn_raises = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn));
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. */ /* Locate the dtor of TYPE. */
tree 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. */ /* Locate the default ctor of TYPE. */
tree 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 NULL_TREE;
return fn;
}
/* Call lookup_fnfields_1 to create the constructor declarations, if /* Locate the copy assignment operator of TYPE. */
necessary. */
if (CLASSTYPE_LAZY_DEFAULT_CTOR (type))
return lazily_declare_fn (sfk_constructor, 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 raises = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn));
tree parms = TYPE_ARG_TYPES (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)) if (move_p && !move_fn_p (fn) && !trivial_fn_p (fn))
return 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; tree binfo, base_binfo, field, scope, fnname, rval, argtype;
int quals; 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_ *deleted_p = false;
points to a COPY_DATA holding the name (NULL for the ctor) }
and desired qualifiers of the source operand. */
tree move_p = false;
locate_copy (tree type, void *client_) switch (sfk)
{ {
struct copy_data *client = (struct copy_data *)client_; case sfk_constructor:
tree fns; case sfk_destructor:
tree best = NULL_TREE; copy_arg_p = false;
bool excess_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; case sfk_move_assignment:
ix = lookup_fnfields_1 (type, client->name); case sfk_copy_assignment:
if (ix < 0) assign_p = true;
return NULL_TREE; fnname = ansi_assopname (NOP_EXPR);
fns = VEC_index (tree, CLASSTYPE_METHOD_VEC (type), ix); 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 flags = LOOKUP_NORMAL|LOOKUP_SPECULATIVE;
it now. */ complain = tf_warning_or_error;
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);
} }
else else
return NULL_TREE;
for (; fns; fns = OVL_NEXT (fns))
{ {
tree fn = OVL_CURRENT (fns); flags = LOOKUP_PROTECT|LOOKUP_SPECULATIVE;
tree parms = TYPE_ARG_TYPES (TREE_TYPE (fn)); complain = tf_none;
tree src_type; }
int excess;
int quals;
parms = skip_artificial_parms_for (fn, parms);
if (!parms)
continue;
src_type = non_reference (TREE_VALUE (parms));
if (src_type == error_mark_node) if (const_p)
return NULL_TREE; quals = TYPE_QUAL_CONST;
else
quals = TYPE_UNQUALIFIED;
argtype = NULL_TREE;
if (!same_type_ignoring_top_level_qualifiers_p (src_type, type)) for (binfo = TYPE_BINFO (ctype), i = 0;
continue; BINFO_BASE_ITERATE (binfo, i, base_binfo); ++i)
if (!sufficient_parms_p (TREE_CHAIN (parms))) {
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; 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; continue;
excess = quals & ~client->quals;
if (!best || (excess_p && !excess)) if (copy_arg_p)
{ {
best = fn; int mem_quals = cp_type_quals (mem_type) | quals;
excess_p = excess; 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 else
/* Ambiguous */ msg = ("non-static data member %qD does not have a move "
return NULL_TREE; "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 /* 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) ...@@ -872,6 +1288,8 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
tree this_parm; tree this_parm;
tree name; tree name;
HOST_WIDE_INT saved_processing_template_decl; HOST_WIDE_INT saved_processing_template_decl;
bool deleted_p;
bool trivial_p;
/* Because we create declarations for implicitly declared functions /* Because we create declarations for implicitly declared functions
lazily, we may be creating the declaration for a member of TYPE 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) ...@@ -903,50 +1321,49 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
case sfk_destructor: case sfk_destructor:
/* Destructor. */ /* Destructor. */
name = constructor_name (type); name = constructor_name (type);
raises = synthesize_exception_spec (type, &locate_dtor, 0);
break; break;
case sfk_constructor: case sfk_constructor:
/* Default constructor. */ /* Default constructor. */
name = constructor_name (type); name = constructor_name (type);
raises = synthesize_exception_spec (type, &locate_ctor, 0);
break; break;
case sfk_copy_constructor: case sfk_copy_constructor:
case sfk_copy_assignment: case sfk_copy_assignment:
case sfk_move_constructor: case sfk_move_constructor:
case sfk_move_assignment:
{ {
struct copy_data data; bool move_p;
if (kind == sfk_copy_assignment
data.name = NULL; || kind == sfk_move_assignment)
data.quals = 0;
if (kind == sfk_copy_assignment)
{ {
return_type = build_reference_type (type); return_type = build_reference_type (type);
name = ansi_assopname (NOP_EXPR); name = ansi_assopname (NOP_EXPR);
data.name = name;
} }
else else
name = constructor_name (type); name = constructor_name (type);
if (const_p) if (const_p)
{ rhs_parm_type = cp_build_qualified_type (type, TYPE_QUAL_CONST);
data.quals = TYPE_QUAL_CONST;
rhs_parm_type = cp_build_qualified_type (type, TYPE_QUAL_CONST);
}
else else
rhs_parm_type = type; rhs_parm_type = type;
rhs_parm_type move_p = (kind == sfk_move_assignment
= cp_build_reference_type (rhs_parm_type, || kind == sfk_move_constructor);
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); parameter_types = tree_cons (NULL_TREE, rhs_parm_type, parameter_types);
raises = synthesize_exception_spec (type, &locate_copy, &data);
break; break;
} }
default: default:
gcc_unreachable (); 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. */ /* Create the function. */
fn_type = build_method_type_directly (type, return_type, parameter_types); fn_type = build_method_type_directly (type, return_type, parameter_types);
if (raises) if (raises)
...@@ -1031,6 +1448,9 @@ defaulted_late_check (tree fn) ...@@ -1031,6 +1448,9 @@ defaulted_late_check (tree fn)
tree eh_spec = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (implicit_fn)); tree eh_spec = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (implicit_fn));
TREE_TYPE (fn) = build_exception_variant (TREE_TYPE (fn), eh_spec); 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 /* Returns true iff FN can be explicitly defaulted, and gives any
...@@ -1055,9 +1475,13 @@ defaultable_fn_check (tree fn) ...@@ -1055,9 +1475,13 @@ defaultable_fn_check (tree fn)
else if (DECL_DESTRUCTOR_P (fn)) else if (DECL_DESTRUCTOR_P (fn))
kind = sfk_destructor; kind = sfk_destructor;
else if (DECL_ASSIGNMENT_OPERATOR_P (fn) else if (DECL_ASSIGNMENT_OPERATOR_P (fn)
&& DECL_OVERLOADED_OPERATOR_P (fn) == NOP_EXPR && DECL_OVERLOADED_OPERATOR_P (fn) == NOP_EXPR)
&& copy_fn_p (fn)) {
kind = sfk_copy_assignment; if (copy_fn_p (fn))
kind = sfk_copy_assignment;
else if (move_fn_p (fn))
kind = sfk_move_assignment;
}
if (kind == sfk_none) if (kind == sfk_none)
{ {
...@@ -1103,21 +1527,48 @@ tree ...@@ -1103,21 +1527,48 @@ tree
lazily_declare_fn (special_function_kind sfk, tree type) lazily_declare_fn (special_function_kind sfk, tree type)
{ {
tree fn; tree fn;
bool const_p; /* Whether or not the argument has a const reference type. */
bool const_p = false;
/* Figure out whether or not the argument has a const reference
type. */ switch (sfk)
if (sfk == sfk_copy_constructor) {
const_p = TYPE_HAS_CONST_COPY_CTOR (type); case sfk_constructor:
else if (sfk == sfk_copy_assignment) CLASSTYPE_LAZY_DEFAULT_CTOR (type) = 0;
const_p = TYPE_HAS_CONST_COPY_ASSIGN (type); break;
else case sfk_copy_constructor:
/* In this case, CONST_P will be ignored. */ const_p = TYPE_HAS_CONST_COPY_CTOR (type);
const_p = false; 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. */ /* Declare the function. */
fn = implicitly_declare_fn (sfk, type, const_p); 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. */ /* A destructor may be virtual. */
if (sfk == sfk_destructor if (sfk == sfk_destructor
|| sfk == sfk_move_assignment
|| sfk == sfk_copy_assignment) || sfk == sfk_copy_assignment)
check_for_override (fn, type); check_for_override (fn, type);
/* Add it to CLASSTYPE_METHOD_VEC. */ /* Add it to CLASSTYPE_METHOD_VEC. */
...@@ -1143,22 +1594,10 @@ lazily_declare_fn (special_function_kind sfk, tree type) ...@@ -1143,22 +1594,10 @@ lazily_declare_fn (special_function_kind sfk, tree type)
TYPE_METHODS (type) = fn; TYPE_METHODS (type) = fn;
} }
maybe_add_class_template_decl_list (type, fn, /*friend_p=*/0); maybe_add_class_template_decl_list (type, fn, /*friend_p=*/0);
if (sfk == sfk_copy_assignment) if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (fn)
CLASSTYPE_LAZY_COPY_ASSIGN (type) = 0; || DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (fn))
else /* Create appropriate clones. */
{ clone_function_decl (fn, /*update_method_vec=*/true);
/* 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);
}
return fn; return fn;
} }
......
...@@ -1335,7 +1335,7 @@ lookup_conversion_operator (tree class_type, tree type) ...@@ -1335,7 +1335,7 @@ lookup_conversion_operator (tree class_type, tree type)
} }
/* TYPE is a class type. Return the index of the fields within /* TYPE is a class type. Return the index of the fields within
the method vector with name NAME, or -1 is no such field exists. */ the method vector with name NAME, or -1 if no such field exists. */
int int
lookup_fnfields_1 (tree type, tree name) lookup_fnfields_1 (tree type, tree name)
...@@ -1361,9 +1361,13 @@ lookup_fnfields_1 (tree type, tree name) ...@@ -1361,9 +1361,13 @@ lookup_fnfields_1 (tree type, tree name)
if (CLASSTYPE_LAZY_MOVE_CTOR (type)) if (CLASSTYPE_LAZY_MOVE_CTOR (type))
lazily_declare_fn (sfk_move_constructor, type); lazily_declare_fn (sfk_move_constructor, type);
} }
else if (name == ansi_assopname(NOP_EXPR) else if (name == ansi_assopname (NOP_EXPR))
&& CLASSTYPE_LAZY_COPY_ASSIGN (type)) {
lazily_declare_fn (sfk_copy_assignment, type); if (CLASSTYPE_LAZY_COPY_ASSIGN (type))
lazily_declare_fn (sfk_copy_assignment, type);
if (CLASSTYPE_LAZY_MOVE_ASSIGN (type))
lazily_declare_fn (sfk_move_assignment, type);
}
else if ((name == dtor_identifier else if ((name == dtor_identifier
|| name == base_dtor_identifier || name == base_dtor_identifier
|| name == complete_dtor_identifier || name == complete_dtor_identifier
...@@ -1441,6 +1445,18 @@ lookup_fnfields_1 (tree type, tree name) ...@@ -1441,6 +1445,18 @@ lookup_fnfields_1 (tree type, tree name)
return -1; return -1;
} }
/* TYPE is a class type. Return the field within the method vector with
name NAME, or NULL_TREE if no such field exists. */
tree
lookup_fnfields_slot (tree type, tree name)
{
int ix = lookup_fnfields_1 (type, name);
if (ix < 0)
return NULL_TREE;
return VEC_index (tree, CLASSTYPE_METHOD_VEC (type), ix);
}
/* Like lookup_fnfields_1, except that the name is extracted from /* Like lookup_fnfields_1, except that the name is extracted from
FUNCTION, which is a FUNCTION_DECL or a TEMPLATE_DECL. */ FUNCTION, which is a FUNCTION_DECL or a TEMPLATE_DECL. */
...@@ -1889,6 +1905,7 @@ check_final_overrider (tree overrider, tree basefn) ...@@ -1889,6 +1905,7 @@ check_final_overrider (tree overrider, tree basefn)
{ {
error ("deleted function %q+D", overrider); error ("deleted function %q+D", overrider);
error ("overriding non-deleted function %q+D", basefn); error ("overriding non-deleted function %q+D", basefn);
maybe_explain_implicit_delete (overrider);
} }
else else
{ {
......
...@@ -3527,31 +3527,6 @@ finalize_nrv (tree *tp, tree var, tree result) ...@@ -3527,31 +3527,6 @@ finalize_nrv (tree *tp, tree var, tree result)
htab_delete (data.visited); htab_delete (data.visited);
} }
/* Return the declaration for the function called by CALL_EXPR T,
TYPE is the class type of the clause decl. */
static tree
omp_clause_info_fndecl (tree t, tree type)
{
tree ret = get_callee_fndecl (t);
if (ret)
return ret;
gcc_assert (TREE_CODE (t) == CALL_EXPR);
t = CALL_EXPR_FN (t);
STRIP_NOPS (t);
if (TREE_CODE (t) == OBJ_TYPE_REF)
{
t = cp_fold_obj_type_ref (t, type);
if (TREE_CODE (t) == ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (t, 0)) == FUNCTION_DECL)
return TREE_OPERAND (t, 0);
}
return NULL_TREE;
}
/* Create CP_OMP_CLAUSE_INFO for clause C. Returns true if it is invalid. */ /* Create CP_OMP_CLAUSE_INFO for clause C. Returns true if it is invalid. */
bool bool
...@@ -3569,80 +3544,27 @@ cxx_omp_create_clause_info (tree c, tree type, bool need_default_ctor, ...@@ -3569,80 +3544,27 @@ cxx_omp_create_clause_info (tree c, tree type, bool need_default_ctor,
info = make_tree_vec (3); info = make_tree_vec (3);
CP_OMP_CLAUSE_INFO (c) = info; CP_OMP_CLAUSE_INFO (c) = info;
if (need_default_ctor if (need_default_ctor || need_copy_ctor)
|| (need_copy_ctor && !TYPE_HAS_TRIVIAL_COPY_CTOR (type)))
{ {
VEC(tree,gc) *vec;
if (need_default_ctor) if (need_default_ctor)
vec = NULL; t = get_default_ctor (type);
else else
{ t = get_copy_ctor (type);
t = build_int_cst (build_pointer_type (type), 0);
t = build1 (INDIRECT_REF, type, t);
vec = make_tree_vector_single (t);
}
t = build_special_member_call (NULL_TREE, complete_ctor_identifier,
&vec, type, LOOKUP_NORMAL,
tf_warning_or_error);
if (vec != NULL) if (t && !trivial_fn_p (t))
release_tree_vector (vec); TREE_VEC_ELT (info, 0) = t;
if (targetm.cxx.cdtor_returns_this () || errorcount)
/* Because constructors and destructors return this,
the call will have been cast to "void". Remove the
cast here. We would like to use STRIP_NOPS, but it
wouldn't work here because TYPE_MODE (t) and
TYPE_MODE (TREE_OPERAND (t, 0)) are different.
They are VOIDmode and Pmode, respectively. */
if (TREE_CODE (t) == NOP_EXPR)
t = TREE_OPERAND (t, 0);
TREE_VEC_ELT (info, 0) = get_callee_fndecl (t);
} }
if ((need_default_ctor || need_copy_ctor) if ((need_default_ctor || need_copy_ctor)
&& TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)) && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
{ TREE_VEC_ELT (info, 1) = get_dtor (type);
t = build_int_cst (build_pointer_type (type), 0);
t = build1 (INDIRECT_REF, type, t);
t = build_special_member_call (t, complete_dtor_identifier,
NULL, type, LOOKUP_NORMAL,
tf_warning_or_error);
if (targetm.cxx.cdtor_returns_this () || errorcount) if (need_copy_assignment)
/* Because constructors and destructors return this,
the call will have been cast to "void". Remove the
cast here. We would like to use STRIP_NOPS, but it
wouldn't work here because TYPE_MODE (t) and
TYPE_MODE (TREE_OPERAND (t, 0)) are different.
They are VOIDmode and Pmode, respectively. */
if (TREE_CODE (t) == NOP_EXPR)
t = TREE_OPERAND (t, 0);
TREE_VEC_ELT (info, 1) = omp_clause_info_fndecl (t, type);
}
if (need_copy_assignment && !TYPE_HAS_TRIVIAL_COPY_ASSIGN (type))
{ {
VEC(tree,gc) *vec; t = get_copy_assign (type);
t = build_int_cst (build_pointer_type (type), 0);
t = build1 (INDIRECT_REF, type, t);
vec = make_tree_vector_single (t);
t = build_special_member_call (t, ansi_assopname (NOP_EXPR),
&vec, type, LOOKUP_NORMAL,
tf_warning_or_error);
release_tree_vector (vec);
/* We'll have called convert_from_reference on the call, which
may well have added an indirect_ref. It's unneeded here,
and in the way, so kill it. */
if (TREE_CODE (t) == INDIRECT_REF)
t = TREE_OPERAND (t, 0);
TREE_VEC_ELT (info, 2) = omp_clause_info_fndecl (t, type); if (t && !trivial_fn_p (t))
TREE_VEC_ELT (info, 2) = t;
} }
return errorcount != save_errorcount; return errorcount != save_errorcount;
...@@ -5076,7 +4998,7 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2) ...@@ -5076,7 +4998,7 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
type1 = strip_array_types (type1); type1 = strip_array_types (type1);
return (trait_expr_value (CPTK_HAS_TRIVIAL_CONSTRUCTOR, type1, type2) return (trait_expr_value (CPTK_HAS_TRIVIAL_CONSTRUCTOR, type1, type2)
|| (CLASS_TYPE_P (type1) || (CLASS_TYPE_P (type1)
&& (t = locate_ctor (type1, NULL)) && (t = locate_ctor (type1))
&& TYPE_NOTHROW_P (TREE_TYPE (t)))); && TYPE_NOTHROW_P (TREE_TYPE (t))));
case CPTK_HAS_TRIVIAL_CONSTRUCTOR: case CPTK_HAS_TRIVIAL_CONSTRUCTOR:
......
...@@ -2847,7 +2847,12 @@ special_function_p (const_tree decl) ...@@ -2847,7 +2847,12 @@ special_function_p (const_tree decl)
if (DECL_CONSTRUCTOR_P (decl)) if (DECL_CONSTRUCTOR_P (decl))
return sfk_constructor; return sfk_constructor;
if (DECL_OVERLOADED_OPERATOR_P (decl) == NOP_EXPR) if (DECL_OVERLOADED_OPERATOR_P (decl) == NOP_EXPR)
return sfk_copy_assignment; {
if (copy_fn_p (decl))
return sfk_copy_assignment;
if (move_fn_p (decl))
return sfk_move_assignment;
}
if (DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (decl)) if (DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (decl))
return sfk_destructor; return sfk_destructor;
if (DECL_COMPLETE_DESTRUCTOR_P (decl)) if (DECL_COMPLETE_DESTRUCTOR_P (decl))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment