aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2010-06-29 20:50:57 -0400
committerJason Merrill <jason@gcc.gnu.org>2010-06-29 20:50:57 -0400
commitac1774315cb7ebc781ade2f9fd99de1c258b9221 (patch)
tree0e8e64d29daa126b9fc1f87bfe35a0967270da6d
parent4640884658bae7ba9ff09068efcbe4b7e94baf8d (diff)
downloadgcc-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
-rw-r--r--gcc/cp/ChangeLog41
-rw-r--r--gcc/cp/call.c54
-rw-r--r--gcc/cp/class.c64
-rw-r--r--gcc/cp/cp-tree.h45
-rw-r--r--gcc/cp/decl.c4
-rw-r--r--gcc/cp/method.c757
-rw-r--r--gcc/cp/search.c25
-rw-r--r--gcc/cp/semantics.c100
-rw-r--r--gcc/cp/tree.c7
9 files changed, 822 insertions, 275 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index bc02bd0..a8df233 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,5 +1,46 @@
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.
* cp-tree.h: Declare it.
* semantics.c (trait_expr_value): Use it.
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 852c7ea..9f4a520 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -5613,6 +5613,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
if (DECL_FUNCTION_MEMBER_P (fn))
{
+ tree access_fn;
/* If FN is a template function, two cases must be considered.
For example:
@@ -5640,10 +5641,41 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
different access. */
if (DECL_TEMPLATE_INFO (fn)
&& DECL_MEMBER_TEMPLATE_P (DECL_TI_TEMPLATE (fn)))
- perform_or_defer_access_check (cand->access_path,
- DECL_TI_TEMPLATE (fn), fn);
+ access_fn = DECL_TI_TEMPLATE (fn);
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. */
@@ -5824,6 +5856,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
tree targ;
tree arg = argarray[num_artificial_parms_for (fn)];
tree fa;
+ bool trivial = trivial_fn_p (fn);
/* Pull out the real argument, disregarding const-correctness. */
targ = arg;
@@ -5848,13 +5881,12 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
if (TREE_CODE (arg) == TARGET_EXPR
&& 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. */
}
/* [class.copy]: the copy constructor is implicitly defined even if
the implementation elided its use. */
- else if (TYPE_HAS_COMPLEX_COPY_CTOR (DECL_CONTEXT (fn))
- || move_fn_p (fn))
+ else if (!trivial)
{
mark_used (fn);
already_used = true;
@@ -5872,13 +5904,10 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
{
if (TREE_CODE (arg) == TARGET_EXPR)
return arg;
- else if (TYPE_HAS_TRIVIAL_COPY_CTOR (DECL_CONTEXT (fn))
- && !move_fn_p (fn))
+ else if (trivial)
return build_target_expr_with_type (arg, DECL_CONTEXT (fn));
}
- else if (TREE_CODE (arg) == TARGET_EXPR
- || (TYPE_HAS_TRIVIAL_COPY_CTOR (DECL_CONTEXT (fn))
- && !move_fn_p (fn)))
+ else if (TREE_CODE (arg) == TARGET_EXPR || trivial)
{
tree to = stabilize_reference (cp_build_indirect_ref (fa, RO_NULL,
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
- && copy_fn_p (fn)
- && TYPE_HAS_TRIVIAL_COPY_ASSIGN (DECL_CONTEXT (fn)))
+ && trivial_fn_p (fn))
{
tree to = stabilize_reference
(cp_build_indirect_ref (argarray[0], RO_NULL, complain));
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index bfd3113..6f6aab6 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -1314,10 +1314,14 @@ check_bases (tree t,
TYPE_HAS_COMPLEX_COPY_ASSIGN (t)
|= TYPE_HAS_COMPLEX_COPY_ASSIGN (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);
CLASSTYPE_CONTAINS_EMPTY_CLASS_P (t)
|= 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:
...
@@ -2670,6 +2674,7 @@ add_implicitly_declared_members (tree t,
a virtual function from a base class. */
if (TYPE_POLYMORPHIC_P (t)
&& (CLASSTYPE_LAZY_COPY_ASSIGN (t)
+ || CLASSTYPE_LAZY_MOVE_ASSIGN (t)
|| CLASSTYPE_LAZY_DESTRUCTOR (t)))
{
tree binfo = TYPE_BINFO (t);
@@ -2686,6 +2691,8 @@ add_implicitly_declared_members (tree t,
{
if (CLASSTYPE_LAZY_COPY_ASSIGN (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)
&& CLASSTYPE_LAZY_DESTRUCTOR (t))
@@ -2848,6 +2855,8 @@ check_field_decl (tree field,
if (TYPE_HAS_COMPLEX_COPY_ASSIGN (type))
error ("member %q+#D with copy assignment operator not allowed in union",
field);
+ /* Don't bother diagnosing move assop now; C++0x has more
+ flexible unions. */
}
else
{
@@ -2856,7 +2865,10 @@ check_field_decl (tree field,
|= TYPE_HAS_NONTRIVIAL_DESTRUCTOR (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_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))
@@ -3022,6 +3034,7 @@ check_field_decls (tree t, tree *access_decls,
only way to initialize nonstatic const and reference
members. */
TYPE_HAS_COMPLEX_COPY_ASSIGN (t) = 1;
+ TYPE_HAS_COMPLEX_MOVE_ASSIGN (t) = 1;
}
type = strip_array_types (type);
@@ -3108,6 +3121,7 @@ check_field_decls (tree t, tree *access_decls,
only way to initialize nonstatic const and reference
members. */
TYPE_HAS_COMPLEX_COPY_ASSIGN (t) = 1;
+ TYPE_HAS_COMPLEX_MOVE_ASSIGN (t) = 1;
}
/* A field that is pseudo-const makes the structure likewise. */
else if (CLASS_TYPE_P (type))
@@ -4277,6 +4291,50 @@ type_has_virtual_destructor (tree type)
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. */
static void
@@ -4411,6 +4469,7 @@ check_bases_and_members (tree t)
/* Do some bookkeeping that will guide the generation of implicitly
declared member functions. */
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
user-provided constructor, or if the default constructor is going
to initialize the vptr. (This is not an if-and-only-if;
@@ -4434,6 +4493,7 @@ check_bases_and_members (tree t)
|| saved_nontrivial_dtor || saved_complex_asn_ref);
CLASSTYPE_NON_STD_LAYOUT (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);
/* If the class has no user-declared constructor, but does have
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index bfdf036..1d9077c 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1307,10 +1307,13 @@ struct GTY(()) lang_type_class {
unsigned has_complex_dflt : 1;
unsigned has_list_ctor : 1;
unsigned non_std_layout : 1;
- unsigned lazy_move_ctor : 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
apply to a template instance if it applies to the template. If
so, make sure to copy it in instantiate_class_template! */
@@ -1318,7 +1321,7 @@ struct GTY(()) lang_type_class {
/* 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
remove a flag. */
- unsigned dummy : 7;
+ unsigned dummy : 4;
tree primary_base;
VEC(tree_pair_s,gc) *vcall_indices;
@@ -1416,6 +1419,11 @@ struct GTY((variable_size)) lang_type {
#define CLASSTYPE_LAZY_COPY_ASSIGN(NODE) \
(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
it has not yet been declared. */
#define CLASSTYPE_LAZY_DESTRUCTOR(NODE) \
@@ -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. */
#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. */
#define TYPE_HAS_COMPLEX_DFLT(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->has_complex_dflt)
@@ -3869,6 +3883,7 @@ typedef enum special_function_kind {
sfk_copy_constructor, /* A copy constructor. */
sfk_move_constructor, /* A move constructor. */
sfk_copy_assignment, /* A copy assignment operator. */
+ sfk_move_assignment, /* A move assignment operator. */
sfk_destructor, /* A destructor. */
sfk_complete_destructor, /* A destructor for complete objects. */
sfk_base_destructor, /* A destructor for base subobjects. */
@@ -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. */
#define LOOKUP_NO_NARROWING (LOOKUP_PREFER_RVALUE << 1)
/* 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)
/* This is the first parameter of a copy constructor. */
#define LOOKUP_COPY_PARM (LOOKUP_NO_COPY_CTOR_CONVERSION << 1)
/* We only want to consider list constructors. */
#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) \
(((F) & LOOKUP_PREFER_NAMESPACES) && !((F) & LOOKUP_PREFER_TYPES))
@@ -4656,6 +4680,8 @@ extern bool user_provided_p (tree);
extern bool type_has_user_provided_constructor (tree);
extern bool type_has_user_provided_default_constructor (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 bool defaultable_fn_check (tree);
extern void fixup_type_variants (tree);
@@ -4921,15 +4947,19 @@ extern void init_method (void);
extern tree make_thunk (tree, bool, tree, tree);
extern void finish_thunk (tree);
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 tree lazily_declare_fn (special_function_kind,
tree);
extern tree skip_artificial_parms_for (const_tree, tree);
extern int num_artificial_parms_for (const_tree);
extern tree make_alias_for (tree, tree);
-extern tree locate_copy (tree, void *);
-extern tree locate_ctor (tree, void *);
-extern tree locate_dtor (tree, void *);
+extern tree get_copy_ctor (tree);
+extern tree get_copy_assign (tree);
+extern tree get_default_ctor (tree);
+extern tree get_dtor (tree);
+extern tree locate_ctor (tree);
/* In optimize.c */
extern bool maybe_clone_body (tree);
@@ -5070,6 +5100,7 @@ extern int accessible_p (tree, tree, bool);
extern tree lookup_field_1 (tree, tree, bool);
extern tree lookup_field (tree, tree, int, bool);
extern int lookup_fnfields_1 (tree, tree);
+extern tree lookup_fnfields_slot (tree, tree);
extern int class_method_index_for_fn (tree, tree);
extern tree lookup_fnfields (tree, tree, int);
extern tree lookup_member (tree, tree, int, bool);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 0c2f7e5..153bd53 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -10273,6 +10273,8 @@ grok_special_member_properties (tree decl)
if (user_provided_p (decl))
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))
TYPE_HAS_LIST_CTOR (class_type) = 1;
}
@@ -10294,6 +10296,8 @@ grok_special_member_properties (tree decl)
if (assop != 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. */
}
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;
}
diff --git a/gcc/cp/search.c b/gcc/cp/search.c
index d291c08..9dbefd3 100644
--- a/gcc/cp/search.c
+++ b/gcc/cp/search.c
@@ -1335,7 +1335,7 @@ lookup_conversion_operator (tree class_type, tree type)
}
/* 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
lookup_fnfields_1 (tree type, tree name)
@@ -1361,9 +1361,13 @@ lookup_fnfields_1 (tree type, tree name)
if (CLASSTYPE_LAZY_MOVE_CTOR (type))
lazily_declare_fn (sfk_move_constructor, type);
}
- else if (name == ansi_assopname(NOP_EXPR)
- && CLASSTYPE_LAZY_COPY_ASSIGN (type))
- lazily_declare_fn (sfk_copy_assignment, type);
+ else if (name == ansi_assopname (NOP_EXPR))
+ {
+ 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
|| name == base_dtor_identifier
|| name == complete_dtor_identifier
@@ -1441,6 +1445,18 @@ lookup_fnfields_1 (tree type, tree name)
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
FUNCTION, which is a FUNCTION_DECL or a TEMPLATE_DECL. */
@@ -1889,6 +1905,7 @@ check_final_overrider (tree overrider, tree basefn)
{
error ("deleted function %q+D", overrider);
error ("overriding non-deleted function %q+D", basefn);
+ maybe_explain_implicit_delete (overrider);
}
else
{
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index adc5e7f..156f278 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -3527,31 +3527,6 @@ finalize_nrv (tree *tp, tree var, tree result)
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. */
bool
@@ -3569,80 +3544,27 @@ cxx_omp_create_clause_info (tree c, tree type, bool need_default_ctor,
info = make_tree_vec (3);
CP_OMP_CLAUSE_INFO (c) = info;
- if (need_default_ctor
- || (need_copy_ctor && !TYPE_HAS_TRIVIAL_COPY_CTOR (type)))
+ if (need_default_ctor || need_copy_ctor)
{
- VEC(tree,gc) *vec;
-
if (need_default_ctor)
- vec = NULL;
+ t = get_default_ctor (type);
else
- {
- 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);
+ t = get_copy_ctor (type);
- if (vec != NULL)
- release_tree_vector (vec);
-
- 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 (t && !trivial_fn_p (t))
+ TREE_VEC_ELT (info, 0) = t;
}
if ((need_default_ctor || need_copy_ctor)
&& TYPE_HAS_NONTRIVIAL_DESTRUCTOR (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);
+ TREE_VEC_ELT (info, 1) = get_dtor (type);
- 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, 1) = omp_clause_info_fndecl (t, type);
- }
-
- if (need_copy_assignment && !TYPE_HAS_TRIVIAL_COPY_ASSIGN (type))
+ if (need_copy_assignment)
{
- VEC(tree,gc) *vec;
-
- 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);
+ t = get_copy_assign (type);
- 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;
@@ -5076,7 +4998,7 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
type1 = strip_array_types (type1);
return (trait_expr_value (CPTK_HAS_TRIVIAL_CONSTRUCTOR, type1, type2)
|| (CLASS_TYPE_P (type1)
- && (t = locate_ctor (type1, NULL))
+ && (t = locate_ctor (type1))
&& TYPE_NOTHROW_P (TREE_TYPE (t))));
case CPTK_HAS_TRIVIAL_CONSTRUCTOR:
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 7236924..3367a09 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -2847,7 +2847,12 @@ special_function_p (const_tree decl)
if (DECL_CONSTRUCTOR_P (decl))
return sfk_constructor;
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))
return sfk_destructor;
if (DECL_COMPLETE_DESTRUCTOR_P (decl))