diff options
author | Mark Mitchell <mmitchell@usa.net> | 1998-05-19 14:51:38 +0000 |
---|---|---|
committer | Mark Mitchell <mmitchel@gcc.gnu.org> | 1998-05-19 14:51:38 +0000 |
commit | ceab47eb37ec0cc015b9a909940cc69fda69c043 (patch) | |
tree | fe4cecea6b558a7d39d252c8a45348d30e31a189 | |
parent | 06033860a75f5fbe45d6df0269b050a2e7dfa086 (diff) | |
download | gcc-ceab47eb37ec0cc015b9a909940cc69fda69c043.zip gcc-ceab47eb37ec0cc015b9a909940cc69fda69c043.tar.gz gcc-ceab47eb37ec0cc015b9a909940cc69fda69c043.tar.bz2 |
call.c (compare_qual): Remove.
* call.c (compare_qual): Remove.
(is_subseq): Tweak.
(is_properly_derived_from): New function.
(maybe_handle_ref_bind): Likewise.
(maybe_handle_implicit_object): Likewise.
(compare_ics): Modify substantially to bring into conformance with
the standard.
* cp-tree.h (TYPE_PTRMEMFUNC_OBJECT_TYPE): New macro.
(comp_cv_qualification): Declare.
(comp_cv_qual_signature): Likewise.
* typeck.c (comp_cv_qualification): Likewise.
(comp_cv_qual_signature): Likewise.
From-SVN: r19880
-rw-r--r-- | gcc/cp/ChangeLog | 15 | ||||
-rw-r--r-- | gcc/cp/call.c | 596 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 7 | ||||
-rw-r--r-- | gcc/cp/typeck.c | 82 | ||||
-rw-r--r-- | gcc/testsuite/g++.old-deja/g++.other/overload3.C | 16 | ||||
-rw-r--r-- | gcc/testsuite/g++.old-deja/g++.other/overload4.C | 10 | ||||
-rw-r--r-- | gcc/testsuite/g++.old-deja/g++.other/overload5.C | 22 |
7 files changed, 517 insertions, 231 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index e02f940..4050467 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,18 @@ +Tue May 19 14:50:27 1998 Mark Mitchell <mmitchell@usa.net> + + * call.c (compare_qual): Remove. + (is_subseq): Tweak. + (is_properly_derived_from): New function. + (maybe_handle_ref_bind): Likewise. + (maybe_handle_implicit_object): Likewise. + (compare_ics): Modify substantially to bring into conformance with + the standard. + * cp-tree.h (TYPE_PTRMEMFUNC_OBJECT_TYPE): New macro. + (comp_cv_qualification): Declare. + (comp_cv_qual_signature): Likewise. + * typeck.c (comp_cv_qualification): Likewise. + (comp_cv_qual_signature): Likewise. + Tue May 19 10:05:02 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu> * Makefile.in (parse.o): Depend on toplev.h. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 82397a6..67795ab 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -45,7 +45,6 @@ static tree build_field_call PROTO((tree, tree, tree, tree)); static tree find_scoped_type PROTO((tree, tree, tree)); static struct z_candidate * tourney PROTO((struct z_candidate *)); static int joust PROTO((struct z_candidate *, struct z_candidate *, int)); -static int compare_qual PROTO((tree, tree)); static int compare_ics PROTO((tree, tree)); static tree build_over_call PROTO((struct z_candidate *, tree, int)); static tree convert_default_arg PROTO((tree, tree)); @@ -89,6 +88,9 @@ static tree strip_top_quals PROTO((tree)); static tree non_reference PROTO((tree)); static tree build_conv PROTO((enum tree_code, tree, tree)); static int is_subseq PROTO((tree, tree)); +static int is_properly_derived_from PROTO((tree, tree)); +static int maybe_handle_ref_bind PROTO((tree*, tree*)); +static void maybe_handle_implicit_object PROTO((tree*)); tree build_vfield_ref (datum, type) @@ -3658,119 +3660,191 @@ build_new_method_call (instance, name, args, basetype_path, flags) flags); } -/* Compare two implicit conversion sequences that differ only in their - qualification conversion. Subroutine of compare_ics. */ +/* Returns non-zero iff standard conversion sequence ICS1 is a proper + subsequence of ICS2. */ static int -compare_qual (ics1, ics2) +is_subseq (ics1, ics2) tree ics1, ics2; { - tree to1 = TREE_TYPE (ics1); - tree to2 = TREE_TYPE (ics2); - - if (TYPE_PTRMEMFUNC_P (to1)) - to1 = TYPE_PTRMEMFUNC_FN_TYPE (to1); - if (TYPE_PTRMEMFUNC_P (to2)) - to2 = TYPE_PTRMEMFUNC_FN_TYPE (to2); + /* We can assume that a conversion of the same code + between the same types indicates a subsequence since we only get + here if the types we are converting from are the same. */ - to1 = TREE_TYPE (to1); - to2 = TREE_TYPE (to2); + while (TREE_CODE (ics1) == RVALUE_CONV + || TREE_CODE (ics1) == LVALUE_CONV) + ics1 = TREE_OPERAND (ics1, 0); - if (TREE_CODE (to1) == OFFSET_TYPE) + while (1) { - to1 = TREE_TYPE (to1); - to2 = TREE_TYPE (to2); - } - - if (TYPE_READONLY (to1) >= TYPE_READONLY (to2) - && TYPE_VOLATILE (to1) > TYPE_VOLATILE (to2)) - return -1; - else if (TYPE_READONLY (to1) > TYPE_READONLY (to2) - && TYPE_VOLATILE (to1) == TYPE_VOLATILE (to2)) - return -1; - else if (TYPE_READONLY (to1) <= TYPE_READONLY (to2) - && TYPE_VOLATILE (to1) < TYPE_VOLATILE (to2)) - return 1; - else if (TYPE_READONLY (to1) < TYPE_READONLY (to2) - && TYPE_VOLATILE (to1) == TYPE_VOLATILE (to2)) - return 1; - return 0; -} + while (TREE_CODE (ics2) == RVALUE_CONV + || TREE_CODE (ics2) == LVALUE_CONV) + ics2 = TREE_OPERAND (ics2, 0); -/* Determine whether standard conversion sequence ICS1 is a proper - subsequence of ICS2. We assume that a conversion of the same code - between the same types indicates a subsequence. */ + if (TREE_CODE (ics2) == USER_CONV + || TREE_CODE (ics2) == AMBIG_CONV + || TREE_CODE (ics2) == IDENTITY_CONV) + /* At this point, ICS1 cannot be a proper subsequence of + ICS2. We can get a USER_CONV when we are comparing the + second standard conversion sequence of two user conversion + sequences. */ + return 0; -static int -is_subseq (ics1, ics2) - tree ics1, ics2; -{ - /* Do not consider lvalue transformations here. */ - if (TREE_CODE (ics2) == RVALUE_CONV - || TREE_CODE (ics2) == LVALUE_CONV) - return 0; + ics2 = TREE_OPERAND (ics2, 0); - for (;; ics2 = TREE_OPERAND (ics2, 0)) - { if (TREE_CODE (ics2) == TREE_CODE (ics1) && comptypes (TREE_TYPE (ics2), TREE_TYPE (ics1), 1) && comptypes (TREE_TYPE (TREE_OPERAND (ics2, 0)), TREE_TYPE (TREE_OPERAND (ics1, 0)), 1)) return 1; - - if (TREE_CODE (ics2) == USER_CONV - || TREE_CODE (ics2) == AMBIG_CONV - || TREE_CODE (ics2) == IDENTITY_CONV) - return 0; } } -/* Compare two implicit conversion sequences according to the rules set out in - [over.ics.rank]. Return values: - - 1: ics1 is better than ics2 - -1: ics2 is better than ics1 - 0: ics1 and ics2 are indistinguishable */ +/* Returns non-zero iff DERIVED is derived from BASE. The inputs may + be any _TYPE nodes. */ static int -compare_ics (ics1, ics2) - tree ics1, ics2; +is_properly_derived_from (derived, base) + tree derived; + tree base; { - tree main1, main2; + if (!IS_AGGR_TYPE_CODE (TREE_CODE (derived)) + || !IS_AGGR_TYPE_CODE (TREE_CODE (base))) + return 0; - if (TREE_CODE (ics1) == QUAL_CONV) - main1 = TREE_OPERAND (ics1, 0); - else - main1 = ics1; + /* We only allow proper derivation here. The DERIVED_FROM_P macro + considers every class derived from itself. */ + return (!comptypes (TYPE_MAIN_VARIANT (derived), + TYPE_MAIN_VARIANT (base), 1) + && DERIVED_FROM_P (base, derived)); +} - if (TREE_CODE (ics2) == QUAL_CONV) - main2 = TREE_OPERAND (ics2, 0); - else - main2 = ics2; +/* We build the ICS for an implicit object parameter as a pointer + conversion sequence. However, such a sequence should be compared + as if it were a reference conversion sequence. If ICS is the + implicit conversion sequence for an implicit object parameter, + modify it accordingly. */ - /* Conversions for `this' are PTR_CONVs, but we compare them as though - they were REF_BINDs. */ - if (ICS_THIS_FLAG (ics1)) +static void +maybe_handle_implicit_object (ics) + tree* ics; +{ + if (ICS_THIS_FLAG (*ics)) { - tree t = main1; + /* [over.match.funcs] + + For non-static member functions, the type of the + implicit object parameter is "reference to cv X" + where X is the class of which the function is a + member and cv is the cv-qualification on the member + function declaration. */ + tree t = *ics; if (TREE_CODE (t) == PTR_CONV) t = TREE_OPERAND (t, 0); t = build1 (IDENTITY_CONV, TREE_TYPE (TREE_TYPE (t)), NULL_TREE); - t = build_conv (REF_BIND, TREE_TYPE (ics1), t); - ICS_STD_RANK (t) = ICS_STD_RANK (main1); - main1 = ics1 = t; + t = build_conv (REF_BIND, TREE_TYPE (*ics), t); + ICS_STD_RANK (t) = ICS_STD_RANK (*ics); + *ics = t; } - if (ICS_THIS_FLAG (ics2)) +} + +/* If ICS is a REF_BIND, modify it appropriately, set ORIG_TO_TYPE + to the type the reference originally referred to, and return 1. + Otherwise, return 0. */ + +static int +maybe_handle_ref_bind (ics, reference_type) + tree* ics; + tree* reference_type; +{ + if (TREE_CODE (*ics) == REF_BIND) { - tree t = main2; - if (TREE_CODE (t) == PTR_CONV) - t = TREE_OPERAND (t, 0); - t = build1 (IDENTITY_CONV, TREE_TYPE (TREE_TYPE (t)), NULL_TREE); - t = build_conv (REF_BIND, TREE_TYPE (ics2), t); - ICS_STD_RANK (t) = ICS_STD_RANK (main2); - main2 = ics2 = t; + /* [over.ics.rank] + + When a parameter of reference type binds directly + (_dcl.init.ref_) to an argument expression, the implicit + conversion sequence is the identity conversion, unless the + argument expression has a type that is a derived class of the + parameter type, in which case the implicit conversion + sequence is a derived-to-base Conversion. + + If the parameter binds directly to the result of applying a + conversion function to the argument expression, the implicit + conversion sequence is a user-defined conversion sequence + (_over.ics.user_), with the second standard conversion + sequence either an identity conversion or, if the conversion + function returns an entity of a type that is a derived class + of the parameter type, a derived-to-base Conversion. + + When a parameter of reference type is not bound directly to + an argument expression, the conversion sequence is the one + required to convert the argument expression to the underlying + type of the reference according to _over.best.ics_. + Conceptually, this conversion sequence corresponds to + copy-initializing a temporary of the underlying type with the + argument expression. Any difference in top-level + cv-qualification is subsumed by the initialization itself and + does not constitute a conversion. */ + + *reference_type = TREE_TYPE (TREE_TYPE (*ics)); + *ics = TREE_OPERAND (*ics, 0); + if (TREE_CODE (*ics) == IDENTITY_CONV + && is_properly_derived_from (TREE_TYPE (*ics), *reference_type)) + *ics = build_conv (BASE_CONV, *reference_type, *ics); + return 1; } + + return 0; +} +/* Compare two implicit conversion sequences according to the rules set out in + [over.ics.rank]. Return values: + + 1: ics1 is better than ics2 + -1: ics2 is better than ics1 + 0: ics1 and ics2 are indistinguishable */ + +static int +compare_ics (ics1, ics2) + tree ics1, ics2; +{ + tree from_type1; + tree from_type2; + tree to_type1; + tree to_type2; + tree deref_from_type1 = NULL_TREE; + tree deref_from_type2; + tree deref_to_type1; + tree deref_to_type2; + + /* REF_BINDING is non-zero if the result of the conversion sequence + is a reference type. In that case REFERENCE_TYPE is the + reference type. */ + int ref_binding1; + int ref_binding2; + tree reference_type1; + tree reference_type2; + + /* Handle implicit object parameters. */ + maybe_handle_implicit_object (&ics1); + maybe_handle_implicit_object (&ics2); + + /* Handle reference parameters. */ + ref_binding1 = maybe_handle_ref_bind (&ics1, &reference_type1); + ref_binding2 = maybe_handle_ref_bind (&ics2, &reference_type2); + + /* [over.ics.rank] + + When comparing the basic forms of implicit conversion sequences (as + defined in _over.best.ics_) + + --a standard conversion sequence (_over.ics.scs_) is a better + conversion sequence than a user-defined conversion sequence + or an ellipsis conversion sequence, and + + --a user-defined conversion sequence (_over.ics.user_) is a + better conversion sequence than an ellipsis conversion sequence + (_over.ics.ellipsis_). */ if (ICS_RANK (ics1) > ICS_RANK (ics2)) return -1; else if (ICS_RANK (ics1) < ICS_RANK (ics2)) @@ -3778,6 +3852,8 @@ compare_ics (ics1, ics2) if (ICS_RANK (ics1) == BAD_RANK) { + /* Both ICS are bad. We try to make a decision based on what + would have happenned if they'd been good. */ if (ICS_USER_FLAG (ics1) > ICS_USER_FLAG (ics2) || ICS_STD_RANK (ics1) > ICS_STD_RANK (ics2)) return -1; @@ -3785,9 +3861,13 @@ compare_ics (ics1, ics2) || ICS_STD_RANK (ics1) < ICS_STD_RANK (ics2)) return 1; - /* else fall through */ + /* We couldn't make up our minds; try to figure it out below. */ } + if (ICS_ELLIPSIS_FLAG (ics1)) + /* Both conversions are ellipsis conversions. */ + return 0; + /* User-defined conversion sequence U1 is a better conversion sequence than another user-defined conversion sequence U2 if they contain the same user-defined conversion operator or constructor and if the sec- @@ -3807,175 +3887,251 @@ compare_ics (ics1, ics2) if (USER_CONV_FN (t1) != USER_CONV_FN (t2)) return 0; - else if (ICS_STD_RANK (ics1) > ICS_STD_RANK (ics2)) - return -1; - else if (ICS_STD_RANK (ics1) < ICS_STD_RANK (ics2)) - return 1; - /* else fall through */ + /* We can just fall through here, after setting up + FROM_TYPE1 and FROM_TYPE2. */ + from_type1 = TREE_TYPE (t1); + from_type2 = TREE_TYPE (t2); } + else + { + /* We're dealing with two standard conversion sequences. -#if 0 /* Handled by ranking */ - /* A conversion that is not a conversion of a pointer, or pointer to - member, to bool is better than another conversion that is such a - conversion. */ -#endif + [over.ics.rank] + + Standard conversion sequence S1 is a better conversion + sequence than standard conversion sequence S2 if + + --S1 is a proper subsequence of S2 (comparing the conversion + sequences in the canonical form defined by _over.ics.scs_, + excluding any Lvalue Transformation; the identity + conversion sequence is considered to be a subsequence of + any non-identity conversion sequence */ + + from_type1 = ics1; + while (TREE_CODE (from_type1) != IDENTITY_CONV) + from_type1 = TREE_OPERAND (from_type1, 0); + from_type1 = TREE_TYPE (from_type1); + + from_type2 = ics2; + while (TREE_CODE (from_type2) != IDENTITY_CONV) + from_type2 = TREE_OPERAND (from_type2, 0); + from_type2 = TREE_TYPE (from_type2); + } - if (TREE_CODE (main1) != TREE_CODE (main2)) + if (comptypes (from_type1, from_type2, 1)) { - /* ...if S1 is a proper subsequence of S2 */ - if (is_subseq (main1, main2)) + if (is_subseq (ics1, ics2)) return 1; - if (is_subseq (main2, main1)) + if (is_subseq (ics2, ics1)) return -1; - return 0; } + else + /* One sequence cannot be a subsequence of the other; they don't + start with the same type. This can happen when comparing the + second standard conversion sequence in two user-defined + conversion sequences. */ + ; - if (TREE_CODE (main1) == PTR_CONV || TREE_CODE (main1) == PMEM_CONV - || TREE_CODE (main1) == REF_BIND || TREE_CODE (main1) == BASE_CONV) - { - tree to1 = TREE_TYPE (main1); - tree from1 = TREE_TYPE (TREE_OPERAND (main1, 0)); - tree to2 = TREE_TYPE (main2); - tree from2 = TREE_TYPE (TREE_OPERAND (main2, 0)); - int distf, distt; - - /* Standard conversion sequence S1 is a better conversion sequence than - standard conversion sequence S2 if... - - S1 and S2 differ only in their qualification conversion and they - yield types identical except for cv-qualifiers and S2 adds all the - qualifiers that S1 adds (and in the same places) and S2 adds yet - more cv-qualifiers than S1, or the similar case with reference - binding15). */ - if (TREE_CODE (main1) == REF_BIND) - { - if (TYPE_MAIN_VARIANT (TREE_TYPE (to1)) - == TYPE_MAIN_VARIANT (TREE_TYPE (to2))) - return compare_qual (ics1, ics2); - } - else if (TREE_CODE (main1) != BASE_CONV && from1 == from2 && to1 == to2) - return compare_qual (ics1, ics2); - - if (TYPE_PTRMEMFUNC_P (to1)) - { - to1 = TYPE_METHOD_BASETYPE (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (to1))); - from1 = TYPE_METHOD_BASETYPE (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (from1))); - } - else if (TREE_CODE (main1) != BASE_CONV) - { - to1 = TREE_TYPE (to1); - if (TREE_CODE (main1) != REF_BIND) - from1 = TREE_TYPE (from1); + /* [over.ics.rank] - if (TREE_CODE (to1) == OFFSET_TYPE) - { - to1 = TYPE_OFFSET_BASETYPE (to1); - from1 = TYPE_OFFSET_BASETYPE (from1); - } - } + Or, if not that, - if (TYPE_PTRMEMFUNC_P (to2)) - { - to2 = TYPE_METHOD_BASETYPE (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (to2))); - from2 = TYPE_METHOD_BASETYPE (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (from2))); - } - else if (TREE_CODE (main1) != BASE_CONV) - { - to2 = TREE_TYPE (to2); - if (TREE_CODE (main1) != REF_BIND) - from2 = TREE_TYPE (from2); + --the rank of S1 is better than the rank of S2 (by the rules + defined below): - if (TREE_CODE (to2) == OFFSET_TYPE) - { - to2 = TYPE_OFFSET_BASETYPE (to2); - from2 = TYPE_OFFSET_BASETYPE (from2); - } - } + Standard conversion sequences are ordered by their ranks: an Exact + Match is a better conversion than a Promotion, which is a better + conversion than a Conversion. - if (! (IS_AGGR_TYPE (from1) && IS_AGGR_TYPE (from2))) - return 0; + Two conversion sequences with the same rank are indistinguishable + unless one of the following rules applies: - /* The sense of pmem conversions is reversed from that of the other - conversions. */ - if (TREE_CODE (main1) == PMEM_CONV) - { - tree t = from1; from1 = from2; from2 = t; - t = to1; to1 = to2; to2 = t; - } + --A conversion that is not a conversion of a pointer, or pointer + to member, to bool is better than another conversion that is such + a conversion. - distf = get_base_distance (from1, from2, 0, 0); - if (distf == -1) - { - distf = -get_base_distance (from2, from1, 0, 0); - if (distf == 1) - return 0; - } + The ICS_STD_RANK automatically handles the pointer-to-bool rule, + so that we do not have to check it explicitly. */ + if (ICS_STD_RANK (ics1) < ICS_STD_RANK (ics2)) + return 1; + else if (ICS_STD_RANK (ics2) < ICS_STD_RANK (ics1)) + return -1; + + to_type1 = TREE_TYPE (ics1); + to_type2 = TREE_TYPE (ics2); - /* If class B is derived directly or indirectly from class A, - conver- sion of B* to A* is better than conversion of B* to - void*, and conversion of A* to void* is better than - conversion of B* to void*. */ + if (TYPE_PTR_P (from_type1) + && TYPE_PTR_P (from_type2) + && TYPE_PTR_P (to_type1) + && TYPE_PTR_P (to_type2)) + { + deref_from_type1 = TREE_TYPE (from_type1); + deref_from_type2 = TREE_TYPE (from_type2); + deref_to_type1 = TREE_TYPE (to_type1); + deref_to_type2 = TREE_TYPE (to_type2); + } + /* The rules for pointers to members A::* are just like the rules + for pointers A*, except opposite: if B is derived from A then + A::* converts to B::*, not vice versa. For that reason, we + switch the from_ and to_ variables here. */ + else if (TYPE_PTRMEM_P (from_type1) + && TYPE_PTRMEM_P (from_type2) + && TYPE_PTRMEM_P (to_type1) + && TYPE_PTRMEM_P (to_type2)) + { + deref_to_type1 = TYPE_OFFSET_BASETYPE (TREE_TYPE (from_type1)); + deref_to_type2 = TYPE_OFFSET_BASETYPE (TREE_TYPE (from_type2)); + deref_from_type1 = TYPE_OFFSET_BASETYPE (TREE_TYPE (to_type1)); + deref_from_type2 = TYPE_OFFSET_BASETYPE (TREE_TYPE (to_type2)); + } + else if (TYPE_PTRMEMFUNC_P (from_type1) + && TYPE_PTRMEMFUNC_P (from_type2) + && TYPE_PTRMEMFUNC_P (to_type1) + && TYPE_PTRMEMFUNC_P (to_type2)) + { + deref_to_type1 = TYPE_PTRMEMFUNC_OBJECT_TYPE (from_type1); + deref_to_type2 = TYPE_PTRMEMFUNC_OBJECT_TYPE (from_type2); + deref_from_type1 = TYPE_PTRMEMFUNC_OBJECT_TYPE (to_type1); + deref_from_type2 = TYPE_PTRMEMFUNC_OBJECT_TYPE (to_type2); + } - if (TREE_CODE (to1) == VOID_TYPE && TREE_CODE (to2) == VOID_TYPE) + if (deref_from_type1 != NULL_TREE + && IS_AGGR_TYPE_CODE (TREE_CODE (deref_from_type1)) + && IS_AGGR_TYPE_CODE (TREE_CODE (deref_from_type2))) + { + /* This was one of the pointer or pointer-like conversions. + + [over.ics.rank] + + --If class B is derived directly or indirectly from class A, + conversion of B* to A* is better than conversion of B* to + void*, and conversion of A* to void* is better than + conversion of B* to void*. */ + if (TREE_CODE (deref_to_type1) == VOID_TYPE + && TREE_CODE (deref_to_type2) == VOID_TYPE) { - if (distf > 0) - return 1; - else if (distf < 0) + if (is_properly_derived_from (deref_from_type1, + deref_from_type2)) return -1; + else if (is_properly_derived_from (deref_from_type2, + deref_from_type1)) + return 1; } - else if (TREE_CODE (to2) == VOID_TYPE && IS_AGGR_TYPE (to1) - && DERIVED_FROM_P (to1, from1)) - return 1; - else if (TREE_CODE (to1) == VOID_TYPE && IS_AGGR_TYPE (to2) - && DERIVED_FROM_P (to2, from2)) - return -1; - - if (! (IS_AGGR_TYPE (to1) && IS_AGGR_TYPE (to2))) - return 0; - - /* If class B is derived directly or indirectly from class A and class - C is derived directly or indirectly from B */ - - distt = get_base_distance (to1, to2, 0, 0); - if (distt == -1) + else if (TREE_CODE (deref_to_type1) == VOID_TYPE + || TREE_CODE (deref_to_type2) == VOID_TYPE) { - distt = -get_base_distance (to2, to1, 0, 0); - if (distt == 1) - return 0; + if (comptypes (deref_from_type1, deref_from_type2, 1)) + { + if (TREE_CODE (deref_to_type2) == VOID_TYPE) + { + if (is_properly_derived_from (deref_from_type1, + deref_to_type1)) + return 1; + } + /* We know that DEREF_TO_TYPE1 is `void' here. */ + else if (is_properly_derived_from (deref_from_type1, + deref_to_type2)) + return -1; + } } - - /* --conversion of C* to B* is better than conversion of C* to A*, */ - if (distf == 0) + else if (IS_AGGR_TYPE_CODE (TREE_CODE (deref_to_type1)) + && IS_AGGR_TYPE_CODE (TREE_CODE (deref_to_type2))) { - if (distt > 0) - return -1; - else if (distt < 0) - return 1; + /* [over.ics.rank] + + --If class B is derived directly or indirectly from class A + and class C is derived directly or indirectly from B, + + --conversion of C* to B* is better than conversion of C* to + A*, + + --conversion of B* to A* is better than conversion of C* to + A* */ + if (comptypes (deref_from_type1, deref_from_type2, 1)) + { + if (is_properly_derived_from (deref_to_type1, + deref_to_type2)) + return 1; + else if (is_properly_derived_from (deref_to_type2, + deref_to_type1)) + return -1; + } + else if (comptypes (deref_to_type1, deref_to_type2, 1)) + { + if (is_properly_derived_from (deref_from_type2, + deref_from_type1)) + return 1; + else if (is_properly_derived_from (deref_from_type1, + deref_from_type2)) + return -1; + } } - /* --conversion of B* to A* is better than conversion of C* to A*, */ - else if (distt == 0) + } + else if (IS_AGGR_TYPE_CODE (TREE_CODE (from_type1)) + && comptypes (from_type1, from_type2, 1)) + { + /* [over.ics.rank] + + --binding of an expression of type C to a reference of type + B& is better than binding an expression of type C to a + reference of type A& + + --conversion of C to B is better than conversion of C to A, */ + if (is_properly_derived_from (from_type1, to_type1) + && is_properly_derived_from (from_type1, to_type2)) { - if (distf > 0) + if (is_properly_derived_from (to_type1, to_type2)) return 1; - else if (distf < 0) + else if (is_properly_derived_from (to_type2, to_type1)) return -1; } } - else if (TREE_CODE (TREE_TYPE (main1)) == POINTER_TYPE - || TYPE_PTRMEMFUNC_P (TREE_TYPE (main1))) + else if (IS_AGGR_TYPE_CODE (TREE_CODE (to_type1)) + && comptypes (to_type1, to_type2, 1)) { - if (TREE_TYPE (main1) == TREE_TYPE (main2)) - return compare_qual (ics1, ics2); - -#if 0 /* This is now handled by making identity better than anything else. */ - /* existing practice, not WP-endorsed: const char * -> const char * - is better than char * -> const char *. (jason 6/29/96) */ - if (TREE_TYPE (ics1) == TREE_TYPE (ics2)) - return -compare_qual (main1, main2); -#endif + /* [over.ics.rank] + + --binding of an expression of type B to a reference of type + A& is better than binding an expression of type C to a + reference of type A&, + + --onversion of B to A is better than conversion of C to A */ + if (is_properly_derived_from (from_type1, to_type1) + && is_properly_derived_from (from_type2, to_type1)) + { + if (is_properly_derived_from (from_type2, from_type1)) + return 1; + else if (is_properly_derived_from (from_type1, from_type2)) + return -1; + } } + /* [over.ics.rank] + + --S1 and S2 differ only in their qualification conversion and yield + similar types T1 and T2 (_conv.qual_), respectively, and the cv- + qualification signature of type T1 is a proper subset of the cv- + qualification signature of type T2 */ + if (TREE_CODE (ics1) == QUAL_CONV + && TREE_CODE (ics2) == QUAL_CONV + && comptypes (from_type1, from_type2, 1)) + return comp_cv_qual_signature (to_type1, to_type2); + + /* [over.ics.rank] + + --S1 and S2 are reference bindings (_dcl.init.ref_), and the + types to which the references refer are the same type except for + top-level cv-qualifiers, and the type to which the reference + initialized by S2 refers is more cv-qualified than the type to + which the reference initialized by S1 refers */ + + if (ref_binding1 && ref_binding2 + && comptypes (TYPE_MAIN_VARIANT (to_type1), + TYPE_MAIN_VARIANT (to_type2), 1)) + return comp_cv_qualification (reference_type2, reference_type1); + + /* Neither conversion sequence is better than the other. */ return 0; } diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index a42ac73..8679f58 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1362,6 +1362,11 @@ extern int flag_new_for_scope; pointer to member function. TYPE_PTRMEMFUNC_P _must_ be true, before using this macro. */ #define TYPE_PTRMEMFUNC_FN_TYPE(NODE) (TREE_TYPE (TYPE_FIELDS (TREE_TYPE (TREE_CHAIN (TREE_CHAIN (TYPE_FIELDS (NODE))))))) + +/* Returns `A' for a type like `int (A::*)(double)' */ +#define TYPE_PTRMEMFUNC_OBJECT_TYPE(NODE) \ + TYPE_METHOD_BASETYPE (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (NODE))) + /* These are use to manipulate the canonical RECORD_TYPE from the hashed POINTER_TYPE, and can only be used on the POINTER_TYPE. */ #define TYPE_GET_PTRMEMFUNC_TYPE(NODE) ((tree)TYPE_LANG_SPECIFIC(NODE)) @@ -2770,6 +2775,8 @@ extern int comptypes PROTO((tree, tree, int)); extern int comp_target_types PROTO((tree, tree, int)); extern int compparms PROTO((tree, tree, int)); extern int comp_target_types PROTO((tree, tree, int)); +extern int comp_cv_qualification PROTO((tree, tree)); +extern int comp_cv_qual_signature PROTO((tree, tree)); extern int self_promoting_args_p PROTO((tree)); extern tree unsigned_type PROTO((tree)); extern tree signed_type PROTO((tree)); diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 9e721dd..de5c3b3 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -1048,6 +1048,46 @@ comp_target_types (ttl, ttr, nptrs) return 0; } +/* Returns 1 if TYPE1 is more cv-qualified than TYPE2, -1 if TYPE2 is + more cv-qualified that TYPE1, and 0 otherwise. */ + +int +comp_cv_qualification (type1, type2) + tree type1; + tree type2; +{ + if (TYPE_READONLY (type1) == TYPE_READONLY (type2) + && TYPE_VOLATILE (type1) == TYPE_VOLATILE (type2)) + return 0; + + if (TYPE_READONLY (type1) >= TYPE_READONLY (type2) + && TYPE_VOLATILE (type1) >= TYPE_VOLATILE (type2)) + return 1; + + if (TYPE_READONLY (type2) >= TYPE_READONLY (type1) + && TYPE_VOLATILE (type2) >= TYPE_VOLATILE (type1)) + return -1; + + return 0; +} + +/* Returns 1 if the cv-qualification signature of TYPE1 is a proper + subset of the cv-qualification signature of TYPE2, and the types + are similar. Returns -1 if the other way 'round, and 0 otherwise. */ + +int +comp_cv_qual_signature (type1, type2) + tree type1; + tree type2; +{ + if (comp_ptr_ttypes_real (type2, type1, -1)) + return 1; + else if (comp_ptr_ttypes_real (type1, type2, -1)) + return -1; + else + return 0; +} + /* If two types share a common base type, return that basetype. If there is not a unique most-derived base type, this function returns ERROR_MARK_NODE. */ @@ -7409,14 +7449,21 @@ c_expand_start_case (exp) return exp; } -/* CONSTP remembers whether or not all the intervening pointers in the `to' - type have been const. */ +/* Returns non-zero if the pointer-type FROM can be converted to the + pointer-type TO via a qualification conversion. If CONSTP is -1, + then we return non-zero if the pointers are similar, and the + cv-qualification signature of FROM is a proper subset of that of TO. + + If CONSTP is positive, then all outer pointers have been + const-qualified. */ static int comp_ptr_ttypes_real (to, from, constp) tree to, from; int constp; { + int to_more_cv_qualified = 0; + for (; ; to = TREE_TYPE (to), from = TREE_TYPE (from)) { if (TREE_CODE (to) != TREE_CODE (from)) @@ -7431,19 +7478,32 @@ comp_ptr_ttypes_real (to, from, constp) so the usual checks are not appropriate. */ if (TREE_CODE (to) != FUNCTION_TYPE && TREE_CODE (to) != METHOD_TYPE) { - if (TYPE_READONLY (from) > TYPE_READONLY (to) - || TYPE_VOLATILE (from) > TYPE_VOLATILE (to)) - return 0; + switch (comp_cv_qualification (from, to)) + { + case 1: + /* FROM is more cv-qualified than TO. */ + return 0; - if (! constp - && (TYPE_READONLY (to) > TYPE_READONLY (from) - || TYPE_VOLATILE (to) > TYPE_READONLY (from))) - return 0; - constp &= TYPE_READONLY (to); + case -1: + /* TO is more cv-qualified than FROM. */ + if (constp == 0) + return 0; + else + ++to_more_cv_qualified; + break; + + default: + break; + } + + if (constp > 0) + constp &= TYPE_READONLY (to); } if (TREE_CODE (to) != POINTER_TYPE) - return comptypes (TYPE_MAIN_VARIANT (to), TYPE_MAIN_VARIANT (from), 1); + return + comptypes (TYPE_MAIN_VARIANT (to), TYPE_MAIN_VARIANT (from), 1) + && (constp >= 0 || to_more_cv_qualified); } } diff --git a/gcc/testsuite/g++.old-deja/g++.other/overload3.C b/gcc/testsuite/g++.old-deja/g++.other/overload3.C new file mode 100644 index 0000000..fc1d5c0 --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.other/overload3.C @@ -0,0 +1,16 @@ +// Build don't run: + +void f(const int *); +void f(int *) {} + +void f2(const volatile int *); +void f2(volatile int *) {} + +int i; + +int main() +{ + f(&i); + f2(&i); +} + diff --git a/gcc/testsuite/g++.old-deja/g++.other/overload4.C b/gcc/testsuite/g++.old-deja/g++.other/overload4.C new file mode 100644 index 0000000..2247853 --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.other/overload4.C @@ -0,0 +1,10 @@ +// Build don't run: + +void f(int* const volatile * const * const*); +void f(int* const * const * const*) {} + +int main() +{ + int*** ip; + f(&ip); +} diff --git a/gcc/testsuite/g++.old-deja/g++.other/overload5.C b/gcc/testsuite/g++.old-deja/g++.other/overload5.C new file mode 100644 index 0000000..5f5e11f --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.other/overload5.C @@ -0,0 +1,22 @@ +// Build don't run: + +struct S {}; + +struct T : public S {}; + +struct U : public T {}; + +void f(int T::*) {} +void f(int U::*); + +void g(void (T::*)(int)) {} +void g(void (U::*)(int)); + +int main() +{ + int S::*ip; + void (S::*fp)(int); + + f(ip); + g(fp); +} |