OSDN Git Service

PR c++/3637
authormmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 20 Nov 2001 09:00:33 +0000 (09:00 +0000)
committermmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 20 Nov 2001 09:00:33 +0000 (09:00 +0000)
* 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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@47209 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/cp/ChangeLog
gcc/cp/call.c
gcc/testsuite/g++.dg/ref1.C [new file with mode: 0644]

index df49519..9d78cbe 100644 (file)
@@ -1,3 +1,12 @@
+2001-11-20  Mark Mitchell  <mark@codesourcery.com>
+
+       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 <johnw@research.att.com>
 
        * dump.c (dump_op): New function.
index 91bc097..4d06dc5 100644 (file)
@@ -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 (file)
index 0000000..aaf04cf
--- /dev/null
@@ -0,0 +1,47 @@
+// Origin: Peter Schmid <schmid@snake.iap.physik.tu-darmstadt.de>
+
+// { dg-do link }
+
+template <class T>
+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<foo> 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);
+}