diff options
author | Mark Mitchell <mark@codesourcery.com> | 2001-04-10 18:06:26 +0000 |
---|---|---|
committer | Mark Mitchell <mmitchel@gcc.gnu.org> | 2001-04-10 18:06:26 +0000 |
commit | 78b45a2404bade7c7a5178fa882129811ff08790 (patch) | |
tree | 5f0d77378e5aadab31152264b12a765ca92dd6e1 /gcc | |
parent | 0450d74d53b419f6455d9fc4f12ccf2a37ce61b8 (diff) | |
download | gcc-78b45a2404bade7c7a5178fa882129811ff08790.zip gcc-78b45a2404bade7c7a5178fa882129811ff08790.tar.gz gcc-78b45a2404bade7c7a5178fa882129811ff08790.tar.bz2 |
class.c (find_final_overrider_data): Add `candidates'.
* 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
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/ChangeLog | 10 | ||||
-rw-r--r-- | gcc/cp/class.c | 160 | ||||
-rw-r--r-- | gcc/testsuite/g++.old-deja/g++.other/override1.C | 20 |
3 files changed, 140 insertions, 50 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 1b0c470..7b5aee3 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -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 diff --git a/gcc/cp/class.c b/gcc/cp/class.c index f99fc3c..406843e 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -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 index 0000000..c7f3a4c --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.other/override1.C @@ -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 {}; |