diff mbox

C++ PATCH for core issue 2137

Message ID 57166EF1.8070401@redhat.com
State New
Headers show

Commit Message

Jason Merrill April 19, 2016, 5:46 p.m. UTC
Issue 2137 corrects the previous adjustment of list-initialization to 
allow copying of aggregates so that it also gives such an initialization 
the same implicit conversion sequence rank as the same copy constructor 
called with () syntax.

Tested x86_64-pc-linux-gnu, applying to trunk.
diff mbox

Patch

commit dd9a42cf5c84e8bb2f14d8d70544261e6c75794a
Author: Jason Merrill <jason@redhat.com>
Date:   Mon Feb 29 21:42:31 2016 -0500

    	DR 2137
    
    	* call.c (implicit_conversion): If we choose a copy constructor
    	for list-initialization from the same type, the conversion is an
    	exact match.

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index ef195f8..636f8f6 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -1862,7 +1862,24 @@  implicit_conversion (tree to, tree from, tree expr, bool c_cast_p,
 
       cand = build_user_type_conversion_1 (to, expr, flags, complain);
       if (cand)
-	conv = cand->second_conv;
+	{
+	  if (BRACE_ENCLOSED_INITIALIZER_P (expr)
+	      && CONSTRUCTOR_NELTS (expr) == 1
+	      && !is_list_ctor (cand->fn))
+	    {
+	      /* "If C is not an initializer-list constructor and the
+		 initializer list has a single element of type cv U, where U is
+		 X or a class derived from X, the implicit conversion sequence
+		 has Exact Match rank if U is X, or Conversion rank if U is
+		 derived from X."  */
+	      tree elt = CONSTRUCTOR_ELT (expr, 0)->value;
+	      tree elttype = TREE_TYPE (elt);
+	      if (reference_related_p (to, elttype))
+		return implicit_conversion (to, elttype, elt,
+					    c_cast_p, flags, complain);
+	    }
+	  conv = cand->second_conv;
+	}
 
       /* We used to try to bind a reference to a temporary here, but that
 	 is now handled after the recursive call to this function at the end
diff --git a/gcc/testsuite/g++.dg/DRs/dr2137-1.C b/gcc/testsuite/g++.dg/DRs/dr2137-1.C
new file mode 100644
index 0000000..ad6b532
--- /dev/null
+++ b/gcc/testsuite/g++.dg/DRs/dr2137-1.C
@@ -0,0 +1,20 @@ 
+// DR 2137
+// { dg-do run { target c++11 } }
+
+// Test that an initializer_list constructor beats the copy constructor.
+
+#include <initializer_list>
+
+bool ok = false;
+
+struct Q {
+  Q() = default;
+  Q(Q const&) = default;
+  Q(Q&&) = default;
+  Q(std::initializer_list<Q>) { ok = true; }
+};
+
+int main() {
+  Q x = Q { Q() };
+  if (!ok) __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/DRs/dr2137-2.C b/gcc/testsuite/g++.dg/DRs/dr2137-2.C
new file mode 100644
index 0000000..ba90860
--- /dev/null
+++ b/gcc/testsuite/g++.dg/DRs/dr2137-2.C
@@ -0,0 +1,21 @@ 
+// DR 2137
+// { dg-do link { target c++11 } }
+
+// Test that copying Q is better than converting to R.
+
+struct Q {
+  Q() { }
+  Q(const Q&) { }
+};
+
+struct R {
+  R(const Q&);
+};
+
+void f(Q) { }
+void f(R);
+
+int main()
+{
+  f({Q()});
+}