From f89862751006da3e7b6acebfab32c9f21d8ee41f Mon Sep 17 00:00:00 2001
From: Nathan Sidwell <nathan@codesourcery.com>
Date: Thu, 24 Apr 2003 16:31:31 +0000
Subject: [PATCH] re PR c++/10337 ("ambiguous overload"-error for non-ambiguous
 situation)

cp:
	PR c++/10337
	* call.c (joust): Don't warn about conversion ops that are exact
	or cv-conversions. Rearrange to avoid multiple type comparisons.
testsuite:
	PR c++/10337
	* g++.dg/warn/conv1.C: New test.
	* g++.old-deja/g++.other/conv7.C: Adjust.
	* g++.old-deja/g++.other/overload14.C: Adjust.

From-SVN: r66038
---
 gcc/cp/ChangeLog                              |  6 ++
 gcc/cp/call.c                                 | 75 ++++++++++---------
 gcc/testsuite/ChangeLog                       |  7 ++
 gcc/testsuite/g++.dg/warn/conv1.C             | 33 ++++++++
 gcc/testsuite/g++.old-deja/g++.other/conv7.C  |  2 +-
 .../g++.old-deja/g++.other/overload14.C       |  2 +-
 6 files changed, 89 insertions(+), 36 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/warn/conv1.C

diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 37955beae7bf..403a64270177 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,9 @@
+2003-04-24  Nathan Sidwell  <nathan@codesourcery.com>
+
+	PR c++/10337
+	* call.c (joust): Don't warn about conversion ops that are exact
+	or cv-conversions. Rearrange to avoid multiple type comparisons.
+
 2003-04-23  Mark Mitchell  <mark@codesourcery.com>
 
 	PR c++/10471
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 200aae721e74..ed97bcb95ec8 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -5757,44 +5757,51 @@ joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn)
      either between a constructor and a conversion op, or between two
      conversion ops.  */
   if (winner && cand1->second_conv
-      && ((DECL_CONSTRUCTOR_P (cand1->fn)
-	   != DECL_CONSTRUCTOR_P (cand2->fn))
-	  /* Don't warn if the two conv ops convert to the same type...  */
-	  || (! DECL_CONSTRUCTOR_P (cand1->fn)
-	      && ! same_type_p (TREE_TYPE (TREE_TYPE (cand1->fn)),
-				TREE_TYPE (TREE_TYPE (cand2->fn))))))
-    {
-      int comp = compare_ics (cand1->second_conv, cand2->second_conv);
-      if (comp != winner)
+      && (!DECL_CONSTRUCTOR_P (cand1->fn) || !DECL_CONSTRUCTOR_P (cand2->fn))
+      && winner != compare_ics (cand1->second_conv, cand2->second_conv))
+    {
+      struct z_candidate *w, *l;
+      bool give_warning = false;
+      
+      if (winner == 1)
+	w = cand1, l = cand2;
+      else
+	w = cand2, l = cand1;
+      
+      /* We don't want to complain about `X::operator T1 ()'
+	 beating `X::operator T2 () const', when T2 is a no less
+	 cv-qualified version of T1. */
+      if (DECL_CONTEXT (w->fn) == DECL_CONTEXT (l->fn)
+	  && !DECL_CONSTRUCTOR_P (w->fn) && !DECL_CONSTRUCTOR_P (l->fn))
 	{
-	  struct z_candidate *w, *l;
-	  tree convn;
-	  if (winner == 1)
-	    w = cand1, l = cand2;
-	  else
-	    w = cand2, l = cand1;
-	  if (DECL_CONTEXT (cand1->fn) == DECL_CONTEXT (cand2->fn)
-	      && ! DECL_CONSTRUCTOR_P (cand1->fn)
-	      && ! DECL_CONSTRUCTOR_P (cand2->fn)
-	      && (convn = standard_conversion
-		  (TREE_TYPE (TREE_TYPE (l->fn)),
-		   TREE_TYPE (TREE_TYPE (w->fn)), NULL_TREE))
-	      && TREE_CODE (convn) == QUAL_CONV)
-	    /* Don't complain about `operator char *()' beating
-	       `operator const char *() const'.  */;
-	  else if (warn)
+	  tree t = TREE_TYPE (TREE_TYPE (l->fn));
+	  tree f = TREE_TYPE (TREE_TYPE (w->fn));
+	  
+	  if (TREE_CODE (t) == TREE_CODE (f) && POINTER_TYPE_P (t))
 	    {
-	      tree source = source_type (TREE_VEC_ELT (w->convs, 0));
-	      if (! DECL_CONSTRUCTOR_P (w->fn))
-		source = TREE_TYPE (source);
-	      warning ("choosing `%D' over `%D'", w->fn, l->fn);
-	      warning ("  for conversion from `%T' to `%T'",
-			  source, TREE_TYPE (w->second_conv));
-	      warning ("  because conversion sequence for the argument is better");
+	      t = TREE_TYPE (t);
+	      f = TREE_TYPE (f);
 	    }
-	  else
-	    add_warning (w, l);
+	  if (!comp_ptr_ttypes (t, f))
+	    give_warning = true;
+	}
+      else
+	give_warning = true;
+      
+      if (!give_warning)
+	/*NOP*/;
+      else if (warn)
+	{
+	  tree source = source_type (TREE_VEC_ELT (w->convs, 0));
+	  if (! DECL_CONSTRUCTOR_P (w->fn))
+	    source = TREE_TYPE (source);
+	  warning ("choosing `%D' over `%D'", w->fn, l->fn);
+	  warning ("  for conversion from `%T' to `%T'",
+		   source, TREE_TYPE (w->second_conv));
+	  warning ("  because conversion sequence for the argument is better");
 	}
+      else
+	add_warning (w, l);
     }
 
   if (winner)
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 3195c2f56a37..303bbbc79e74 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,10 @@
+2003-04-24  Nathan Sidwell  <nathan@codesourcery.com>
+
+	PR c++/10337
+	* g++.dg/warn/conv1.C: New test.
+	* g++.old-deja/g++.other/conv7.C: Adjust.
+	* g++.old-deja/g++.other/overload14.C: Adjust.
+
 2003-04-23  Mark Mitchell  <mark@codesourcery.com>
 
 	PR c++/10471
diff --git a/gcc/testsuite/g++.dg/warn/conv1.C b/gcc/testsuite/g++.dg/warn/conv1.C
new file mode 100644
index 000000000000..d06cbd5863e2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/conv1.C
@@ -0,0 +1,33 @@
+// { dg-do compile }
+
+// Copyright (C) 2003 Free Software Foundation, Inc.
+// Contributed by Nathan Sidwell 20 Apr 2003 <nathan@codesourcery.com>
+
+// PR 10337, unneeded warning
+
+class A {
+  public:
+  A() {}
+};
+
+class B : public A {
+  public:
+  B() {}
+  void operator=(const A& b) {}
+  void operator=(const B& b) {}
+};
+
+class C {
+  public:
+  C() {}
+  operator B &() { return _b; }
+  operator const B &() const { return _b; }
+  
+  B _b;
+};
+
+int main() {
+  B b;
+  C c;
+  b = c;
+}
diff --git a/gcc/testsuite/g++.old-deja/g++.other/conv7.C b/gcc/testsuite/g++.old-deja/g++.other/conv7.C
index 0a7e76dfe3f8..8bb534c22630 100644
--- a/gcc/testsuite/g++.old-deja/g++.other/conv7.C
+++ b/gcc/testsuite/g++.old-deja/g++.other/conv7.C
@@ -40,6 +40,6 @@ yyparse()
 {
 
   iterator_template<IdlDeclarator_bar,IdlDeclarator_bar&,foo*,foo*> declIter;
-  const IdlDeclarator& declarator = *declIter; // WARNING - choosing
+  const IdlDeclarator& declarator = *declIter;
   return 1;
 }
diff --git a/gcc/testsuite/g++.old-deja/g++.other/overload14.C b/gcc/testsuite/g++.old-deja/g++.other/overload14.C
index 8938ef1d7d46..6ef73a6f3e6d 100644
--- a/gcc/testsuite/g++.old-deja/g++.other/overload14.C
+++ b/gcc/testsuite/g++.old-deja/g++.other/overload14.C
@@ -26,6 +26,6 @@ A::operator A::B ()
 
 int main ()
 {
-  (A::C) A ();		// WARNING - 
+  (A::C) A ();
   return 0;
 }
-- 
GitLab