diff mbox

[C++] PR 64418

Message ID 549EE327.8080009@gmail.com
State New
Headers show

Commit Message

Momchil Velikov Dec. 27, 2014, 4:49 p.m. UTC
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.

Comments

Paolo Carlini Dec. 27, 2014, 6:32 p.m. UTC | #1
Hi,

On 12/27/2014 05:49 PM, Momchil Velikov wrote:
> +		 conversion in the context of list-initialisation.  */
Nit: I think you want to spell initialization, with a z, like in the 
standard (and all the uses of the expression in our front-end)

Paolo.
Jason Merrill Dec. 27, 2014, 11:47 p.m. UTC | #2
On 12/27/2014 11:49 AM, Momchil Velikov wrote:
> struct C {
>        C(const C &);
> };
>
> struct X {
>        operator C() const;
> };
>
> C a{X()};
>
> 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.

As I commented on the PR, the current G++ behavior is correct under the 
resolution of DR 1467.

Jason
diff mbox

Patch

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};