re PR c++/44909 ([C++0x] Copy constructors implicitly deleted)
authorJason Merrill <jason@redhat.com>
Tue, 13 Jul 2010 22:23:49 +0000 (18:23 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Tue, 13 Jul 2010 22:23:49 +0000 (18:23 -0400)
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.

From-SVN: r162159

gcc/cp/ChangeLog
gcc/cp/class.c
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/method.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/implicit6.C [new file with mode: 0644]
gcc/testsuite/g++.dg/parse/error28.C

index c076929..98c6220 100644 (file)
@@ -1,5 +1,15 @@
 2010-07-13  Jason Merrill  <jason@redhat.com>
 
+       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.
index dfb2cd9..ed7367c 100644 (file)
@@ -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.  */
index cf128dc..8b076d3 100644 (file)
@@ -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
index 541f77e..1491720 100644 (file)
@@ -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;
index ad41e9a..b09064b 100644 (file)
@@ -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:
index b998da3..aa86ae3 100644 (file)
@@ -1,5 +1,10 @@
 2010-07-13  Jason Merrill  <jason@redhat.com>
 
+       PR c++/44909
+       * g++.dg/cpp0x/implicit6.C: New.
+
+2010-07-13  Jason Merrill  <jason@redhat.com>
+
        PR c++/44540
        * g++.dg/abi/noreturn1.C: New.
        * g++.dg/abi/noreturn2.C: New.
diff --git a/gcc/testsuite/g++.dg/cpp0x/implicit6.C b/gcc/testsuite/g++.dg/cpp0x/implicit6.C
new file mode 100644 (file)
index 0000000..e517333
--- /dev/null
@@ -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;
index 7e235a1..a0b1e7f 100644 (file)
@@ -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" }