DR 1518 DR 1630 PR c++/54835 PR c++/60417
authorJason Merrill <jason@redhat.com>
Sat, 24 Oct 2015 02:58:10 +0000 (22:58 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Sat, 24 Oct 2015 02:58:10 +0000 (22:58 -0400)
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.

From-SVN: r229283

gcc/cp/ChangeLog
gcc/cp/call.c
gcc/testsuite/g++.dg/cpp0x/explicit10.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/initlist40.C
gcc/testsuite/g++.dg/init/explicit1.C
gcc/testsuite/g++.dg/init/explicit2.C

index e3dbe6b7090eb1aefcd1b634c9e4be97f360df4c..5434dd27795b99770c79e59c3fefc7daaa81167f 100644 (file)
@@ -1,5 +1,12 @@
 2015-10-23  Jason Merrill  <jason@redhat.com>
 
+       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.
+
        PR c++/67813
        * constexpr.c (cxx_eval_store_expression): Always use *valp if
        set.
index 5b57dc97b54b945fc33dc3ac47936d74279ddb27..1223dcd3b1448640859c51f807abcab9bcbe274b 100644 (file)
@@ -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 (file)
index 0000000..f31f856
--- /dev/null
@@ -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" }
+}
index de2e19d3adcf7e157ca8cc52b25f7971a58d01a6..6e6a11a64541b1f5393365790e16a74719c5d028 100644 (file)
@@ -8,6 +8,6 @@ struct A
 
 int main()
 {
-  A a1 = { };
+  A a1 = { };                  // { dg-error "explicit" }
   A a2 = { 24 };               // { dg-error "explicit" }
 }
index f376df2364830f60df67c7e6d666ee1267b67893..328e867319800049e45dae4657393dc15d2bbb58 100644 (file)
@@ -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 } }
 }
index d1dbb39fc612043968661ba8c13a66b5585ae44d..604426ae6d214a9275124aea81e8e7ec32076365 100644 (file)
@@ -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 } }
 }