diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index df495199dad..9d78cbe43df 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,12 @@ +2001-11-20 Mark Mitchell + + PR c++/3637 + * call.c (non_reference): Add documentation. + (convert_class_to_reference): Do not strip reference types + from conversion operators. + (maybe_handle_ref_bind): Simplify. + (compare_ics): Correct handling of references. + 2001-11-19 John Wilkinson * dump.c (dump_op): New function. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 91bc0978ad2..4d06dc5dcd6 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -88,7 +88,7 @@ static tree reference_binding PARAMS ((tree, tree, tree, int)); static tree non_reference PARAMS ((tree)); static tree build_conv PARAMS ((enum tree_code, tree, tree)); static int is_subseq PARAMS ((tree, tree)); -static int maybe_handle_ref_bind PARAMS ((tree*, tree*)); +static tree maybe_handle_ref_bind PARAMS ((tree*)); static void maybe_handle_implicit_object PARAMS ((tree*)); static struct z_candidate * add_candidate PARAMS ((struct z_candidate *, tree, tree, int)); @@ -648,6 +648,9 @@ build_conv (code, type, from) return t; } +/* If T is a REFERENCE_TYPE return the type to which T refers. + Otherwise, return T itself. */ + static tree non_reference (t) tree t; @@ -1024,8 +1027,7 @@ convert_class_to_reference (t, s, expr) return NULL_TREE; conv = build1 (IDENTITY_CONV, s, expr); - conv = build_conv (USER_CONV, - non_reference (TREE_TYPE (TREE_TYPE (cand->fn))), + conv = build_conv (USER_CONV, TREE_TYPE (TREE_TYPE (cand->fn)), conv); TREE_OPERAND (conv, 1) = build_ptr_wrapper (cand); ICS_USER_FLAG (conv) = 1; @@ -4764,26 +4766,25 @@ maybe_handle_implicit_object (ics) } } -/* If ICS is a REF_BIND, modify it appropriately, set TARGET_TYPE - to the type the reference originally referred to, and return 1. - Otherwise, return 0. */ +/* If *ICS is a REF_BIND set *ICS to the remainder of the conversion, + and return the type to which the reference refers. Otherwise, + leave *ICS unchanged and return NULL_TREE. */ -static int -maybe_handle_ref_bind (ics, target_type) +static tree +maybe_handle_ref_bind (ics) tree* ics; - tree* target_type; { if (TREE_CODE (*ics) == REF_BIND) { tree old_ics = *ics; - *target_type = TREE_TYPE (TREE_TYPE (*ics)); - *ics = TREE_OPERAND (*ics, 0); + tree type = TREE_TYPE (TREE_TYPE (old_ics)); + *ics = TREE_OPERAND (old_ics, 0); ICS_USER_FLAG (*ics) = ICS_USER_FLAG (old_ics); ICS_BAD_FLAG (*ics) = ICS_BAD_FLAG (old_ics); - return 1; + return type; } - return 0; + return NULL_TREE; } /* Compare two implicit conversion sequences according to the rules set out in @@ -4810,8 +4811,6 @@ compare_ics (ics1, ics2) /* REF_BINDING is non-zero if the result of the conversion sequence is a reference type. In that case TARGET_TYPE is the type referred to by the reference. */ - int ref_binding1; - int ref_binding2; tree target_type1; tree target_type2; @@ -4820,8 +4819,8 @@ compare_ics (ics1, ics2) maybe_handle_implicit_object (&ics2); /* Handle reference parameters. */ - ref_binding1 = maybe_handle_ref_bind (&ics1, &target_type1); - ref_binding2 = maybe_handle_ref_bind (&ics2, &target_type2); + target_type1 = maybe_handle_ref_bind (&ics1); + target_type2 = maybe_handle_ref_bind (&ics2); /* [over.ics.rank] @@ -5060,9 +5059,11 @@ compare_ics (ics1, ics2) } } } - else if (IS_AGGR_TYPE_CODE (TREE_CODE (from_type1)) + else if (CLASS_TYPE_P (non_reference (from_type1)) && same_type_p (from_type1, from_type2)) { + tree from = non_reference (from_type1); + /* [over.ics.rank] --binding of an expression of type C to a reference of type @@ -5070,8 +5071,8 @@ compare_ics (ics1, ics2) 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 (is_properly_derived_from (from, to_type1) + && is_properly_derived_from (from, to_type2)) { if (is_properly_derived_from (to_type1, to_type2)) return 1; @@ -5079,9 +5080,11 @@ compare_ics (ics1, ics2) return -1; } } - else if (IS_AGGR_TYPE_CODE (TREE_CODE (to_type1)) + else if (CLASS_TYPE_P (non_reference (to_type1)) && same_type_p (to_type1, to_type2)) { + tree to = non_reference (to_type1); + /* [over.ics.rank] --binding of an expression of type B to a reference of type @@ -5089,8 +5092,8 @@ compare_ics (ics1, ics2) 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_type1, to) + && is_properly_derived_from (from_type2, to)) { if (is_properly_derived_from (from_type2, from_type1)) return 1; @@ -5118,7 +5121,7 @@ compare_ics (ics1, ics2) initialized by S2 refers is more cv-qualified than the type to which the reference initialized by S1 refers */ - if (ref_binding1 && ref_binding2 + if (target_type1 && target_type2 && same_type_ignoring_top_level_qualifiers_p (to_type1, to_type2)) return comp_cv_qualification (target_type2, target_type1); diff --git a/gcc/testsuite/g++.dg/ref1.C b/gcc/testsuite/g++.dg/ref1.C new file mode 100644 index 00000000000..aaf04cff684 --- /dev/null +++ b/gcc/testsuite/g++.dg/ref1.C @@ -0,0 +1,47 @@ +// Origin: Peter Schmid + +// { dg-do link } + +template +class Ptr { +protected: + T * ptr; + +public: + + Ptr(void) : ptr(0) { }; + Ptr(T * p) : ptr(p) { }; + + ~Ptr(void) { delete ptr; } + + operator T & () { return *ptr; } +}; + +class base { +public: + base(void) { } + ~base(void) { } +}; + + +class foo : public base { +private: + foo(const foo & rv); + +public: + + foo(void) { } + ~foo(void) { } +}; + +void func2(base & b) { + // ... +} + +int main () { + Ptr f = new foo; + /* This should not result in a copy; the result of the conversion + operator should be bound directly to the reference argument to + `func2'. */ + func2(f); +}