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.voutilai...@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.


commit 9adecc7c621fabfcdf91e3f92cf15bd2adc9d2a5
Author: Jason Merrill <ja...@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" }

Reply via email to