C++ PATCH for c++/50512 (regression in overload resolution)

Message ID 4E80BDA3.2030301@redhat.com
State New
Headers show

Commit Message

Jason Merrill Sept. 26, 2011, 6 p.m.
My patch for DR 1328 started comparing rvaluedness_matches_p for all 
reference binding conversions, not just those where the target type 
differs in rvaluedness.  In this testcase, the rvaluedness of the 
initializer differs: when calling the first function the initializer is 
a pointer constant, while with the second one the initializer is an 
array lvalue.  This patch avoids preferring the second by limiting the 
rvaluedness match test to either cases where the target type differs in 
rvaluedness or is the same.

Tested x86_64-pc-linux-gnu, applied to trunk.


commit a745b69ecfdad74c803282e29749c4deec416a3f
Author: Jason Merrill <jason@redhat.com>
Date:   Mon Sep 26 13:36:57 2011 -0400

    	PR c++/50512
    	* call.c (compare_ics): Only consider rvaluedness_matches_p
    	if the target type is the same or it too differs in rvalueness.

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 579e563..a52ec29 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -7864,18 +7864,25 @@  compare_ics (conversion *ics1, conversion *ics2)
      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 */
+     which the reference initialized by S1 refers.
+     DR 1328 [over.match.best]: the context is an initialization by
+     conversion function for direct reference binding ( of a
+     reference to function type, the return type of F1 is the same kind of
+     reference (i.e. lvalue or rvalue) as the reference being initialized,
+     and the return type of F2 is not.  */
   if (ref_conv1 && ref_conv2)
-      if (!ref_conv1->this_p && !ref_conv2->this_p)
+      if (!ref_conv1->this_p && !ref_conv2->this_p
+	  && (ref_conv1->rvaluedness_matches_p
+	      != ref_conv2->rvaluedness_matches_p)
+	  && (same_type_p (ref_conv1->type, ref_conv2->type)
+	      || (TYPE_REF_IS_RVALUE (ref_conv1->type)
+		  != TYPE_REF_IS_RVALUE (ref_conv2->type))))
-	  if (ref_conv1->rvaluedness_matches_p
-	      > ref_conv2->rvaluedness_matches_p)
-	    return 1;
-	  if (ref_conv2->rvaluedness_matches_p
-	      > ref_conv1->rvaluedness_matches_p)
-	    return -1;
+	  return (ref_conv1->rvaluedness_matches_p
+		  - ref_conv2->rvaluedness_matches_p);
       if (same_type_ignoring_top_level_qualifiers_p (to_type1, to_type2))
diff --git a/gcc/testsuite/g++.dg/overload/rvalue3.C b/gcc/testsuite/g++.dg/overload/rvalue3.C
new file mode 100644
index 0000000..5a5d237
--- /dev/null
+++ b/gcc/testsuite/g++.dg/overload/rvalue3.C
@@ -0,0 +1,8 @@ 
+// PR c++/50512
+void foo (const char *const& s);
+template<typename C> void foo (const C& x) { x.a; }
+void f () {
+  foo ("abc");