DR 2137 - copy-constructor rank in list-initialization
authorJason Merrill <jason@redhat.com>
Tue, 19 Apr 2016 18:50:08 +0000 (14:50 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Tue, 19 Apr 2016 18:50:08 +0000 (14:50 -0400)
* call.c (implicit_conversion): If we choose a copy constructor
for list-initialization from the same type, the conversion is an
exact match.

From-SVN: r235219

gcc/cp/ChangeLog
gcc/cp/call.c
gcc/testsuite/g++.dg/DRs/dr2137-1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/DRs/dr2137-2.C [new file with mode: 0644]

index a2509af865b9cbf6233b4c25f5c2059d5950c91b..7ff3dc573254353d5bbd55ec7a68237d47917a16 100644 (file)
@@ -1,5 +1,10 @@
 2016-04-19  Jason Merrill  <jason@redhat.com>
 
+       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.
+
        * constexpr.c (breaks): Handle EXIT_EXPR.
        (cxx_eval_loop_expr): Handle COMPOUND_EXPR body.
        (cxx_eval_constant_expression): Handle EXIT_EXPR, improve handling
index ed234904a63de40d13e0a087f0929ca60c1b3dc9..11f2d42108e7bc0f1b8d6f223657d718aba27503 100644 (file)
@@ -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 (file)
index 0000000..ad6b532
--- /dev/null
@@ -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 (file)
index 0000000..ba90860
--- /dev/null
@@ -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()});
+}