diff mbox

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

Message ID 563119B7.2060603@redhat.com
State New
Headers show

Commit Message

Jason Merrill Oct. 28, 2015, 6:53 p.m. UTC
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.
diff mbox

Patch

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