class.c (find_final_overrider_data): Add `candidates'.
authorMark Mitchell <mark@codesourcery.com>
Tue, 10 Apr 2001 18:06:26 +0000 (18:06 +0000)
committerMark Mitchell <mmitchel@gcc.gnu.org>
Tue, 10 Apr 2001 18:06:26 +0000 (18:06 +0000)
* class.c (find_final_overrider_data): Add `candidates'.
(dfs_find_final_overrider): Don't issue error messages
prematurely.
(find_final_overrider): Issue error messages here.
(build_base_field): Don't warn about amgibuous direct bases here.
(warn_about_ambiguous_direct_bases): New function.
(layout_class_type): Use it.

From-SVN: r41224

gcc/cp/ChangeLog
gcc/cp/class.c
gcc/testsuite/g++.old-deja/g++.other/override1.C [new file with mode: 0644]

index 1b0c470aba7ef4a2c7c63574bf80eba8f68d0d50..7b5aee39e42097f93a6de10eb6466a25989be725 100644 (file)
@@ -1,3 +1,13 @@
+2001-04-10  Mark Mitchell  <mark@codesourcery.com>
+
+       * class.c (find_final_overrider_data): Add `candidates'.
+       (dfs_find_final_overrider): Don't issue error messages
+       prematurely.
+       (find_final_overrider): Issue error messages here.
+       (build_base_field): Don't warn about amgibuous direct bases here.
+       (warn_about_ambiguous_direct_bases): New function.
+       (layout_class_type): Use it.
+
 2001-04-10  Richard Henderson  <rth@redhat.com>
 
        * typeck.c (build_array_ref): Push the array reference inside
index f99fc3c1cdf2f7e1fa6e5f6ac475d04c8298ca72..406843e0c9ba15228223a60025210380e0c216fc 100644 (file)
@@ -212,7 +212,7 @@ static void record_subobject_offsets PARAMS ((tree, tree, splay_tree, int));
 static int layout_conflict_p PARAMS ((tree, tree, splay_tree, int));
 static int splay_tree_compare_integer_csts PARAMS ((splay_tree_key k1,
                                                    splay_tree_key k2));
-
+static void warn_about_ambiguous_direct_bases PARAMS ((tree));
 
 /* Macros for dfs walking during vtt construction. See
    dfs_ctor_vtable_bases_queue_p, dfs_build_secondary_vptr_vtt_inits
@@ -2495,6 +2495,9 @@ typedef struct find_final_overrider_data_s {
   tree most_derived_type;
   /* The final overriding function.  */
   tree overriding_fn;
+  /* The functions that we thought might be final overriders, but
+     aren't.  */
+  tree candidates;
   /* The BINFO for the class in which the final overriding function
      appears.  */
   tree overriding_base;
@@ -2553,49 +2556,79 @@ dfs_find_final_overrider (binfo, data)
                break;
              }
 
-         if (ffod->overriding_fn && ffod->overriding_fn != method)
+         /* If we didn't already have an overrider, or any
+            candidates, then this function is the best candidate so
+            far.  */
+         if (!ffod->overriding_fn && !ffod->candidates)
            {
-             /* We've found a different overrider along a different
-                path.  That can be OK if the new one overrides the
-                old one.  Consider:
-             
-                  struct S { virtual void f(); };
-                  struct T : public virtual S { virtual void f(); };
-                  struct U : public virtual S, public virtual T {};
-             
-                Here `T::f' is the final overrider for `S::f'.  */
-             if (strictly_overrides (method, ffod->overriding_fn))
-               {
-                 ffod->overriding_fn = method;
-                 ffod->overriding_base = TREE_VALUE (path);
-               }
-             else if (!strictly_overrides (ffod->overriding_fn, method))
-               {
-                 cp_error ("no unique final overrider for `%D' in `%T'", 
-                           ffod->most_derived_type,
-                           ffod->fn);
-                 cp_error ("candidates are: `%#D'", ffod->overriding_fn);
-                 cp_error ("                `%#D'", method);
-                 return error_mark_node;
-               }
+             ffod->overriding_fn = method;
+             ffod->overriding_base = TREE_VALUE (path);
            }
-         else if (ffod->overriding_base
-                  && (!tree_int_cst_equal 
-                      (BINFO_OFFSET (TREE_VALUE (path)),
-                       BINFO_OFFSET (ffod->overriding_base))))
+         /* If we found the same overrider we already have, then
+            we just need to check that we're finding it in the same
+            place.  */
+         else if (ffod->overriding_fn == method)
            {
-             /* We've found two instances of the same base that
-                provide overriders.  */
-             cp_error ("no unique final overrider for `%D' since there two instances of `%T' in `%T'", 
-                       ffod->fn,
-                       BINFO_TYPE (ffod->overriding_base),
-                       ffod->most_derived_type);
-             return error_mark_node;
+             if (ffod->overriding_base
+                 && (!tree_int_cst_equal 
+                     (BINFO_OFFSET (TREE_VALUE (path)),
+                      BINFO_OFFSET (ffod->overriding_base))))
+               {
+                 ffod->candidates 
+                   = build_tree_list (NULL_TREE,
+                                      ffod->overriding_fn);
+                 ffod->overriding_fn = NULL_TREE;
+                 ffod->overriding_base = NULL_TREE;
+               }
            }
+         /* If there was already an overrider, and it overrides this
+            function, then the old overrider is still the best
+            candidate.  */
+         else if (ffod->overriding_fn
+                  && strictly_overrides (ffod->overriding_fn,
+                                         method))
+           ;
          else
            {
-             ffod->overriding_fn = method;
-             ffod->overriding_base = TREE_VALUE (path);
+             tree candidates;
+             bool incomparable = false;
+
+             /* If there were previous candidates, and this function
+                overrides all of them, then it is the new best
+                candidate.  */
+             for (candidates = ffod->candidates;
+                  candidates;
+                  candidates = TREE_CHAIN (candidates))
+               {
+                 /* If the candidate overrides the METHOD, then we
+                    needn't worry about it any further.  */
+                 if (strictly_overrides (TREE_VALUE (candidates),
+                                         method))
+                   {
+                     method = NULL_TREE;
+                     break;
+                   }
+
+                 /* If the METHOD doesn't override the candidate,
+                    then it is incomporable.  */
+                 if (!strictly_overrides (method,
+                                          TREE_VALUE (candidates)))
+                   incomparable = true;
+               }
+
+             /* If METHOD overrode all the candidates, then it is the
+                new best candidate.  */
+             if (!candidates && !incomparable)
+               {
+                 ffod->overriding_fn = method;
+                 ffod->overriding_base = TREE_VALUE (path);
+                 ffod->candidates = NULL_TREE;
+               }
+             /* If METHOD didn't override all the candidates, then it
+                is another candidate.  */
+             else if (method && incomparable)
+               ffod->candidates 
+                 = tree_cons (NULL_TREE, method, ffod->candidates);
            }
        }
     }
@@ -2639,12 +2672,16 @@ find_final_overrider (t, binfo, fn)
   ffod.most_derived_type = t;
   ffod.overriding_fn = NULL_TREE;
   ffod.overriding_base = NULL_TREE;
+  ffod.candidates = NULL_TREE;
+
+  dfs_walk (TYPE_BINFO (t),
+           dfs_find_final_overrider,
+           NULL,
+           &ffod);
 
-  if (dfs_walk (TYPE_BINFO (t),
-               dfs_find_final_overrider,
-               NULL,
-               &ffod))
-    return error_mark_node;
+  /* If there was no winner, issue an error message.  */
+  if (!ffod.overriding_fn)
+    cp_error ("no unique final overrider for `%D' in `%T'", fn, t);
 
   return build_tree_list (ffod.overriding_fn, ffod.overriding_base);
 }
@@ -4041,13 +4078,6 @@ build_base_field (rli, binfo, empty_p, offsets)
       layout_empty_base (binfo, size_int (eoc), offsets);
     }
 
-  /* Check for inaccessible base classes.  If the same base class
-     appears more than once in the hierarchy, but isn't virtual, then
-     it's ambiguous.  */
-  if (get_base_distance (basetype, rli->t, 0, NULL) == -2)
-    cp_warning ("direct base `%T' inaccessible in `%T' due to ambiguity",
-               basetype, rli->t);
-  
   /* Record the offsets of BINFO and its base subobjects.  */
   record_subobject_offsets (BINFO_TYPE (binfo), 
                            BINFO_OFFSET (binfo),
@@ -4830,6 +4860,32 @@ end_of_class (t, include_virtuals_p)
   return result;
 }
 
+/* Warn about direct bases of T that are inaccessible because they are
+   ambiguous.  For example:
+
+     struct S {};
+     struct T : public S {};
+     struct U : public S, public T {};
+
+   Here, `(S*) new U' is not allowed because there are two `S'
+   subobjects of U.  */
+
+static void
+warn_about_ambiguous_direct_bases (t)
+     tree t;
+{
+  int i;
+
+  for (i = 0; i < CLASSTYPE_N_BASECLASSES (t); ++i)
+    {
+      tree basetype = TYPE_BINFO_BASETYPE (t, i);
+
+      if (get_base_distance (basetype, t, 0, NULL) == -2)
+       cp_warning ("direct base `%T' inaccessible in `%T' due to ambiguity",
+                   basetype, t);
+    }
+}
+
 /* Compare two INTEGER_CSTs K1 and K2.  */
 
 static int
@@ -5035,6 +5091,10 @@ layout_class_type (t, empty_p, vfuns_p,
      base subobject fields.  */
   layout_virtual_bases (t, empty_base_offsets);
 
+  /* Warn about direct bases that can't be talked about due to
+     ambiguity.  */
+  warn_about_ambiguous_direct_bases (t);
+
   /* Clean up.  */
   splay_tree_delete (empty_base_offsets);
 }
diff --git a/gcc/testsuite/g++.old-deja/g++.other/override1.C b/gcc/testsuite/g++.old-deja/g++.other/override1.C
new file mode 100644 (file)
index 0000000..c7f3a4c
--- /dev/null
@@ -0,0 +1,20 @@
+// Build don't link:
+// Origin: Frank Pilhofer <fp@fpx.de>
+
+struct A {
+virtual void f ();
+};
+
+struct B : virtual public A {
+void f ();
+};
+
+struct C : virtual public A {
+void f ();
+};
+
+struct D : virtual public B, virtual public C {
+void f ();
+};
+
+struct Di : virtual public B, virtual public C, virtual public D {};