* 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).