This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

C++ PATCH for DR 1518 (c++/54835, c++/60417)


At the last C++ meeting in Lenexa, I observed that the resolution for DR 1630 resolved 1518 by saying that default-initialization could call an explicit default constructor. Since then there was wide sentiment from the library working group that this was a wrong resolution, so at this meeting we've gone back the other way, accepting that extending explicit to default constructors breaks some valid C++98 code in later C++ standard conformance modes.

So the testcases in 54835 and 60417 are ill-formed in C++11 and up.

Tested x86_64-pc-linux-gnu, applying to trunk.
commit b925e067cedd06ae1c9cf8462ae13687382cd72a
Author: Jason Merrill <jason@redhat.com>
Date:   Wed Oct 21 16:19:20 2015 -1000

    	DR 1518
    	DR 1630
    	PR c++/54835
    	PR c++/60417
    	* call.c (convert_like_real): Value-initialization can't use
    	explicit constructors in C++11 and up.

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 5b57dc9..1223dcd 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -6341,9 +6341,32 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
 	tree convfn = cand->fn;
 	unsigned i;
 
-	/* If we're initializing from {}, it's value-initialization.  Note
-	   that under the resolution of core 1630, value-initialization can
-	   use explicit constructors.  */
+	/* When converting from an init list we consider explicit
+	   constructors, but actually trying to call one is an error.  */
+	if (DECL_NONCONVERTING_P (convfn) && DECL_CONSTRUCTOR_P (convfn)
+	    /* Unless this is for direct-list-initialization.  */
+	    && !DIRECT_LIST_INIT_P (expr)
+	    /* And in C++98 a default constructor can't be explicit.  */
+	    && cxx_dialect >= cxx11)
+	  {
+	    if (!(complain & tf_error))
+	      return error_mark_node;
+	    location_t loc = location_of (expr);
+	    if (CONSTRUCTOR_NELTS (expr) == 0
+		&& FUNCTION_FIRST_USER_PARMTYPE (convfn) != void_list_node)
+	      {
+		if (pedwarn (loc, 0, "converting to %qT from initializer list "
+			     "would use explicit constructor %qD",
+			     totype, convfn))
+		  inform (loc, "in C++11 and above a default constructor "
+			  "can be explicit");
+	      }
+	    else
+	      error ("converting to %qT from initializer list would use "
+		     "explicit constructor %qD", totype, convfn);
+	  }
+
+	/* If we're initializing from {}, it's value-initialization.  */
 	if (BRACE_ENCLOSED_INITIALIZER_P (expr)
 	    && CONSTRUCTOR_NELTS (expr) == 0
 	    && TYPE_HAS_DEFAULT_CONSTRUCTOR (totype))
@@ -6359,18 +6382,6 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
 	    return expr;
 	  }
 
-	/* When converting from an init list we consider explicit
-	   constructors, but actually trying to call one is an error.  */
-	if (DECL_NONCONVERTING_P (convfn) && DECL_CONSTRUCTOR_P (convfn)
-	    /* Unless this is for direct-list-initialization.  */
-	    && !DIRECT_LIST_INIT_P (expr))
-	  {
-	    if (!(complain & tf_error))
-	      return error_mark_node;
-	    error ("converting to %qT from initializer list would use "
-		   "explicit constructor %qD", totype, convfn);
-	  }
-
 	expr = mark_rvalue_use (expr);
 
 	/* Set user_conv_p on the argument conversions, so rvalue/base
diff --git a/gcc/testsuite/g++.dg/cpp0x/explicit10.C b/gcc/testsuite/g++.dg/cpp0x/explicit10.C
new file mode 100644
index 0000000..f31f856
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/explicit10.C
@@ -0,0 +1,40 @@
+// DR 1518
+// { dg-do compile { target c++11 } }
+
+struct A {
+  explicit A() = default;
+};
+
+struct B : A {
+  explicit B() = default;
+};
+
+struct C {
+  explicit C();
+};
+
+struct D : A {
+  C c;
+  explicit D() = default;
+};
+
+template<typename T> void f() {
+  T t = {};			// { dg-error "explicit" }
+}
+template<typename T> void g() {
+  void x(T t);
+  x({});			// { dg-error "explicit" }
+}
+
+int main()
+{
+  f<A>();			// { dg-bogus "required from here" }
+  f<B>();			// { dg-message "required from here" }
+  f<C>();			// { dg-message "required from here" }
+  f<D>();			// { dg-message "required from here" }
+
+  g<A>();			// { dg-bogus "required from here" }
+  g<B>();			// { dg-message "required from here" }
+  g<C>();			// { dg-message "required from here" }
+  g<D>();			// { dg-message "required from here" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist40.C b/gcc/testsuite/g++.dg/cpp0x/initlist40.C
index de2e19d..6e6a11a 100644
--- a/gcc/testsuite/g++.dg/cpp0x/initlist40.C
+++ b/gcc/testsuite/g++.dg/cpp0x/initlist40.C
@@ -8,6 +8,6 @@ struct A
 
 int main()
 {
-  A a1 = { };
+  A a1 = { };			// { dg-error "explicit" }
   A a2 = { 24 };		// { dg-error "explicit" }
 }
diff --git a/gcc/testsuite/g++.dg/init/explicit1.C b/gcc/testsuite/g++.dg/init/explicit1.C
index f376df2..328e867 100644
--- a/gcc/testsuite/g++.dg/init/explicit1.C
+++ b/gcc/testsuite/g++.dg/init/explicit1.C
@@ -1,9 +1,10 @@
 // PR c++/60417
+// { dg-options -pedantic }
 
 struct A { explicit A(int = 0); };
 struct B { A a; };
 
 int main()
 {
-  B b = {};
+  B b = {};			// { dg-warning "explicit" "" { target c++11 } }
 }
diff --git a/gcc/testsuite/g++.dg/init/explicit2.C b/gcc/testsuite/g++.dg/init/explicit2.C
index d1dbb39..604426a 100644
--- a/gcc/testsuite/g++.dg/init/explicit2.C
+++ b/gcc/testsuite/g++.dg/init/explicit2.C
@@ -1,8 +1,9 @@
 // PR c++/60417
+// { dg-options -pedantic }
 
 struct A { explicit A(int = 0); };
 
 int main()
 {
-  A a[1] = { };
+  A a[1] = { };			// { dg-warning "explicit" "" { target c++11 } }
 }

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]