Hello,
This patch fixes an issue with C++11 where user-defined conversion is
not properly suppressed in certain cases of list-initialisation.
Consider the example:
--- 8< ------
struct C {
C(const C &);
};
struct X {
operator C() const;
};
C a{X()};
--- 8< ------
This program is successfully compiled. However, I believe this is an
erroneous behaviour.
The variable "a" is initialised by direct list-initialization
according to 8.5.4. [dcl.init.list] #3 and 13.3.1.7 [over.match.list].
As the class C does not have an initializer-list ctor, all the
constructors of C are tried with the elements of the initializer list
as arguments.
GCC tries and in fact finds a user-defined conversion sequence from X
to the first parameter of the C's copy-ctor.
However, according to 13.3.3.1 [over.best.ics] #4,
"[...] when considering the argument of a constructor [...] that is a
candidate by [...] by 13.3.1.7 [...] or when the initializer list has
exactly one element and a conversion to some class X or reference to
(possibly cv-qualified) X is considered for the first parameter of a
constructor of X [...] only standard conversion sequences and ellipsis
conversion sequences are considered.
Bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51553 is related to
this one.
Bootstrapped and regtested on:
Target: x86_64-unknown-linux-gnu
Configured with: /home/chill/src/gcc-list-conv/configure
--prefix=/home/chill/opt/gcc-list-conv --enable-languages=c,c++
--disable-multilib
Thread model: posix
gcc version 5.0.0 20141225 (experimental) [chill/list-conv revision
b97cebe:8ccc35f:77c6247fdf2b97e796de45e5a2279b3a44b2f998] (GCC)
without regressions, except the testcase initlist64.C, which, I believe
is flawed and was fixed.
/cp
2014-12-27 Momchil Velikov <momchil.veli...@gmail.com>
PR c++/64418
* call.c (add_function_candidate): Do not allow user-defined
conversions during list-initialisation, when the constructor is
called with a single argument that takes a reference to the
constructor's class.
/testsuite
2014-12-27 Momchil Velikov <momchil.veli...@gmail.com>
PR c++/64418
* g++.dg/cpp0x/initlist64.C: Fix testcase.
* g++.dg/cpp0x/initlist91.C: New.
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 86c78ab..1e36dd2 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -2078,11 +2078,10 @@ add_function_candidate (struct z_candidate **candidates,
{
if (!(flags & LOOKUP_ONLYCONVERTING))
lflags |= LOOKUP_COPY_PARM;
- /* We allow user-defined conversions within init-lists, but
- don't list-initialize the copy parm, as that would mean
- using two levels of braces for the same type. */
- if ((flags & LOOKUP_LIST_INIT_CTOR)
- && BRACE_ENCLOSED_INITIALIZER_P (arg))
+
+ /* According to [over.best.ics] #4, suppress user-defined
+ conversion in the context of list-initialisation. */
+ if ((flags & LOOKUP_LIST_INIT_CTOR))
lflags |= LOOKUP_NO_CONVERSION;
}
else
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist64.C b/gcc/testsuite/g++.dg/cpp0x/initlist64.C
index 78e5308..11e6bd9 100644
--- a/gcc/testsuite/g++.dg/cpp0x/initlist64.C
+++ b/gcc/testsuite/g++.dg/cpp0x/initlist64.C
@@ -16,14 +16,14 @@ struct Z
explicit operator X() const;
};
-X a = { Y() };
+X a = { Y() }; // { dg-error "" }
X aa = Y();
-X b{ Y() };
+X b{ Y() }; // { dg-error "" }
X bb(Y());
X c = { Z() }; // { dg-error "" }
X cc = Z(); // { dg-error "" }
-X d{ Z() };
+X d{ Z() }; // { dg-error "" }
X dd( Z() );
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist91.C b/gcc/testsuite/g++.dg/cpp0x/initlist91.C
new file mode 100644
index 0000000..9debb79
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/initlist91.C
@@ -0,0 +1,25 @@
+// PR c++/51553
+// { dg-do compile { target c++11 } }
+
+struct C {
+ C(const C &);
+ C(const C &, int);
+ C(int, const C &);
+};
+
+struct X {
+ operator C() const;
+};
+
+X x;
+
+C a{x}; // { dg-error "" }
+C b{x, 1};
+C c{1, x};
+C d(x);
+C e(x, 1);
+C f(1, x);
+C g = x;
+C h = {x}; // { dg-error "" }
+C i = {x, 1};
+C j = {1, x};