public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* C++ PATCH for DR 1518 (c++/54835, c++/60417)
@ 2015-10-25 20:48 Ville Voutilainen
  2015-10-26  1:13 ` Ville Voutilainen
  0 siblings, 1 reply; 5+ messages in thread
From: Ville Voutilainen @ 2015-10-25 20:48 UTC (permalink / raw)
  To: Jason Merrill, gcc-patches

It seems to me that there's a discrepancy in handling explicit
default constructors. Based on my tests, this works:

struct X {explicit X() {}};

void f(X) {}

int main()
{
    f({});
}

However, if the explicit constructor is defaulted, gcc accepts the code:

struct X {explicit X() = default;};

void f(X) {}

int main()
{
    f({});
}

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: C++ PATCH for DR 1518 (c++/54835, c++/60417)
  2015-10-25 20:48 C++ PATCH for DR 1518 (c++/54835, c++/60417) Ville Voutilainen
@ 2015-10-26  1:13 ` Ville Voutilainen
  2015-10-26 14:51   ` Jason Merrill
  0 siblings, 1 reply; 5+ messages in thread
From: Ville Voutilainen @ 2015-10-26  1:13 UTC (permalink / raw)
  To: Jason Merrill, gcc-patches

On 25 October 2015 at 22:15, Ville Voutilainen
<ville.voutilainen@gmail.com> wrote:
> It seems to me that there's a discrepancy in handling explicit
> default constructors. Based on my tests, this works:
>
> struct X {explicit X() {}};
>
> void f(X) {}
>
> int main()
> {
>     f({});
> }
>
> However, if the explicit constructor is defaulted, gcc accepts the code:
>
> struct X {explicit X() = default;};
>
> void f(X) {}
>
> int main()
> {
>     f({});
> }

And to clarify, I'd expect both of those snippets to be rejected, but only the
former is.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: C++ PATCH for DR 1518 (c++/54835, c++/60417)
  2015-10-26  1:13 ` Ville Voutilainen
@ 2015-10-26 14:51   ` Jason Merrill
  2015-10-28 19:09     ` Jason Merrill
  0 siblings, 1 reply; 5+ messages in thread
From: Jason Merrill @ 2015-10-26 14:51 UTC (permalink / raw)
  To: Ville Voutilainen, gcc-patches

On 10/25/2015 09:04 PM, Ville Voutilainen wrote:
> On 25 October 2015 at 22:15, Ville Voutilainen
> <ville.voutilainen@gmail.com> wrote:
>> It seems to me that there's a discrepancy in handling explicit
>> default constructors. Based on my tests, this works:
>>
>> struct X {explicit X() {}};
>>
>> void f(X) {}
>>
>> int main()
>> {
>>      f({});
>> }
>>
>> However, if the explicit constructor is defaulted, gcc accepts the code:
>>
>> struct X {explicit X() = default;};
>>
>> void f(X) {}
>>
>> int main()
>> {
>>      f({});
>> }
>
> And to clarify, I'd expect both of those snippets to be rejected, but only the
> former is.

The latter is accepted because the second X is an aggregate, and the 
aggregate initialization bullet comes before value-initialization in 8.5.4.

Jason

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: C++ PATCH for DR 1518 (c++/54835, c++/60417)
  2015-10-26 14:51   ` Jason Merrill
@ 2015-10-28 19:09     ` Jason Merrill
  0 siblings, 0 replies; 5+ messages in thread
From: Jason Merrill @ 2015-10-28 19:09 UTC (permalink / raw)
  To: Ville Voutilainen, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1024 bytes --]

On 10/26/2015 10:47 AM, Jason Merrill wrote:
> On 10/25/2015 09:04 PM, Ville Voutilainen wrote:
>> On 25 October 2015 at 22:15, Ville Voutilainen
>> <ville.voutilainen@gmail.com> wrote:
>>> It seems to me that there's a discrepancy in handling explicit
>>> default constructors. Based on my tests, this works:
>>>
>>> struct X {explicit X() {}};
>>>
>>> void f(X) {}
>>>
>>> int main()
>>> {
>>>      f({});
>>> }
>>>
>>> However, if the explicit constructor is defaulted, gcc accepts the code:
>>>
>>> struct X {explicit X() = default;};
>>>
>>> void f(X) {}
>>>
>>> int main()
>>> {
>>>      f({});
>>> }
>>
>> And to clarify, I'd expect both of those snippets to be rejected, but
>> only the
>> former is.
>
> The latter is accepted because the second X is an aggregate, and the
> aggregate initialization bullet comes before value-initialization in 8.5.4.

Further discussion on -core leads me to try changing X to be 
non-aggregate because of the explicit constructor.

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



[-- Attachment #2: dr1518-2.patch --]
[-- Type: text/x-patch, Size: 3154 bytes --]

commit 9adecc7c621fabfcdf91e3f92cf15bd2adc9d2a5
Author: Jason Merrill <jason@redhat.com>
Date:   Mon Oct 26 17:31:08 2015 -0400

    	DR 1518
    	* class.c (type_has_user_provided_or_explicit_constructor): New.
    	(check_bases_and_members): Use it.
    	* cp-tree.h: Declare it.

diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 685b7b3..692bc44 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -5150,6 +5150,33 @@ type_has_user_provided_constructor (tree t)
   return false;
 }
 
+/* Returns true iff class T has a user-provided constructor.  */
+
+bool
+type_has_user_provided_or_explicit_constructor (tree t)
+{
+  tree fns;
+
+  if (!CLASS_TYPE_P (t))
+    return false;
+
+  if (!TYPE_HAS_USER_CONSTRUCTOR (t))
+    return false;
+
+  /* This can happen in error cases; avoid crashing.  */
+  if (!CLASSTYPE_METHOD_VEC (t))
+    return false;
+
+  for (fns = CLASSTYPE_CONSTRUCTORS (t); fns; fns = OVL_NEXT (fns))
+    {
+      tree fn = OVL_CURRENT (fns);
+      if (user_provided_p (fn) || DECL_NONCONVERTING_P (fn))
+	return true;
+    }
+
+  return false;
+}
+
 /* Returns true iff class T has a non-user-provided (i.e. implicitly
    declared or explicitly defaulted in the class body) default
    constructor.  */
@@ -5735,7 +5762,8 @@ check_bases_and_members (tree t)
      Again, other conditions for being an aggregate are checked
      elsewhere.  */
   CLASSTYPE_NON_AGGREGATE (t)
-    |= (type_has_user_provided_constructor (t) || TYPE_POLYMORPHIC_P (t));
+    |= (type_has_user_provided_or_explicit_constructor (t)
+	|| TYPE_POLYMORPHIC_P (t));
   /* This is the C++98/03 definition of POD; it changed in C++0x, but we
      retain the old definition internally for ABI reasons.  */
   CLASSTYPE_NON_LAYOUT_POD_P (t)
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index af2ba64..acdd71c 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5574,6 +5574,7 @@ extern bool type_has_user_nondefault_constructor (tree);
 extern tree in_class_defaulted_default_constructor (tree);
 extern bool user_provided_p			(tree);
 extern bool type_has_user_provided_constructor  (tree);
+extern bool type_has_user_provided_or_explicit_constructor  (tree);
 extern bool type_has_non_user_provided_default_constructor (tree);
 extern bool vbase_has_user_provided_move_assign (tree);
 extern tree default_init_uninitialized_part (tree);
diff --git a/gcc/testsuite/g++.dg/cpp0x/explicit10.C b/gcc/testsuite/g++.dg/cpp0x/explicit10.C
index f31f856..f9f8925 100644
--- a/gcc/testsuite/g++.dg/cpp0x/explicit10.C
+++ b/gcc/testsuite/g++.dg/cpp0x/explicit10.C
@@ -28,12 +28,12 @@ template<typename T> void g() {
 
 int main()
 {
-  f<A>();			// { dg-bogus "required from here" }
+  f<A>();			// { dg-message "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<A>();			// { dg-message "required from here" }
   g<B>();			// { dg-message "required from here" }
   g<C>();			// { dg-message "required from here" }
   g<D>();			// { dg-message "required from here" }

^ permalink raw reply	[flat|nested] 5+ messages in thread

* C++ PATCH for DR 1518 (c++/54835, c++/60417)
@ 2015-10-24  3:14 Jason Merrill
  0 siblings, 0 replies; 5+ messages in thread
From: Jason Merrill @ 2015-10-24  3:14 UTC (permalink / raw)
  To: gcc-patches List

[-- Attachment #1: Type: text/plain, Size: 577 bytes --]

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.

[-- Attachment #2: dr1518.patch --]
[-- Type: text/x-patch, Size: 4891 bytes --]

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

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2015-10-28 18:53 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-10-25 20:48 C++ PATCH for DR 1518 (c++/54835, c++/60417) Ville Voutilainen
2015-10-26  1:13 ` Ville Voutilainen
2015-10-26 14:51   ` Jason Merrill
2015-10-28 19:09     ` Jason Merrill
  -- strict thread matches above, loose matches on Subject: below --
2015-10-24  3:14 Jason Merrill

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).