cp-tree.h (add_method): Change prototype.
authorMark Mitchell <mark@codesourcery.com>
Fri, 4 Aug 2000 18:41:00 +0000 (18:41 +0000)
committerMark Mitchell <mmitchel@gcc.gnu.org>
Fri, 4 Aug 2000 18:41:00 +0000 (18:41 +0000)
* cp-tree.h (add_method): Change prototype.
* class.c (add_method): Remove FIELDS parameter.  Add ERROR_P.
Don't double the size of the method vector in the error case.
(handle_using_decl): Adjust call to add_method.
(add_implicitly_declared_members): Likewise.
(clone_function_decl): Likewise.
* decl2.c (check_classfn): Likewise.
* semantics.c (finish_member_declaration): Likewise.

From-SVN: r35490

gcc/cp/ChangeLog
gcc/cp/class.c
gcc/cp/cp-tree.h
gcc/cp/decl2.c
gcc/cp/semantics.c
gcc/testsuite/g++.old-deja/g++.other/crash21.C [new file with mode: 0644]

index 5f57de9821be4ca8e33b61a39da1addcf9192a06..f6c1683dc3342ee53e795d4b56c5f78a46a2c6f5 100644 (file)
@@ -1,3 +1,14 @@
+2000-08-04  Mark Mitchell  <mark@codesourcery.com>
+
+       * cp-tree.h (add_method): Change prototype.
+       * class.c (add_method): Remove FIELDS parameter.  Add ERROR_P.
+       Don't double the size of the method vector in the error case.
+       (handle_using_decl): Adjust call to add_method.
+       (add_implicitly_declared_members): Likewise.
+       (clone_function_decl): Likewise.
+       * decl2.c (check_classfn): Likewise.
+       * semantics.c (finish_member_declaration): Likewise.
+       
 2000-08-04  Joseph S. Myers  <jsm28@cam.ac.uk>
 
        * decl.c (flag_isoc94): New variable.
index cf62937a4816fa145bdadb2799474f7670e79057..aafecbe4fbbf0f104aadb9ff85e6e0fd35faf4f5 100644 (file)
@@ -1155,190 +1155,199 @@ add_virtual_function (new_virtuals_p, overridden_virtuals_p,
 \f
 extern struct obstack *current_obstack;
 
-/* Add method METHOD to class TYPE.
-
-   If non-NULL, FIELDS is the entry in the METHOD_VEC vector entry of
-   the class type where the method should be added.  */
+/* Add method METHOD to class TYPE.  If ERROR_P is true, we are adding
+   the method after the class has already been defined because a
+   declaration for it was seen.  (Even though that is erroneous, we
+   add the method for improved error recovery.)  */
 
 void
-add_method (type, fields, method)
-     tree type, *fields, method;
+add_method (type, method, error_p)
+     tree type;
+     tree method;
+     int error_p;
 {
   int using = (DECL_CONTEXT (method) != type);
-  
-  if (fields && *fields)
-    *fields = build_overload (method, *fields);
-  else 
+  int len;
+  int slot;
+  tree method_vec;
+
+  if (!CLASSTYPE_METHOD_VEC (type))
+    /* Make a new method vector.  We start with 8 entries.  We must
+       allocate at least two (for constructors and destructors), and
+       we're going to end up with an assignment operator at some point
+       as well.
+       
+       We could use a TREE_LIST for now, and convert it to a TREE_VEC
+       in finish_struct, but we would probably waste more memory
+       making the links in the list than we would by over-allocating
+       the size of the vector here.  Furthermore, we would complicate
+       all the code that expects this to be a vector.  */
+    CLASSTYPE_METHOD_VEC (type) = make_tree_vec (8);
+
+  method_vec = CLASSTYPE_METHOD_VEC (type);
+  len = TREE_VEC_LENGTH (method_vec);
+
+  /* Constructors and destructors go in special slots.  */
+  if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (method))
+    slot = CLASSTYPE_CONSTRUCTOR_SLOT;
+  else if (DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (method))
+    slot = CLASSTYPE_DESTRUCTOR_SLOT;
+  else
     {
-      int len;
-      int slot;
-      tree method_vec;
-
-      if (!CLASSTYPE_METHOD_VEC (type))
-       /* Make a new method vector.  We start with 8 entries.  We must
-          allocate at least two (for constructors and destructors), and
-          we're going to end up with an assignment operator at some
-          point as well.  
-
-          We could use a TREE_LIST for now, and convert it to a
-          TREE_VEC in finish_struct, but we would probably waste more
-          memory making the links in the list than we would by
-          over-allocating the size of the vector here.  Furthermore,
-          we would complicate all the code that expects this to be a
-          vector.  */
-       CLASSTYPE_METHOD_VEC (type) = make_tree_vec (8);
-
-      method_vec = CLASSTYPE_METHOD_VEC (type);
-      len = TREE_VEC_LENGTH (method_vec);
-
-      /* Constructors and destructors go in special slots.  */
-      if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (method))
-       slot = CLASSTYPE_CONSTRUCTOR_SLOT;
-      else if (DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (method))
-       slot = CLASSTYPE_DESTRUCTOR_SLOT;
-      else
-       {
-         /* See if we already have an entry with this name.  */
-         for (slot = CLASSTYPE_FIRST_CONVERSION_SLOT; slot < len; ++slot)
-           if (!TREE_VEC_ELT (method_vec, slot)
-               || (DECL_NAME (OVL_CURRENT (TREE_VEC_ELT (method_vec, 
-                                                         slot))) 
-                   == DECL_NAME (method)))
-             break;
+      /* See if we already have an entry with this name.  */
+      for (slot = CLASSTYPE_FIRST_CONVERSION_SLOT; slot < len; ++slot)
+       if (!TREE_VEC_ELT (method_vec, slot)
+           || (DECL_NAME (OVL_CURRENT (TREE_VEC_ELT (method_vec, 
+                                                     slot))) 
+               == DECL_NAME (method)))
+         break;
                
-         if (slot == len)
-           {
-             /* We need a bigger method vector.  */
-             tree new_vec = make_tree_vec (2 * len);
-             bcopy ((PTR) &TREE_VEC_ELT (method_vec, 0),
-                    (PTR) &TREE_VEC_ELT (new_vec, 0),
-                    len * sizeof (tree));
-             len = 2 * len;
-             method_vec = CLASSTYPE_METHOD_VEC (type) = new_vec;
-           }
+      if (slot == len)
+       {
+         /* We need a bigger method vector.  */
+         int new_len;
+         tree new_vec;
+
+         /* In the non-error case, we are processing a class
+            definition.  Double the size of the vector to give room
+            for new methods.  */
+         if (!error_p)
+           new_len = 2 * len;
+         /* In the error case, the vector is already complete.  We
+            don't expect many errors, and the rest of the front-end
+            will get confused if there are empty slots in the vector.  */
+         else
+           new_len = len + 1;
+
+         new_vec = make_tree_vec (new_len);
+         bcopy ((PTR) &TREE_VEC_ELT (method_vec, 0),
+                (PTR) &TREE_VEC_ELT (new_vec, 0),
+                len * sizeof (tree));
+         len = new_len;
+         method_vec = CLASSTYPE_METHOD_VEC (type) = new_vec;
+       }
 
-         if (DECL_CONV_FN_P (method) && !TREE_VEC_ELT (method_vec, slot))
+      if (DECL_CONV_FN_P (method) && !TREE_VEC_ELT (method_vec, slot))
+       {
+         /* Type conversion operators have to come before ordinary
+            methods; add_conversions depends on this to speed up
+            looking for conversion operators.  So, if necessary, we
+            slide some of the vector elements up.  In theory, this
+            makes this algorithm O(N^2) but we don't expect many
+            conversion operators.  */
+         for (slot = 2; slot < len; ++slot)
            {
-             /* Type conversion operators have to come before
-                ordinary methods; add_conversions depends on this to
-                speed up looking for conversion operators.  So, if
-                necessary, we slide some of the vector elements up.
-                In theory, this makes this algorithm O(N^2) but we
-                don't expect many conversion operators.  */
-             for (slot = 2; slot < len; ++slot)
-               {
-                 tree fn = TREE_VEC_ELT (method_vec, slot);
+             tree fn = TREE_VEC_ELT (method_vec, slot);
   
-                 if (!fn)
-                   /* There are no more entries in the vector, so we
-                      can insert the new conversion operator here.  */
-                   break;
+             if (!fn)
+               /* There are no more entries in the vector, so we
+                  can insert the new conversion operator here.  */
+               break;
                  
-                 if (!DECL_CONV_FN_P (OVL_CURRENT (fn)))
-                   /* We can insert the new function right at the
-                      SLOTth position.  */
-                   break;
-               }
+             if (!DECL_CONV_FN_P (OVL_CURRENT (fn)))
+               /* We can insert the new function right at the
+                  SLOTth position.  */
+               break;
+           }
   
-             if (!TREE_VEC_ELT (method_vec, slot))
-               /* There is nothing in the Ith slot, so we can avoid
-                  moving anything.  */
+         if (!TREE_VEC_ELT (method_vec, slot))
+           /* There is nothing in the Ith slot, so we can avoid
+              moving anything.  */
                ; 
-             else
-               {
-                 /* We know the last slot in the vector is empty
-                    because we know that at this point there's room
-                    for a new function.  */
-                 bcopy ((PTR) &TREE_VEC_ELT (method_vec, slot),
-                        (PTR) &TREE_VEC_ELT (method_vec, slot + 1),
-                        (len - slot - 1) * sizeof (tree));
-                 TREE_VEC_ELT (method_vec, slot) = NULL_TREE;
-               }
+         else
+           {
+             /* We know the last slot in the vector is empty
+                because we know that at this point there's room
+                for a new function.  */
+             bcopy ((PTR) &TREE_VEC_ELT (method_vec, slot),
+                    (PTR) &TREE_VEC_ELT (method_vec, slot + 1),
+                    (len - slot - 1) * sizeof (tree));
+             TREE_VEC_ELT (method_vec, slot) = NULL_TREE;
            }
        }
+    }
       
-      if (template_class_depth (type))
-       /* TYPE is a template class.  Don't issue any errors now; wait
-          until instantiation time to complain.  */
-         ;
-      else
-       {
-         tree fns;
+  if (template_class_depth (type))
+    /* TYPE is a template class.  Don't issue any errors now; wait
+       until instantiation time to complain.  */
+    ;
+  else
+    {
+      tree fns;
 
-         /* Check to see if we've already got this method.  */
-         for (fns = TREE_VEC_ELT (method_vec, slot);
-              fns;
-              fns = OVL_NEXT (fns))
-           {
-             tree fn = OVL_CURRENT (fns);
+      /* Check to see if we've already got this method.  */
+      for (fns = TREE_VEC_ELT (method_vec, slot);
+          fns;
+          fns = OVL_NEXT (fns))
+       {
+         tree fn = OVL_CURRENT (fns);
                 
-             if (TREE_CODE (fn) != TREE_CODE (method))
-               continue;
+         if (TREE_CODE (fn) != TREE_CODE (method))
+           continue;
 
-             if (TREE_CODE (method) != TEMPLATE_DECL)
+         if (TREE_CODE (method) != TEMPLATE_DECL)
+           {
+             /* [over.load] Member function declarations with the
+                same name and the same parameter types cannot be
+                overloaded if any of them is a static member
+                function declaration.  */
+             if ((DECL_STATIC_FUNCTION_P (fn)
+                  != DECL_STATIC_FUNCTION_P (method))
+                 || using)
                {
-                 /* [over.load] Member function declarations with the
-                    same name and the same parameter types cannot be
-                    overloaded if any of them is a static member
-                    function declaration.  */
-                 if ((DECL_STATIC_FUNCTION_P (fn)
-                      != DECL_STATIC_FUNCTION_P (method))
-                     || using)
+                 tree parms1 = TYPE_ARG_TYPES (TREE_TYPE (fn));
+                 tree parms2 = TYPE_ARG_TYPES (TREE_TYPE (method));
+
+                 if (! DECL_STATIC_FUNCTION_P (fn))
+                   parms1 = TREE_CHAIN (parms1);
+                 if (! DECL_STATIC_FUNCTION_P (method))
+                   parms2 = TREE_CHAIN (parms2);
+
+                 if (compparms (parms1, parms2))
                    {
-                     tree parms1 = TYPE_ARG_TYPES (TREE_TYPE (fn));
-                     tree parms2 = TYPE_ARG_TYPES (TREE_TYPE (method));
-
-                     if (! DECL_STATIC_FUNCTION_P (fn))
-                       parms1 = TREE_CHAIN (parms1);
-                     if (! DECL_STATIC_FUNCTION_P (method))
-                       parms2 = TREE_CHAIN (parms2);
-
-                     if (compparms (parms1, parms2))
-                       {
-                         if (using)
-                           /* Defer to the local function.  */
-                           return;
-                         else
-                           cp_error ("`%#D' and `%#D' cannot be overloaded",
-                                     fn, method);
-                       }
+                     if (using)
+                       /* Defer to the local function.  */
+                       return;
+                     else
+                       cp_error ("`%#D' and `%#D' cannot be overloaded",
+                                 fn, method);
                    }
-
-                 /* Since this is an ordinary function in a
-                    non-template class, it's mangled name can be used
-                    as a unique identifier.  This technique is only
-                    an optimization; we would get the same results if
-                    we just used decls_match here.  */
-                 if (DECL_ASSEMBLER_NAME (fn) 
-                     != DECL_ASSEMBLER_NAME (method))
-                   continue;
                }
-             else if (!decls_match (fn, method))
+
+             /* Since this is an ordinary function in a
+                non-template class, it's mangled name can be used
+                as a unique identifier.  This technique is only
+                an optimization; we would get the same results if
+                we just used decls_match here.  */
+             if (DECL_ASSEMBLER_NAME (fn) 
+                 != DECL_ASSEMBLER_NAME (method))
                continue;
+           }
+         else if (!decls_match (fn, method))
+           continue;
 
-             /* There has already been a declaration of this method
-                or member template.  */
-             cp_error_at ("`%D' has already been declared in `%T'", 
-                          method, type);
+         /* There has already been a declaration of this method
+            or member template.  */
+         cp_error_at ("`%D' has already been declared in `%T'", 
+                      method, type);
 
-             /* We don't call duplicate_decls here to merge the
-                declarations because that will confuse things if the
-                methods have inline definitions.  In particular, we
-                will crash while processing the definitions.  */
-             return;
-           }
+         /* We don't call duplicate_decls here to merge the
+            declarations because that will confuse things if the
+            methods have inline definitions.  In particular, we
+            will crash while processing the definitions.  */
+         return;
        }
+    }
 
-      /* Actually insert the new method.  */
-      TREE_VEC_ELT (method_vec, slot) 
-       = build_overload (method, TREE_VEC_ELT (method_vec, slot));
+  /* Actually insert the new method.  */
+  TREE_VEC_ELT (method_vec, slot) 
+    = build_overload (method, TREE_VEC_ELT (method_vec, slot));
 
       /* Add the new binding.  */ 
-      if (!DECL_CONSTRUCTOR_P (method)
-         && !DECL_DESTRUCTOR_P (method))
-       push_class_level_binding (DECL_NAME (method),
-                                 TREE_VEC_ELT (method_vec, slot));
-    }
+  if (!DECL_CONSTRUCTOR_P (method)
+      && !DECL_DESTRUCTOR_P (method))
+    push_class_level_binding (DECL_NAME (method),
+                             TREE_VEC_ELT (method_vec, slot));
 }
 
 /* Subroutines of finish_struct.  */
@@ -1567,7 +1576,7 @@ handle_using_decl (using_decl, t)
   if (flist)
     for (; flist; flist = OVL_NEXT (flist))
       {
-       add_method (t, 0, OVL_CURRENT (flist));
+       add_method (t, OVL_CURRENT (flist), /*error_p=*/0);
        alter_access (t, OVL_CURRENT (flist), access);
       }
   else
@@ -3146,7 +3155,7 @@ add_implicitly_declared_members (t, cant_have_default_ctor,
   /* Now, hook all of the new functions on to TYPE_METHODS,
      and add them to the CLASSTYPE_METHOD_VEC.  */
   for (f = &implicit_fns; *f; f = &TREE_CHAIN (*f))
-    add_method (t, 0, *f);
+    add_method (t, *f, /*error_p=*/0);
   *f = TYPE_METHODS (t);
   TYPE_METHODS (t) = implicit_fns;
 
@@ -4203,10 +4212,10 @@ clone_function_decl (fn, update_method_vec_p)
         and a not-in-charge version.  */
       clone = build_clone (fn, complete_ctor_identifier);
       if (update_method_vec_p)
-       add_method (DECL_CONTEXT (clone), NULL, clone);
+       add_method (DECL_CONTEXT (clone), clone, /*error_p=*/0);
       clone = build_clone (fn, base_ctor_identifier);
       if (update_method_vec_p)
-       add_method (DECL_CONTEXT (clone), NULL, clone);
+       add_method (DECL_CONTEXT (clone), clone, /*error_p=*/0);
     }
   else
     {
@@ -4220,13 +4229,13 @@ clone_function_decl (fn, update_method_vec_p)
         function table.  */
       clone = build_clone (fn, deleting_dtor_identifier);
       if (update_method_vec_p)
-       add_method (DECL_CONTEXT (clone), NULL, clone);
+       add_method (DECL_CONTEXT (clone), clone, /*error_p=*/0);
       clone = build_clone (fn, complete_dtor_identifier);
       if (update_method_vec_p)
-       add_method (DECL_CONTEXT (clone), NULL, clone);
+       add_method (DECL_CONTEXT (clone), clone, /*error_p=*/0);
       clone = build_clone (fn, base_dtor_identifier);
       if (update_method_vec_p)
-       add_method (DECL_CONTEXT (clone), NULL, clone);
+       add_method (DECL_CONTEXT (clone), clone, /*error_p=*/0);
     }
 }
 
index a945ab4436c024adf152dc288c1888ecf2a7aec0..2c534f38d301ed043d222422193973af8a9c7b3f 100644 (file)
@@ -3805,7 +3805,7 @@ extern tree build_vbase_path                      PARAMS ((enum tree_code, tree, tree, tree, int));
 extern tree build_vtbl_ref                     PARAMS ((tree, tree));
 extern tree build_vfn_ref                      PARAMS ((tree *, tree, tree));
 extern tree get_vtable_decl                     PARAMS ((tree, int));
-extern void add_method                         PARAMS ((tree, tree *, tree));
+extern void add_method                         PARAMS ((tree, tree, int));
 extern int currently_open_class                        PARAMS ((tree));
 extern tree currently_open_derived_class       PARAMS ((tree));
 extern tree get_vfield_offset                  PARAMS ((tree));
index 690a78de6cf11ddca778c0bd56442c53db45ca4d..514b9c6ef0739cf3a4bd72415471a9f06aaf5297 100644 (file)
@@ -1549,7 +1549,7 @@ check_classfn (ctype, function)
      case we'll only confuse ourselves when the function is declared
      properly within the class.  */
   if (COMPLETE_TYPE_P (ctype))
-    add_method (ctype, methods, function);
+    add_method (ctype, function, /*error_p=*/1);
   return NULL_TREE;
 }
 
index 066f6756b679e1b3f2665e0781d40ca21c2f7085..9dc6bca5a81aba9dd1c801e30a8e1a9d631cf930 100644 (file)
@@ -1969,7 +1969,7 @@ finish_member_declaration (decl)
     {
       /* We also need to add this function to the
         CLASSTYPE_METHOD_VEC.  */
-      add_method (current_class_type, 0, decl);
+      add_method (current_class_type, decl, /*error_p=*/0);
 
       TREE_CHAIN (decl) = TYPE_METHODS (current_class_type);
       TYPE_METHODS (current_class_type) = decl;
diff --git a/gcc/testsuite/g++.old-deja/g++.other/crash21.C b/gcc/testsuite/g++.old-deja/g++.other/crash21.C
new file mode 100644 (file)
index 0000000..e9e642f
--- /dev/null
@@ -0,0 +1,15 @@
+// Build don't link:
+// Origin: Gabriel Dos Reis <gdr@codesourcery.com>
+
+struct  A {
+  virtual void f(int&) const;
+};
+
+struct B : public A {
+  int x;
+};
+
+void B::f(int& t)
+{
+  x = t;
+}