diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index c0769292a89..98c6220cd63 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,15 @@ 2010-07-13 Jason Merrill + PR c++/44909 + * cp-tree.h (struct lang_type_class): Add has_user_opeq. + (TYPE_HAS_USER_OPEQ): New. + * decl.c (grok_special_member_properties): Set it. + * class.c (add_implicitly_declared_members): Don't lazily declare + constructors/operator= if a base or member has a user-declared one. + (check_bases_and_members, check_bases): Adjust. + (check_field_decls, check_field_decl): Adjust. + * method.c (synthesized_method_walk): Initialize check_vdtor. + PR c++/44540 * mangle.c (write_type): Canonicalize. (canonicalize_for_substitution): Retain cv-quals on FUNCTION_TYPE. diff --git a/gcc/cp/class.c b/gcc/cp/class.c index dfb2cd942d7..ed7367c95c4 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -130,7 +130,7 @@ static void finish_struct_methods (tree); static void maybe_warn_about_overly_private_class (tree); static int method_name_cmp (const void *, const void *); static int resort_method_name_cmp (const void *, const void *); -static void add_implicitly_declared_members (tree, int, int); +static void add_implicitly_declared_members (tree, int, int, int, int); static tree fixed_type_or_null (tree, int *, int *); static tree build_simple_base_path (tree expr, tree binfo); static tree build_vtbl_ref_1 (tree, tree); @@ -139,13 +139,13 @@ static void build_vtbl_initializer (tree, tree, tree, tree, int *, static int count_fields (tree); static int add_fields_to_record_type (tree, struct sorted_fields_type*, int); static bool check_bitfield_decl (tree); -static void check_field_decl (tree, tree, int *, int *, int *); -static void check_field_decls (tree, tree *, int *, int *); +static void check_field_decl (tree, tree, int *, int *, int *, int *, int *); +static void check_field_decls (tree, tree *, int *, int *, int *, int *); static tree *build_base_field (record_layout_info, tree, splay_tree, tree *); static void build_base_fields (record_layout_info, splay_tree, tree *); static void check_methods (tree); static void remove_zero_width_bit_fields (tree); -static void check_bases (tree, int *, int *); +static void check_bases (tree, int *, int *, int *, int *); static void check_bases_and_members (tree); static tree create_vtable_ptr (tree, tree *); static void include_empty_classes (record_layout_info); @@ -1249,7 +1249,9 @@ handle_using_decl (tree using_decl, tree t) static void check_bases (tree t, int* cant_have_const_ctor_p, - int* no_const_asn_ref_p) + int* no_const_asn_ref_p, + int* cant_have_lazy_ctor, + int* cant_have_lazy_opeq) { int i; int seen_non_virtual_nearly_empty_base_p; @@ -1288,6 +1290,10 @@ check_bases (tree t, if (TYPE_HAS_COPY_ASSIGN (basetype) && !TYPE_HAS_CONST_COPY_ASSIGN (basetype)) *no_const_asn_ref_p = 1; + if (TYPE_HAS_USER_CONSTRUCTOR (basetype)) + *cant_have_lazy_ctor = 1; + if (TYPE_HAS_USER_OPEQ (basetype)) + *cant_have_lazy_opeq = 1; if (BINFO_VIRTUAL_P (base_binfo)) /* A virtual base does not effect nearly emptiness. */ @@ -2628,7 +2634,9 @@ maybe_add_class_template_decl_list (tree type, tree t, int friend_p) static void add_implicitly_declared_members (tree t, int cant_have_const_cctor, - int cant_have_const_assignment) + int cant_have_const_assignment, + int cant_have_lazy_ctor, + int cant_have_lazy_opeq) { /* Destructor. */ if (!CLASSTYPE_DESTRUCTORS (t)) @@ -2682,6 +2690,26 @@ add_implicitly_declared_members (tree t, CLASSTYPE_LAZY_MOVE_ASSIGN (t) = 1; } + /* If a base or member type has a user-declared constructor or operator=, + we need to declare ours now to avoid issues with circular lazy + declarations (cpp0x/implicit6.C). */ + if (cant_have_lazy_ctor) + { + if (CLASSTYPE_LAZY_DEFAULT_CTOR (t)) + lazily_declare_fn (sfk_constructor, t); + if (CLASSTYPE_LAZY_COPY_CTOR (t)) + lazily_declare_fn (sfk_copy_constructor, t); + if (CLASSTYPE_LAZY_MOVE_CTOR (t)) + lazily_declare_fn (sfk_move_constructor, t); + } + if (cant_have_lazy_opeq) + { + 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); + } + /* We can't be lazy about declaring functions that might override a virtual function from a base class. */ if (TYPE_POLYMORPHIC_P (t) @@ -2830,7 +2858,9 @@ check_field_decl (tree field, tree t, int* cant_have_const_ctor, int* no_const_asn_ref, - int* any_default_members) + int* any_default_members, + int* cant_have_lazy_ctor, + int* cant_have_lazy_opeq) { tree type = strip_array_types (TREE_TYPE (field)); @@ -2847,7 +2877,8 @@ check_field_decl (tree field, for (fields = TYPE_FIELDS (type); fields; fields = TREE_CHAIN (fields)) if (TREE_CODE (fields) == FIELD_DECL && !DECL_C_BIT_FIELD (field)) check_field_decl (fields, t, cant_have_const_ctor, - no_const_asn_ref, any_default_members); + no_const_asn_ref, any_default_members, + cant_have_lazy_ctor, cant_have_lazy_opeq); } /* Check members with class type for constructors, destructors, etc. */ @@ -2893,6 +2924,11 @@ check_field_decl (tree field, if (TYPE_HAS_COPY_ASSIGN (type) && !TYPE_HAS_CONST_COPY_ASSIGN (type)) *no_const_asn_ref = 1; + + if (TYPE_HAS_USER_CONSTRUCTOR (type)) + *cant_have_lazy_ctor = 1; + if (TYPE_HAS_USER_OPEQ (type)) + *cant_have_lazy_opeq = 1; } if (DECL_INITIAL (field) != NULL_TREE) { @@ -2932,7 +2968,9 @@ check_field_decl (tree field, static void check_field_decls (tree t, tree *access_decls, int *cant_have_const_ctor_p, - int *no_const_asn_ref_p) + int *no_const_asn_ref_p, + int *cant_have_lazy_ctor_p, + int *cant_have_lazy_opeq_p) { tree *field; tree *next; @@ -3124,7 +3162,9 @@ check_field_decls (tree t, tree *access_decls, check_field_decl (x, t, cant_have_const_ctor_p, no_const_asn_ref_p, - &any_default_members); + &any_default_members, + cant_have_lazy_ctor_p, + cant_have_lazy_opeq_p); /* If any field is const, the structure type is pseudo-const. */ if (CP_TYPE_CONST_P (type)) @@ -4447,6 +4487,8 @@ check_bases_and_members (tree t) /* Nonzero if the implicitly generated assignment operator should take a non-const reference argument. */ int no_const_asn_ref; + int cant_have_lazy_ctor = 0; + int cant_have_lazy_opeq = 0; tree access_decls; bool saved_complex_asn_ref; bool saved_nontrivial_dtor; @@ -4459,7 +4501,8 @@ check_bases_and_members (tree t) /* Check all the base-classes. */ check_bases (t, &cant_have_const_ctor, - &no_const_asn_ref); + &no_const_asn_ref, &cant_have_lazy_ctor, + &cant_have_lazy_opeq); /* Check all the method declarations. */ check_methods (t); @@ -4476,7 +4519,9 @@ check_bases_and_members (tree t) being set appropriately. */ check_field_decls (t, &access_decls, &cant_have_const_ctor, - &no_const_asn_ref); + &no_const_asn_ref, + &cant_have_lazy_ctor, + &cant_have_lazy_opeq); /* A nearly-empty class has to be vptr-containing; a nearly empty class contains just a vptr. */ @@ -4548,7 +4593,9 @@ check_bases_and_members (tree t) /* Synthesize any needed methods. */ add_implicitly_declared_members (t, cant_have_const_ctor, - no_const_asn_ref); + no_const_asn_ref, + cant_have_lazy_ctor, + cant_have_lazy_opeq); /* Check defaulted declarations here so we have cant_have_const_ctor and don't need to worry about clones. */ diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index cf128dc315a..8b076d358c0 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1326,6 +1326,7 @@ struct GTY(()) lang_type_class { unsigned lazy_move_assign : 1; unsigned has_complex_move_ctor : 1; unsigned has_complex_move_assign : 1; + unsigned has_user_opeq : 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 @@ -1334,7 +1335,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 : 4; + unsigned dummy : 3; tree primary_base; VEC(tree_pair_s,gc) *vcall_indices; @@ -3142,6 +3143,10 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) user-declared constructor. */ #define TYPE_HAS_USER_CONSTRUCTOR(NODE) (TYPE_LANG_FLAG_1 (NODE)) +/* ...or a user-declared operator=. */ +#define TYPE_HAS_USER_OPEQ(NODE) \ + (LANG_TYPE_CLASS_CHECK (NODE)->has_user_opeq) + /* When appearing in an INDIRECT_REF, it means that the tree structure underneath is actually a call to a constructor. This is needed when the constructor must initialize local storage (which can diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 541f77ecf08..1491720a972 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -10293,6 +10293,8 @@ grok_special_member_properties (tree decl) int assop = copy_fn_p (decl); + if (!DECL_ARTIFICIAL (decl)) + TYPE_HAS_USER_OPEQ (class_type) = 1; if (assop) { TYPE_HAS_COPY_ASSIGN (class_type) = 1; diff --git a/gcc/cp/method.c b/gcc/cp/method.c index ad41e9acc57..b09064b7cc0 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -1004,6 +1004,7 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p, #endif assign_p = false; + check_vdtor = false; switch (sfk) { case sfk_move_assignment: diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index b998da373c4..aa86ae395b9 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2010-07-13 Jason Merrill + + PR c++/44909 + * g++.dg/cpp0x/implicit6.C: New. + 2010-07-13 Jason Merrill PR c++/44540 diff --git a/gcc/testsuite/g++.dg/cpp0x/implicit6.C b/gcc/testsuite/g++.dg/cpp0x/implicit6.C new file mode 100644 index 00000000000..e517333773f --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/implicit6.C @@ -0,0 +1,25 @@ +// Circular implicit declarations were causing errors +// { dg-options -std=c++0x } + +struct Ray; + +struct Vector +{ + virtual void f(); // make non-trivially-copyable + Vector(); + Vector(const Ray &) ; +}; + +struct array +{ + Vector v; +}; + +struct Ray +{ + array a; + operator Vector(); +}; + +extern Ray r1; +Ray r2=r1; diff --git a/gcc/testsuite/g++.dg/parse/error28.C b/gcc/testsuite/g++.dg/parse/error28.C index 7e235a13b21..a0b1e7f690f 100644 --- a/gcc/testsuite/g++.dg/parse/error28.C +++ b/gcc/testsuite/g++.dg/parse/error28.C @@ -3,7 +3,7 @@ struct virt { virt () {} virt (int i) {} }; struct der : public virtual virt { // { dg-message "8:der::der" } - der (int i) : virt(i) {} // { dg-message "3:candidates are: der" } + der (int i) : virt(i) {} // { dg-message "3:der::der" } }; struct top : public der { top () {} // { dg-bogus "der\\(const" }