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