OSDN Git Service

cp:
authornathan <nathan@138bc75d-0d04-0410-961f-82ee72b054a4>
Sun, 9 Dec 2001 16:33:44 +0000 (16:33 +0000)
committernathan <nathan@138bc75d-0d04-0410-961f-82ee72b054a4>
Sun, 9 Dec 2001 16:33:44 +0000 (16:33 +0000)
PR g++/87
* cp-tree.h (DECL_COPY_CONSTRUCTOR_P): Use copy_fn_p.
(copy_args_p): Rename to ...
(copy_fn_p): ... here.
(grok_special_member_properties): New function.
(grok_op_properties): Lose VIRTUALP parameter.
(copy_assignment_arg_p): Remove.
* call.c (build_over_call): Use copy_fn_p.
* decl.c (grokfndecl): Reformat. Adjust call to
grok_op_properties.
(copy_args_p): Rename to ...
(copy_fn_p): ... here. Reject template functions. Check for pass
by value.
(grok_special_member_properties): Remember special functions.
(grok_ctor_properties): Don't remember them here, just check.
(grok_op_properties): Likewise.
(start_method): Call grok_special_member_properties.
* decl2.c (grokfield): Likewise.
(copy_assignment_arg_p): Remove.
(grok_function_init): Don't remember abstract assignment here.
* pt.c (instantiate_class_template): Call
grok_special_member_properties.
(tsubst_decl): Adjust grok_op_properties call.
testsuite:
* g++.dg/other/copy1.C: New test.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@47813 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/decl2.c
gcc/cp/pt.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/other/copy1.C [new file with mode: 0644]

index d8004b6..ea344c4 100644 (file)
@@ -1,3 +1,29 @@
+2001-12-04  Nathan Sidwell  <nathan@codesourcery.com>
+
+       PR g++/87
+       * cp-tree.h (DECL_COPY_CONSTRUCTOR_P): Use copy_fn_p.
+       (copy_args_p): Rename to ...
+       (copy_fn_p): ... here.
+       (grok_special_member_properties): New function.
+       (grok_op_properties): Lose VIRTUALP parameter.
+       (copy_assignment_arg_p): Remove.
+       * call.c (build_over_call): Use copy_fn_p.
+       * decl.c (grokfndecl): Reformat. Adjust call to
+       grok_op_properties.
+       (copy_args_p): Rename to ...
+       (copy_fn_p): ... here. Reject template functions. Check for pass
+       by value.
+       (grok_special_member_properties): Remember special functions.
+       (grok_ctor_properties): Don't remember them here, just check.
+       (grok_op_properties): Likewise.
+       (start_method): Call grok_special_member_properties.
+       * decl2.c (grokfield): Likewise.
+       (copy_assignment_arg_p): Remove.
+       (grok_function_init): Don't remember abstract assignment here.
+       * pt.c (instantiate_class_template): Call
+       grok_special_member_properties.
+       (tsubst_decl): Adjust grok_op_properties call.
+
 2001-12-08  Aldy Hernandez  <aldyh@redhat.com>
 
         * lex.c (rid_to_yy): Add RID_CHOOSE_EXPR and
index 0a59b17..21049b8 100644 (file)
@@ -4280,7 +4280,7 @@ build_over_call (cand, args, flags)
        }
     }
   else if (DECL_OVERLOADED_OPERATOR_P (fn) == NOP_EXPR
-          && copy_args_p (fn)
+          && copy_fn_p (fn)
           && TYPE_HAS_TRIVIAL_ASSIGN_REF (DECL_CONTEXT (fn)))
     {
       tree to = stabilize_reference
index 992c708..6172adf 100644 (file)
@@ -1841,7 +1841,7 @@ struct lang_decl
 
 /* Nonzero if NODE (a FUNCTION_DECL) is a copy constructor.  */
 #define DECL_COPY_CONSTRUCTOR_P(NODE) \
-  (DECL_CONSTRUCTOR_P (NODE) && copy_args_p (NODE))
+  (DECL_CONSTRUCTOR_P (NODE) && copy_fn_p (NODE) > 0)
 
 /* Nonzero if NODE is a destructor.  */
 #define DECL_DESTRUCTOR_P(NODE)                                \
@@ -3690,9 +3690,10 @@ extern int complete_array_type                   PARAMS ((tree, tree, int));
 extern tree build_ptrmemfunc_type              PARAMS ((tree));
 /* the grokdeclarator prototype is in decl.h */
 extern int parmlist_is_exprlist                        PARAMS ((tree));
-extern int copy_args_p                         PARAMS ((tree));
+extern int copy_fn_p                           PARAMS ((tree));
+extern void grok_special_member_properties     PARAMS ((tree));
 extern int grok_ctor_properties                        PARAMS ((tree, tree));
-extern void grok_op_properties                 PARAMS ((tree, int, int));
+extern void grok_op_properties                 PARAMS ((tree, int));
 extern tree xref_tag                           PARAMS ((tree, tree, int));
 extern tree xref_tag_from_type                 PARAMS ((tree, tree, int));
 extern void xref_basetypes                     PARAMS ((tree, tree, tree, tree));
@@ -3757,7 +3758,6 @@ extern tree grokfield                             PARAMS ((tree, tree, tree, tree, tree));
 extern tree grokbitfield                       PARAMS ((tree, tree, tree));
 extern tree groktypefield                      PARAMS ((tree, tree));
 extern tree grokoptypename                     PARAMS ((tree, tree));
-extern int copy_assignment_arg_p               PARAMS ((tree, int));
 extern void cplus_decl_attributes              PARAMS ((tree *, tree, int));
 extern tree constructor_name_full              PARAMS ((tree));
 extern tree constructor_name                   PARAMS ((tree));
index 66aa70d..26d3a24 100644 (file)
@@ -8789,9 +8789,7 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals,
   tree t;
 
   if (raises)
-    {
-      type = build_exception_variant (type, raises);
-    }
+    type = build_exception_variant (type, raises);
 
   decl = build_lang_decl (FUNCTION_DECL, declarator, type);
   /* Propagate volatile out from type to decl. */
@@ -8902,7 +8900,7 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals,
     }
 
   if (IDENTIFIER_OPNAME_P (DECL_NAME (decl)))
-    grok_op_properties (decl, virtualp, check < 0);
+    grok_op_properties (decl, friendp);
 
   if (ctype && decl_function_context (decl))
     DECL_NO_STATIC_CHAIN (decl) = 1;
@@ -12053,90 +12051,150 @@ grokparms (first_parm)
 }
 
 \f
-/* D is a constructor or overloaded `operator='.  Returns non-zero if
-   D's arguments allow it to be a copy constructor, or copy assignment
+/* D is a constructor or overloaded `operator='.
+
+   Let T be the class in which D is declared. Then, this function
+   returns:
+
+   -1 if D's is an ill-formed constructor or copy assignment operator
+      whose first parameter is of type `T'.
+   0  if D is not a copy constructor or copy assignment
+      operator.
+   1  if D is a copy constructor or copy assignment operator whose
+      first parameter is a reference to const qualified T.
+   2  if D is a copy constructor or copy assignment operator whose
+      first parameter is a reference to non-const qualified T.
+
+   This function can be used as a predicate. Positive values indicate
+   a copy constructor and non-zero values indicate a copy assignment
    operator.  */
 
 int
-copy_args_p (d)
+copy_fn_p (d)
      tree d;
 {
-  tree t;
+  tree args;
+  tree arg_type;
+  int result = 1;
+  
+  my_friendly_assert (DECL_FUNCTION_MEMBER_P (d), 20011208);
 
-  if (!DECL_FUNCTION_MEMBER_P (d))
+  if (DECL_TEMPLATE_INFO (d) && is_member_template (DECL_TI_TEMPLATE (d)))
+    /* Instantiations of template member functions are never copy
+       functions.  Note that member functions of templated classes are
+       represented as template functions internally, and we must
+       accept those as copy functions.  */
+    return 0;
+    
+  args = FUNCTION_FIRST_USER_PARMTYPE (d);
+  if (!args)
     return 0;
 
-  t = FUNCTION_FIRST_USER_PARMTYPE (d);
-  if (t && TREE_CODE (TREE_VALUE (t)) == REFERENCE_TYPE
-      && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_VALUE (t)))
-         == DECL_CONTEXT (d))
-      && (TREE_CHAIN (t) == NULL_TREE
-         || TREE_CHAIN (t) == void_list_node
-         || TREE_PURPOSE (TREE_CHAIN (t))))
-    return 1;
-  return 0;
+  arg_type = TREE_VALUE (args);
+
+  if (TYPE_MAIN_VARIANT (arg_type) == DECL_CONTEXT (d))
+    {
+      /* Pass by value copy assignment operator.  */
+      result = -1;
+    }
+  else if (TREE_CODE (arg_type) == REFERENCE_TYPE
+          && TYPE_MAIN_VARIANT (TREE_TYPE (arg_type)) == DECL_CONTEXT (d))
+    {
+      if (CP_TYPE_CONST_P (TREE_TYPE (arg_type)))
+       result = 2;
+    }
+  else
+    return 0;
+  
+  args = TREE_CHAIN (args);
+
+  if (args && args != void_list_node && !TREE_PURPOSE (args))
+    /* There are more non-optional args.  */
+    return 0;
+
+  return result;
 }
 
-/* These memoizing functions keep track of special properties which
-   a class may have.  `grok_ctor_properties' notices whether a class
-   has a constructor of the form X(X&), and also complains
-   if the class has a constructor of the form X(X).
-   `grok_op_properties' takes notice of the various forms of
-   operator= which are defined, as well as what sorts of type conversion
-   may apply.  Both functions take a FUNCTION_DECL as an argument.  */
+/* Remember any special properties of member function DECL.  */
+
+void grok_special_member_properties (decl)
+     tree decl;
+{
+  if (!DECL_NONSTATIC_MEMBER_FUNCTION_P(decl))
+    ; /* Not special.  */
+  else if (DECL_CONSTRUCTOR_P (decl))
+    {
+      int ctor = copy_fn_p (decl);
+      
+      if (ctor > 0)
+       {
+         /* [class.copy]
+             
+            A non-template constructor for class X is a copy
+            constructor if its first parameter is of type X&, const
+            X&, volatile X& or const volatile X&, and either there
+            are no other parameters or else all other parameters have
+            default arguments.  */
+         TYPE_HAS_INIT_REF (DECL_CONTEXT (decl)) = 1;
+         if (ctor > 1)
+           TYPE_HAS_CONST_INIT_REF (DECL_CONTEXT (decl)) = 1;
+       }
+      else if (sufficient_parms_p (FUNCTION_FIRST_USER_PARMTYPE (decl)))
+       TYPE_HAS_DEFAULT_CONSTRUCTOR (DECL_CONTEXT (decl)) = 1;
+    }
+  else if (DECL_OVERLOADED_OPERATOR_P (decl) == NOP_EXPR)
+    {
+      /* [class.copy]
+         
+        A non-template assignment operator for class X is a copy
+        assignment operator if its parameter is of type X, X&, const
+        X&, volatile X& or const volatile X&.  */
+      
+      int assop = copy_fn_p (decl);
+      
+      if (assop)
+       {
+         TYPE_HAS_ASSIGN_REF (DECL_CONTEXT (decl)) = 1;
+         if (assop != 1)
+           TYPE_HAS_CONST_ASSIGN_REF (DECL_CONTEXT (decl)) = 1;
+         if (DECL_PURE_VIRTUAL_P (decl))
+           TYPE_HAS_ABSTRACT_ASSIGN_REF (DECL_CONTEXT (decl)) = 1;
+       }
+    }
+}
+
+/* Check a constructor DECL has the correct form.  Complains
+   if the class has a constructor of the form X(X).  */
 
 int
 grok_ctor_properties (ctype, decl)
      tree ctype, decl;
 {
-  tree parmtypes = FUNCTION_FIRST_USER_PARMTYPE (decl);
-  tree parmtype = parmtypes ? TREE_VALUE (parmtypes) : void_type_node;
-
-  /* [class.copy]
-
-     A non-template constructor for class X is a copy constructor if
-     its first parameter is of type X&, const X&, volatile X& or const
-     volatile X&, and either there are no other parameters or else all
-     other parameters have default arguments.  */
-  if (TREE_CODE (parmtype) == REFERENCE_TYPE
-      && TYPE_MAIN_VARIANT (TREE_TYPE (parmtype)) == ctype
-      && sufficient_parms_p (TREE_CHAIN (parmtypes))
-      && !(DECL_TEMPLATE_INSTANTIATION (decl)
-          && is_member_template (DECL_TI_TEMPLATE (decl))))
-    {
-      TYPE_HAS_INIT_REF (ctype) = 1;
-      if (CP_TYPE_CONST_P (TREE_TYPE (parmtype)))
-       TYPE_HAS_CONST_INIT_REF (ctype) = 1;
-    }
-  /* [class.copy]
-
-     A declaration of a constructor for a class X is ill-formed if its
-     first parameter is of type (optionally cv-qualified) X and either
-     there are no other parameters or else all other parameters have
-     default arguments.
-
-     We *don't* complain about member template instantiations that
-     have this form, though; they can occur as we try to decide what
-     constructor to use during overload resolution.  Since overload
-     resolution will never prefer such a constructor to the
-     non-template copy constructor (which is either explicitly or
-     implicitly defined), there's no need to worry about their
-     existence.  Theoretically, they should never even be
-     instantiated, but that's hard to forestall.  */
-  else if (TYPE_MAIN_VARIANT (parmtype) == ctype
-          && sufficient_parms_p (TREE_CHAIN (parmtypes))
-          && !(DECL_TEMPLATE_INSTANTIATION (decl)
-               && is_member_template (DECL_TI_TEMPLATE (decl))))
-    {
+  int ctor_parm = copy_fn_p (decl);
+
+  if (ctor_parm < 0)
+    {
+      /* [class.copy]
+         
+        A declaration of a constructor for a class X is ill-formed if
+        its first parameter is of type (optionally cv-qualified) X
+        and either there are no other parameters or else all other
+        parameters have default arguments.
+         
+        We *don't* complain about member template instantiations that
+        have this form, though; they can occur as we try to decide
+        what constructor to use during overload resolution.  Since
+        overload resolution will never prefer such a constructor to
+        the non-template copy constructor (which is either explicitly
+        or implicitly defined), there's no need to worry about their
+        existence.  Theoretically, they should never even be
+        instantiated, but that's hard to forestall.  */
       cp_error ("invalid constructor; you probably meant `%T (const %T&)'",
                ctype, ctype);
       SET_IDENTIFIER_ERROR_LOCUS (DECL_NAME (decl), ctype);
       return 0;
     }
-  else if (TREE_CODE (parmtype) == VOID_TYPE
-          || TREE_PURPOSE (parmtypes) != NULL_TREE)
-    TYPE_HAS_DEFAULT_CONSTRUCTOR (ctype) = 1;
-
+  
   return 1;
 }
 
@@ -12169,9 +12227,9 @@ unary_op_p (code)
 /* Do a little sanity-checking on how they declared their operator.  */
 
 void
-grok_op_properties (decl, virtualp, friendp)
+grok_op_properties (decl, friendp)
      tree decl;
-     int virtualp, friendp;
+     int friendp;
 {
   tree argtypes = TYPE_ARG_TYPES (TREE_TYPE (decl));
   tree argtype;
@@ -12341,37 +12399,7 @@ grok_op_properties (decl, virtualp, friendp)
                         ref ? "a reference to " : "", what);
            }
        }
-
-      if (DECL_ASSIGNMENT_OPERATOR_P (decl)
-         && operator_code == NOP_EXPR)
-       {
-         tree parmtype;
-
-         if (arity != 2 && methodp)
-           {
-             cp_error ("`%D' must take exactly one argument", decl);
-             return;
-           }
-         parmtype = TREE_VALUE (TREE_CHAIN (argtypes));
-
-         /* [class.copy]
-
-            A user-declared copy assignment operator X::operator= is
-            a non-static non-template member function of class X with
-            exactly one parameter of type X, X&, const X&, volatile
-            X& or const volatile X&.  */
-         if (copy_assignment_arg_p (parmtype, virtualp)
-             && !(DECL_TEMPLATE_INSTANTIATION (decl)
-                  && is_member_template (DECL_TI_TEMPLATE (decl)))
-             && ! friendp)
-           {
-             TYPE_HAS_ASSIGN_REF (current_class_type) = 1;
-             if (TREE_CODE (parmtype) != REFERENCE_TYPE
-                 || CP_TYPE_CONST_P (TREE_TYPE (parmtype)))
-               TYPE_HAS_CONST_ASSIGN_REF (current_class_type) = 1;
-           }
-       }
-      else if (operator_code == COND_EXPR)
+      if (operator_code == COND_EXPR)
        {
          /* 13.4.0.3 */
          cp_error ("ISO C++ prohibits overloading operator ?:");
@@ -12507,7 +12535,7 @@ grok_op_properties (decl, virtualp, friendp)
          && TREE_CODE (TREE_TYPE (TREE_TYPE (decl))) == REFERENCE_TYPE)
        cp_warning ("`%D' should return by value", decl);
 
-      /* 13.4.0.8 */
+      /* [over.oper]/8 */
       for (; argtypes && argtypes != void_list_node;
           argtypes = TREE_CHAIN (argtypes))
         if (TREE_PURPOSE (argtypes))
@@ -14244,14 +14272,7 @@ start_method (declspecs, declarator, attrlist)
          fndecl = copy_node (fndecl);
          TREE_CHAIN (fndecl) = NULL_TREE;
        }
-
-      if (DECL_CONSTRUCTOR_P (fndecl))
-       {
-         if (! grok_ctor_properties (current_class_type, fndecl))
-           return void_type_node;
-       }
-      else if (IDENTIFIER_OPNAME_P (DECL_NAME (fndecl)))
-       grok_op_properties (fndecl, DECL_VIRTUAL_P (fndecl), 0);
+      grok_special_member_properties (fndecl);
     }
 
   cp_finish_decl (fndecl, NULL_TREE, NULL_TREE, 0);
index 737d295..e625d96 100644 (file)
@@ -1645,6 +1645,9 @@ grokfield (declarator, declspecs, init, asmspec_tree, attrlist)
          SET_DECL_RTL (value, NULL_RTX);
          SET_DECL_ASSEMBLER_NAME (value, get_identifier (asmspec));
        }
+      if (!DECL_FRIEND_P (value))
+       grok_special_member_properties (value);
+      
       cp_finish_decl (value, init, asmspec_tree, flags);
 
       /* Pass friends back this way.  */
@@ -1762,28 +1765,6 @@ grokoptypename (declspecs, declarator)
 
 */
 
-int
-copy_assignment_arg_p (parmtype, virtualp)
-     tree parmtype;
-     int virtualp ATTRIBUTE_UNUSED;
-{
-  if (current_class_type == NULL_TREE)
-    return 0;
-
-  if (TREE_CODE (parmtype) == REFERENCE_TYPE)
-    parmtype = TREE_TYPE (parmtype);
-
-  if ((TYPE_MAIN_VARIANT (parmtype) == current_class_type)
-#if 0
-      /* Non-standard hack to support old Booch components.  */
-      || (! virtualp && DERIVED_FROM_P (parmtype, current_class_type))
-#endif
-      )
-    return 1;
-
-  return 0;
-}
-
 static void
 grok_function_init (decl, init)
      tree decl;
@@ -1796,17 +1777,7 @@ grok_function_init (decl, init)
   if (TREE_CODE (type) == FUNCTION_TYPE)
     cp_error ("initializer specified for non-member function `%D'", decl);
   else if (integer_zerop (init))
-    {
-      DECL_PURE_VIRTUAL_P (decl) = 1;
-      if (DECL_OVERLOADED_OPERATOR_P (decl) == NOP_EXPR)
-       {
-         tree parmtype
-           = TREE_VALUE (TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (decl))));
-
-         if (copy_assignment_arg_p (parmtype, 1))
-           TYPE_HAS_ABSTRACT_ASSIGN_REF (current_class_type) = 1;
-       }
-    }
+    DECL_PURE_VIRTUAL_P (decl) = 1;
   else
     cp_error ("invalid initializer for virtual method `%D'", decl);
 }
index 8e620be..48f3951 100644 (file)
@@ -5186,6 +5186,7 @@ instantiate_class_template (type)
     {
       tree r = tsubst (t, args, /*complain=*/1, NULL_TREE);
       set_current_access_from_decl (r);
+      grok_special_member_properties (r);
       finish_member_declaration (r);
     }
 
@@ -5895,10 +5896,10 @@ tsubst_decl (t, args, type)
               If it isn't, that'll be handled by
               clone_constructors_and_destructors.  */
            if (PRIMARY_TEMPLATE_P (gen_tmpl))
-             clone_function_decl(r, /*update_method_vec_p=*/0);
+             clone_function_decl (r, /*update_method_vec_p=*/0);
          }
        else if (IDENTIFIER_OPNAME_P (DECL_NAME (r)))
-         grok_op_properties (r, DECL_VIRTUAL_P (r), DECL_FRIEND_P (r));
+         grok_op_properties (r, DECL_FRIEND_P (r));
       }
       break;
 
index 1320d3c..9c77430 100644 (file)
@@ -1,3 +1,7 @@
+2001-12-09  Nathan Sidwell  <nathan@codesourcery.com>
+
+       * g++.dg/other/copy1.C: New test.
+
 2001-10-08  Aldy Hernandez  <aldyh@redhat.com>
 
         * gcc.c-torture/execute/builtin-types-compatible-p.c: New.
diff --git a/gcc/testsuite/g++.dg/other/copy1.C b/gcc/testsuite/g++.dg/other/copy1.C
new file mode 100644 (file)
index 0000000..d02b08f
--- /dev/null
@@ -0,0 +1,83 @@
+// { dg-do run }
+
+// Copyright (C) 2000 Free Software Foundation, Inc.
+// Contributed by Nathan Sidwell 30 Nov 2001 <nathan@nathan@codesourcery.com>
+
+// PR 87
+
+int assign = 0;
+int ctor = 0;
+int assignC = 0;
+
+struct A {
+  int i;
+
+  template<class T>
+  void operator=(const T&) const
+  { 
+    assign = 1;
+  }
+
+  A () : i (0) {}
+  
+  template <typename T> A (const T &)
+  {
+    ctor = 1;
+  }
+};
+
+struct B : A 
+{
+};
+
+struct C 
+{
+  int i;
+
+  C (int i_) :i (i_) {}
+  
+  template <int I>
+  void operator= (const C &)
+  {
+    assignC = 1;
+  }
+};
+
+
+int main()
+{
+  const A a;
+  A b;
+  B c;
+
+  b = a;
+  if (assign)
+    return 5;
+  
+  b.i = 100;
+  c.i = 200;
+  
+  a = b; 
+
+  if (!assign)
+    return 1;
+  if (a.i)
+    return 2;
+
+  A e (b);
+  if (ctor)
+    return 3;
+  
+  A d (c);
+  if (!ctor)
+    return 4;
+
+  C c0 (0);
+  C c1 (1);
+
+  c0 = c1;
+  if (assignC)
+    return 5;
+  
+  return 0;
+}