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.
commit dd9a42cf5c84e8bb2f14d8d70544261e6c75794a
Author: Jason Merrill <ja...@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()});
+}