diff mbox

[C++] PR 52174 aka DR 1423

Message ID 538DDBF6.70102@oracle.com
State New
Headers show

Commit Message

Paolo Carlini June 3, 2014, 2:30 p.m. UTC
Hi,

implementing the resolution seems rather straightforward, just check 
LOOKUP_ONLYCONVERTING in standard_conversion. However, while playing 
with some additional tests outside bug & testsuite (similar to 
nullptr32.C), I noticed a latent issue: in case of base initializers we 
were setting anyway LOOKUP_ONLYCONVERTING in add_function_candidate (the 
other cases listed in 8.5/16 are handled elsewhere and seem all fine). 
Thus the rather ad-hoc-ish tweak there: I spent some time on it and 
couldn't find anything reasonably simple & better, appears to work 
anyway, for templates too.

Tested x86_64-linux.

Thanks,
Paolo.

//////////////////////////
gcc/cp
2014-06-03  Paolo Carlini  <paolo.carlini@oracle.com>

	DR 1423
	PR c++/52174
	* call.c (standard_conversion): Convert nullptr to bool only
	in case of direct-initialization.
	(add_function_candidate): Do not set LOOKUP_ONLYCONVERTING
	in lflags when processing a base initializer. 

gcc/testsuite
2014-06-03  Paolo Carlini  <paolo.carlini@oracle.com>

	DR 1423
	PR c++/52174
	* g++.dg/cpp0x/nullptr31.C: New.
	* g++.dg/cpp0x/nullptr32.C: Likewise.
	* g++.dg/cpp0x/sfinae-nullptr1.C: Likewise.
	* g++.dg/cpp0x/nullptr17.C: Update.

libstdc++-v3
2014-06-03  Paolo Carlini  <paolo.carlini@oracle.com>

	DR 1423
	PR c++/52174
	* testsuite/20_util/is_assignable/value.cc: Update.

Comments

Paolo Carlini June 3, 2014, 2:41 p.m. UTC | #1
.. wondering if I should check DECL_CONSTRUCTOR_P (fn) too.

Paolo.
Jason Merrill June 3, 2014, 3:02 p.m. UTC | #2
On 06/03/2014 10:30 AM, Paolo Carlini wrote:
> implementing the resolution seems rather straightforward, just check
> LOOKUP_ONLYCONVERTING in standard_conversion.

Yep.  Though it would be better to return a bad_p conversion than none 
at all.

> However, while playing
> with some additional tests outside bug & testsuite (similar to
> nullptr32.C), I noticed a latent issue: in case of base initializers we
> were setting anyway LOOKUP_ONLYCONVERTING in add_function_candidate

Right.  In the case of

> +  TDerived()
> +  : TBase<T>(nullptr) { }

we have direct-initialization of TBase<T>, but the parameter of the 
TBase constructor is copy-initialized, so nullptr32.C is ill-formed; 
please drop this hunk of the patch.

Jason
diff mbox

Patch

Index: gcc/cp/call.c
===================================================================
--- gcc/cp/call.c	(revision 211162)
+++ gcc/cp/call.c	(working copy)
@@ -1311,15 +1311,15 @@  standard_conversion (tree to, tree from, tree expr
     {
       /* [conv.bool]
 
-	  An rvalue of arithmetic, unscoped enumeration, pointer, or
-	  pointer to member type can be converted to an rvalue of type
-	  bool. ... An rvalue of type std::nullptr_t can be converted
-	  to an rvalue of type bool;  */
+	  A prvalue of arithmetic, unscoped enumeration, pointer, or pointer
+	  to member type can be converted to a prvalue of type bool. ...
+	  For direct-initialization (8.5 [dcl.init]), a prvalue of type
+	  std::nullptr_t can be converted to a prvalue of type bool;  */
       if (ARITHMETIC_TYPE_P (from)
 	  || UNSCOPED_ENUM_P (from)
 	  || fcode == POINTER_TYPE
 	  || TYPE_PTRMEM_P (from)
-	  || NULLPTR_TYPE_P (from))
+	  || (NULLPTR_TYPE_P (from) && !(flags & LOOKUP_ONLYCONVERTING)))
 	{
 	  conv = build_conv (ck_std, to, conv);
 	  if (fcode == POINTER_TYPE
@@ -2056,7 +2056,10 @@  add_function_candidate (struct z_candidate **candi
 		  && BRACE_ENCLOSED_INITIALIZER_P (arg))
 		lflags |= LOOKUP_NO_CONVERSION;
 	    }
-	  else
+	  /* Per 8.5/16, certainly the initialization that occurs in
+	     base initializers is direct-initialization, thus don't
+	     set the flag in that case.  */
+	  else if (!(cfun && cp_function_chain && in_base_initializer))
 	    lflags |= LOOKUP_ONLYCONVERTING;
 
 	  t = implicit_conversion (parmtype, argtype, arg,
Index: gcc/testsuite/g++.dg/cpp0x/nullptr17.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/nullptr17.C	(revision 211162)
+++ gcc/testsuite/g++.dg/cpp0x/nullptr17.C	(working copy)
@@ -1,6 +1,7 @@ 
 // { dg-do compile { target c++11 } }
 
-// Test that bool is a better overload match than int
+// Used to test that bool is a better overload match than int
+// Updated for DR 1423
 
 template <typename T, typename U> struct tType_equal;
 template <typename T> struct tType_equal<T, T> { typedef void type; };
@@ -16,7 +17,7 @@  bool i( bool );
 void test_i()
 {
   // Overload to bool, not int
-  type_equal<bool>(i(nullptr));
+  type_equal<bool>(i(nullptr));  // { dg-error "no matching" }
   decltype(nullptr) mynull = 0;
-  type_equal<bool>(i(mynull));
+  type_equal<bool>(i(mynull));   // { dg-error "no matching" }
 }
Index: gcc/testsuite/g++.dg/cpp0x/nullptr31.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/nullptr31.C	(revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/nullptr31.C	(working copy)
@@ -0,0 +1,11 @@ 
+// DR 1423, PR c++/52174
+// { dg-do compile { target c++11 } }
+
+bool b1 = nullptr;  // { dg-error "cannot convert" }
+
+bool b2(nullptr);
+bool b3{nullptr};
+
+int  i1 = nullptr;  // { dg-error "cannot convert" }
+int  i2(nullptr);   // { dg-error "cannot convert" }
+int  i3{nullptr};   // { dg-error "cannot convert" }
Index: gcc/testsuite/g++.dg/cpp0x/nullptr32.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/nullptr32.C	(revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/nullptr32.C	(working copy)
@@ -0,0 +1,30 @@ 
+// DR 1423, PR c++/52174
+// { dg-do compile { target c++11 } }
+
+struct Base
+{
+  Base(bool);
+};
+
+struct Derived
+: Base
+{
+  Derived()
+  : Base(nullptr) { }
+};
+
+template<typename>
+struct TBase
+{
+  TBase(bool);
+};
+
+template<typename T>
+struct TDerived
+: TBase<T>
+{
+  TDerived()
+  : TBase<T>(nullptr) { }
+};
+
+template class TDerived<int>;
Index: gcc/testsuite/g++.dg/cpp0x/sfinae-nullptr1.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/sfinae-nullptr1.C	(revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/sfinae-nullptr1.C	(working copy)
@@ -0,0 +1,18 @@ 
+// DR 1423, PR c++/52174
+// { dg-do compile { target c++11 } }
+
+template<class T>
+T&& make();
+
+template<class T>
+void sink(T);
+
+template<class T1, class T2,
+  class = decltype(sink<T2>(make<T1>()))
+>
+auto f(int) -> char(&)[1];
+
+template<class, class>
+auto f(...) -> char(&)[2];
+
+static_assert(sizeof(f<decltype(nullptr), bool>(0)) != 1, "");
Index: libstdc++-v3/testsuite/20_util/is_assignable/value.cc
===================================================================
--- libstdc++-v3/testsuite/20_util/is_assignable/value.cc	(revision 211151)
+++ libstdc++-v3/testsuite/20_util/is_assignable/value.cc	(working copy)
@@ -174,7 +174,7 @@  static_assert(!std::is_assignable<bool&, SE>::valu
 static_assert(std::is_assignable<bool&, void*>::value, "Error");
 static_assert(std::is_assignable<bool&, int B::*>::value, "Error");
 static_assert(std::is_assignable<bool&, void*>::value, "Error");
-static_assert(std::is_assignable<bool&, std::nullptr_t>::value, "Error");
+static_assert(!std::is_assignable<bool&, std::nullptr_t>::value, "Error");
 
 static_assert(std::is_assignable<std::nullptr_t&,
 std::nullptr_t>::value, "Error");