From 218e9dde70559f520bc54c6b749acb2b678d861e Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Tue, 19 Apr 2016 14:50:08 -0400 Subject: [PATCH] DR 2137 - copy-constructor rank in list-initialization * 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 | 5 +++++ gcc/cp/call.c | 19 ++++++++++++++++++- gcc/testsuite/g++.dg/DRs/dr2137-1.C | 20 ++++++++++++++++++++ gcc/testsuite/g++.dg/DRs/dr2137-2.C | 21 +++++++++++++++++++++ 4 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/DRs/dr2137-1.C create mode 100644 gcc/testsuite/g++.dg/DRs/dr2137-2.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index a2509af865b..7ff3dc57325 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,10 @@ 2016-04-19 Jason Merrill + 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 diff --git a/gcc/cp/call.c b/gcc/cp/call.c index ed234904a63..11f2d42108e 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 00000000000..ad6b5325a1e --- /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 + +bool ok = false; + +struct Q { + Q() = default; + Q(Q const&) = default; + Q(Q&&) = default; + Q(std::initializer_list) { 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 00000000000..ba90860b3af --- /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()}); +} -- 2.30.2