diff mbox

C++ PATCH for c++/51553 (list-initialization using conversion op)

Message ID 4EEF99BA.8040800@redhat.com
State New
Headers show

Commit Message

Jason Merrill Dec. 19, 2011, 8:08 p.m. UTC
The code I put in back when I implemented list-initialization rejects 
additional user-defined conversions when considering the copy parm of a 
copy/move constructor, in order to avoid ambiguity when a nested 
braced-init-list could initialize either the copy parm or the parm of 
another constructor.  But this testcase shows that this is too broad; we 
only want to suppress the copy constructor when the argument is another 
braced-init-list.

That change fixes most of the testcase, but then we incorrectly accept 
the declaration of 'c'.  To fix that, we need to separate the handling 
of explicit constructors from explicit conversion operators in 
list-initialization.

Tested x86_64-pc-linux-gnu, applying to trunk.
diff mbox

Patch

commit 7186017c5f76e0673483df849965fe705e45dcf3
Author: Jason Merrill <jason@redhat.com>
Date:   Mon Dec 19 14:01:11 2011 -0500

    	PR c++/51553
    	* cp-tree.h (LOOKUP_LIST_INIT_CTOR): Rename from
    	LOOKUP_NO_COPY_CTOR_CONVERSION.
    	(add_list_candidates): Set it earlier.
    	(add_candidates): Don't check explicit on ctors when it's set.
    	(add_function_candidate): Check it even when LOOKUP_ONLYCONVERTING
    	is set.

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 3e6db51..29aed98 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -1956,17 +1956,17 @@  add_function_candidate (struct z_candidate **candidates,
 	     to handle move constructors and template constructors as well;
 	     the standardese should soon be updated similarly.  */
 	  if (ctype && i == 0 && (len-skip == 1)
-	      && !(flags & LOOKUP_ONLYCONVERTING)
 	      && DECL_CONSTRUCTOR_P (fn)
 	      && parmtype != error_mark_node
 	      && (same_type_ignoring_top_level_qualifiers_p
 		  (non_reference (parmtype), ctype)))
 	    {
-	      lflags |= LOOKUP_COPY_PARM;
+	      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_NO_COPY_CTOR_CONVERSION)
+	      if ((flags & LOOKUP_LIST_INIT_CTOR)
 		  && BRACE_ENCLOSED_INITIALIZER_P (arg))
 		lflags |= LOOKUP_NO_CONVERSION;
 	    }
@@ -3344,9 +3344,8 @@  add_list_candidates (tree fns, tree first_arg,
 
   gcc_assert (*candidates == NULL);
 
-  /* For list-initialization we consider explicit constructors, but
-     give an error if one is selected.  */
-  flags &= ~LOOKUP_ONLYCONVERTING;
+  /* We're looking for a ctor for list-initialization.  */
+  flags |= LOOKUP_LIST_INIT_CTOR;
   /* And we don't allow narrowing conversions.  We also use this flag to
      avoid the copy constructor call for copy-list-initialization.  */
   flags |= LOOKUP_NO_NARROWING;
@@ -3374,8 +3373,6 @@  add_list_candidates (tree fns, tree first_arg,
   flags &= ~LOOKUP_LIST_ONLY;
   /* We allow more user-defined conversions within an init-list.  */
   flags &= ~LOOKUP_NO_CONVERSION;
-  /* But not for the copy ctor.  */
-  flags |= LOOKUP_NO_COPY_CTOR_CONVERSION;
 
   add_candidates (fns, first_arg, args, NULL_TREE,
 		  explicit_targs, template_only, conversion_path,
@@ -4801,7 +4798,11 @@  add_candidates (tree fns, tree first_arg, const VEC(tree,gc) *args,
       if (DECL_CONSTRUCTOR_P (fn))
 	{
 	  check_list_ctor = !!(flags & LOOKUP_LIST_ONLY);
-	  check_converting = !!(flags & LOOKUP_ONLYCONVERTING);
+	  /* For list-initialization we consider explicit constructors
+	     and complain if one is chosen.  */
+	  check_converting
+	    = ((flags & (LOOKUP_ONLYCONVERTING|LOOKUP_LIST_INIT_CTOR))
+	       == LOOKUP_ONLYCONVERTING);
 	}
       else
 	{
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 42a9ced..633b6b4 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -4384,11 +4384,10 @@  enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, TYPENAME_FLAG };
 #define LOOKUP_PREFER_RVALUE (LOOKUP_HIDDEN << 1)
 /* We're inside an init-list, so narrowing conversions are ill-formed.  */
 #define LOOKUP_NO_NARROWING (LOOKUP_PREFER_RVALUE << 1)
-/* Avoid user-defined conversions for the first parameter of a copy
-   constructor (or move constructor).  */
-#define LOOKUP_NO_COPY_CTOR_CONVERSION (LOOKUP_NO_NARROWING << 1)
+/* We're looking up a constructor for list-initialization.  */
+#define LOOKUP_LIST_INIT_CTOR (LOOKUP_NO_NARROWING << 1)
 /* This is the first parameter of a copy constructor.  */
-#define LOOKUP_COPY_PARM (LOOKUP_NO_COPY_CTOR_CONVERSION << 1)
+#define LOOKUP_COPY_PARM (LOOKUP_LIST_INIT_CTOR << 1)
 /* We only want to consider list constructors.  */
 #define LOOKUP_LIST_ONLY (LOOKUP_COPY_PARM << 1)
 /* Return after determining which function to call and checking access.
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist64.C b/gcc/testsuite/g++.dg/cpp0x/initlist64.C
index 337e89b..bcf1658 100644
--- a/gcc/testsuite/g++.dg/cpp0x/initlist64.C
+++ b/gcc/testsuite/g++.dg/cpp0x/initlist64.C
@@ -22,7 +22,7 @@  X aa = Y();
 X b{ Y() };
 X bb(Y());
 
-X c = { Z() };  // { dg-error "" "" { xfail *-*-* } }
+X c = { Z() };  // { dg-error "" }
 X cc = Z();	// { dg-error "" }
 
 X d{ Z() };