public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug c++/88165] error: default member initializer for 'A::B::m' required before the end of its enclosing class
[not found] <bug-88165-4@http.gcc.gnu.org/bugzilla/>
@ 2021-12-14 5:07 ` pinskia at gcc dot gnu.org
2021-12-14 5:16 ` pinskia at gcc dot gnu.org
` (8 subsequent siblings)
9 siblings, 0 replies; 10+ messages in thread
From: pinskia at gcc dot gnu.org @ 2021-12-14 5:07 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88165
--- Comment #5 from Andrew Pinski <pinskia at gcc dot gnu.org> ---
Hmm, clang also rejects this ...
^ permalink raw reply [flat|nested] 10+ messages in thread
* [Bug c++/88165] error: default member initializer for 'A::B::m' required before the end of its enclosing class
[not found] <bug-88165-4@http.gcc.gnu.org/bugzilla/>
2021-12-14 5:07 ` [Bug c++/88165] error: default member initializer for 'A::B::m' required before the end of its enclosing class pinskia at gcc dot gnu.org
@ 2021-12-14 5:16 ` pinskia at gcc dot gnu.org
2022-01-13 6:55 ` fchelnokov at gmail dot com
` (7 subsequent siblings)
9 siblings, 0 replies; 10+ messages in thread
From: pinskia at gcc dot gnu.org @ 2021-12-14 5:16 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88165
--- Comment #6 from Andrew Pinski <pinskia at gcc dot gnu.org> ---
DR 1352 might be related.
^ permalink raw reply [flat|nested] 10+ messages in thread
* [Bug c++/88165] error: default member initializer for 'A::B::m' required before the end of its enclosing class
[not found] <bug-88165-4@http.gcc.gnu.org/bugzilla/>
2021-12-14 5:07 ` [Bug c++/88165] error: default member initializer for 'A::B::m' required before the end of its enclosing class pinskia at gcc dot gnu.org
2021-12-14 5:16 ` pinskia at gcc dot gnu.org
@ 2022-01-13 6:55 ` fchelnokov at gmail dot com
2022-04-22 8:18 ` jcl at nvidia dot com
` (6 subsequent siblings)
9 siblings, 0 replies; 10+ messages in thread
From: fchelnokov at gmail dot com @ 2022-01-13 6:55 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88165
--- Comment #7 from Fedor Chelnokov <fchelnokov at gmail dot com> ---
This struct definition:
```
struct A {
struct B {
int i = 0;
B() {}
};
A(B = {});
};
```
is accepted by GCC, but another one ({} replaced with = default) is not:
```
struct C {
struct D {
int i = 0;
D() = default;
};
C(D = {});
};
```
Demo: https://gcc.godbolt.org/z/WTPdTn1Yf
Could you please explain why? I though that both must be same accepted or same
rejected.
^ permalink raw reply [flat|nested] 10+ messages in thread
* [Bug c++/88165] error: default member initializer for 'A::B::m' required before the end of its enclosing class
[not found] <bug-88165-4@http.gcc.gnu.org/bugzilla/>
` (2 preceding siblings ...)
2022-01-13 6:55 ` fchelnokov at gmail dot com
@ 2022-04-22 8:18 ` jcl at nvidia dot com
2022-04-22 8:26 ` redi at gcc dot gnu.org
` (5 subsequent siblings)
9 siblings, 0 replies; 10+ messages in thread
From: jcl at nvidia dot com @ 2022-04-22 8:18 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88165
JC Liang <jcl at nvidia dot com> changed:
What |Removed |Added
----------------------------------------------------------------------------
CC| |jcl at nvidia dot com
--- Comment #8 from JC Liang <jcl at nvidia dot com> ---
Also suffering from this issue, it's really annoying and diverged from msvc...
^ permalink raw reply [flat|nested] 10+ messages in thread
* [Bug c++/88165] error: default member initializer for 'A::B::m' required before the end of its enclosing class
[not found] <bug-88165-4@http.gcc.gnu.org/bugzilla/>
` (3 preceding siblings ...)
2022-04-22 8:18 ` jcl at nvidia dot com
@ 2022-04-22 8:26 ` redi at gcc dot gnu.org
2022-04-22 8:35 ` redi at gcc dot gnu.org
` (4 subsequent siblings)
9 siblings, 0 replies; 10+ messages in thread
From: redi at gcc dot gnu.org @ 2022-04-22 8:26 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88165
Jonathan Wakely <redi at gcc dot gnu.org> changed:
What |Removed |Added
----------------------------------------------------------------------------
Status|NEW |RESOLVED
Resolution|--- |DUPLICATE
--- Comment #9 from Jonathan Wakely <redi at gcc dot gnu.org> ---
This is PR 96645 and the examples on comment 1 and comment 7 compile with GCC
trunk. The example in comment 0 doesn't compile still, see PR 96645 for
details.
*** This bug has been marked as a duplicate of bug 96645 ***
^ permalink raw reply [flat|nested] 10+ messages in thread
* [Bug c++/88165] error: default member initializer for 'A::B::m' required before the end of its enclosing class
[not found] <bug-88165-4@http.gcc.gnu.org/bugzilla/>
` (4 preceding siblings ...)
2022-04-22 8:26 ` redi at gcc dot gnu.org
@ 2022-04-22 8:35 ` redi at gcc dot gnu.org
2022-04-22 8:44 ` fchelnokov at gmail dot com
` (3 subsequent siblings)
9 siblings, 0 replies; 10+ messages in thread
From: redi at gcc dot gnu.org @ 2022-04-22 8:35 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88165
--- Comment #10 from Jonathan Wakely <redi at gcc dot gnu.org> ---
(In reply to Fedor Chelnokov from comment #7)
> This struct definition:
> ```
> struct A {
> struct B {
> int i = 0;
> B() {}
This declares default constructor, meaning that the type is default
constructible. Period.
By declaring B(); you assert that B is default constructible.
> };
> A(B = {});
This is valid, because the user-provided default constructor for B is all the
compiler needs to see to know that B={} is valid.
> };
> ```
> is accepted by GCC, but another one ({} replaced with = default) is not:
> ```
> struct C {
> struct D {
> int i = 0;
> D() = default;
This declares a default constructor that might be defined implicitly by the
compiler, **or** it might get deleted if the member definitions of D would make
the implicit default constructor ill-formed. This is obviously very different
from the case where you declare B(); There is no assertion that D is default
constructible, the compiler has to deduce whether or not that's true. That
depends on the default member initializer for D::i. The initializer (which is
just '0' here) is a "complete class context" which means it is not processed
until the class D is complete (this allows you to use other members, or e.g.
sizeof(D) as the initializer).
A nested class like C::D is not complete until its enclosing class is complete.
This means the initializer for C::D::i is compiled after C is complete. This
means whether C::D is default constructible is not known until C is complete.
> };
> C(D = {});
This requires checking whether C::D is default constructible, but we are still
in the body of C, so C is not complete, which means C::D is not complete, which
means we don't know if C::D is default constructible.
> };
> ```
> Demo: https://gcc.godbolt.org/z/WTPdTn1Yf
>
> Could you please explain why? I though that both must be same accepted or
> same rejected.
I hope the explanation above helps.
GCC trunk now has a tweak to parse simple initializers like 0 immediately,
instead of waiting for the class to be complete (because 0 doesn't depend on
anything in the class). But for the original example in comment 0 the
initializer std::numeric_limits<double>::max(); has to perform name lookup and
overload resolution, and so is still delayed until the class is complete.
^ permalink raw reply [flat|nested] 10+ messages in thread
* [Bug c++/88165] error: default member initializer for 'A::B::m' required before the end of its enclosing class
[not found] <bug-88165-4@http.gcc.gnu.org/bugzilla/>
` (5 preceding siblings ...)
2022-04-22 8:35 ` redi at gcc dot gnu.org
@ 2022-04-22 8:44 ` fchelnokov at gmail dot com
2022-04-22 8:55 ` jcl at nvidia dot com
` (2 subsequent siblings)
9 siblings, 0 replies; 10+ messages in thread
From: fchelnokov at gmail dot com @ 2022-04-22 8:44 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88165
--- Comment #11 from Fedor Chelnokov <fchelnokov at gmail dot com> ---
Thanks a lot for the explanation!
^ permalink raw reply [flat|nested] 10+ messages in thread
* [Bug c++/88165] error: default member initializer for 'A::B::m' required before the end of its enclosing class
[not found] <bug-88165-4@http.gcc.gnu.org/bugzilla/>
` (6 preceding siblings ...)
2022-04-22 8:44 ` fchelnokov at gmail dot com
@ 2022-04-22 8:55 ` jcl at nvidia dot com
2022-04-22 10:29 ` andysem at mail dot ru
2022-04-22 10:42 ` redi at gcc dot gnu.org
9 siblings, 0 replies; 10+ messages in thread
From: jcl at nvidia dot com @ 2022-04-22 8:55 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88165
--- Comment #12 from JC Liang <jcl at nvidia dot com> ---
(In reply to Jonathan Wakely from comment #10)
> (In reply to Fedor Chelnokov from comment #7)
> > This struct definition:
> > ```
> > struct A {
> > struct B {
> > int i = 0;
> > B() {}
>
> This declares default constructor, meaning that the type is default
> constructible. Period.
>
> By declaring B(); you assert that B is default constructible.
>
> > };
> > A(B = {});
>
> This is valid, because the user-provided default constructor for B is all
> the compiler needs to see to know that B={} is valid.
>
> > };
> > ```
> > is accepted by GCC, but another one ({} replaced with = default) is not:
> > ```
> > struct C {
> > struct D {
> > int i = 0;
> > D() = default;
>
> This declares a default constructor that might be defined implicitly by the
> compiler, **or** it might get deleted if the member definitions of D would
> make the implicit default constructor ill-formed. This is obviously very
> different from the case where you declare B(); There is no assertion that D
> is default constructible, the compiler has to deduce whether or not that's
> true. That depends on the default member initializer for D::i. The
> initializer (which is just '0' here) is a "complete class context" which
> means it is not processed until the class D is complete (this allows you to
> use other members, or e.g. sizeof(D) as the initializer).
>
> A nested class like C::D is not complete until its enclosing class is
> complete. This means the initializer for C::D::i is compiled after C is
> complete. This means whether C::D is default constructible is not known
> until C is complete.
>
>
> > };
> > C(D = {});
>
> This requires checking whether C::D is default constructible, but we are
> still in the body of C, so C is not complete, which means C::D is not
> complete, which means we don't know if C::D is default constructible.
>
> > };
> > ```
> > Demo: https://gcc.godbolt.org/z/WTPdTn1Yf
> >
> > Could you please explain why? I though that both must be same accepted or
> > same rejected.
>
> I hope the explanation above helps.
>
> GCC trunk now has a tweak to parse simple initializers like 0 immediately,
> instead of waiting for the class to be complete (because 0 doesn't depend on
> anything in the class). But for the original example in comment 0 the
> initializer std::numeric_limits<double>::max(); has to perform name lookup
> and overload resolution, and so is still delayed until the class is complete.
This is an excellent explanation, hope it benefits everyone who got here from
Google search.
^ permalink raw reply [flat|nested] 10+ messages in thread
* [Bug c++/88165] error: default member initializer for 'A::B::m' required before the end of its enclosing class
[not found] <bug-88165-4@http.gcc.gnu.org/bugzilla/>
` (7 preceding siblings ...)
2022-04-22 8:55 ` jcl at nvidia dot com
@ 2022-04-22 10:29 ` andysem at mail dot ru
2022-04-22 10:42 ` redi at gcc dot gnu.org
9 siblings, 0 replies; 10+ messages in thread
From: andysem at mail dot ru @ 2022-04-22 10:29 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88165
--- Comment #13 from andysem at mail dot ru ---
(In reply to Jonathan Wakely from comment #10)
> (In reply to Fedor Chelnokov from comment #7)
> > This struct definition:
> > ```
> > struct A {
> > struct B {
> > int i = 0;
> > B() {}
>
> This declares default constructor, meaning that the type is default
> constructible. Period.
>
> By declaring B(); you assert that B is default constructible.
>
> > };
> > A(B = {});
>
> This is valid, because the user-provided default constructor for B is all
> the compiler needs to see to know that B={} is valid.
>
> > };
> > ```
> > is accepted by GCC, but another one ({} replaced with = default) is not:
> > ```
> > struct C {
> > struct D {
> > int i = 0;
> > D() = default;
>
> This declares a default constructor that might be defined implicitly by the
> compiler, **or** it might get deleted if the member definitions of D would
> make the implicit default constructor ill-formed. This is obviously very
> different from the case where you declare B(); There is no assertion that D
> is default constructible, the compiler has to deduce whether or not that's
> true. That depends on the default member initializer for D::i. The
> initializer (which is just '0' here) is a "complete class context" which
> means it is not processed until the class D is complete (this allows you to
> use other members, or e.g. sizeof(D) as the initializer).
>
> A nested class like C::D is not complete until its enclosing class is
> complete. This means the initializer for C::D::i is compiled after C is
> complete. This means whether C::D is default constructible is not known
> until C is complete.
>
>
> > };
> > C(D = {});
>
> This requires checking whether C::D is default constructible, but we are
> still in the body of C, so C is not complete, which means C::D is not
> complete, which means we don't know if C::D is default constructible.
Does it? I thought the default arguments were only evaluated at the point where
they are actually used, i.e. in this case - when `C` constructor is invoked
with no arguments.
> > };
> > ```
> > Demo: https://gcc.godbolt.org/z/WTPdTn1Yf
> >
> > Could you please explain why? I though that both must be same accepted or
> > same rejected.
>
> I hope the explanation above helps.
Thank you for the explanation.
If this is how the standard specifies compiler behavior, I wonder if this
should be considered as a defect (DR). There is nothing in
`std::numeric_limits<double>::max()` that depends on the definition of `C`, so
there is no reason to prevent it from compiling.
^ permalink raw reply [flat|nested] 10+ messages in thread
* [Bug c++/88165] error: default member initializer for 'A::B::m' required before the end of its enclosing class
[not found] <bug-88165-4@http.gcc.gnu.org/bugzilla/>
` (8 preceding siblings ...)
2022-04-22 10:29 ` andysem at mail dot ru
@ 2022-04-22 10:42 ` redi at gcc dot gnu.org
9 siblings, 0 replies; 10+ messages in thread
From: redi at gcc dot gnu.org @ 2022-04-22 10:42 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88165
--- Comment #14 from Jonathan Wakely <redi at gcc dot gnu.org> ---
(In reply to andysem from comment #13)
> (In reply to Jonathan Wakely from comment #10)
> > > C(D = {});
> >
> > This requires checking whether C::D is default constructible, but we are
> > still in the body of C, so C is not complete, which means C::D is not
> > complete, which means we don't know if C::D is default constructible.
>
> Does it? I thought the default arguments were only evaluated at the point
> where they are actually used, i.e. in this case - when `C` constructor is
> invoked with no arguments.
It's surprising, I agree. Whether the default argument is valid determines
whether this constructor is considered a default constructor, which determines
whether the compiler needs to implicitly declare a separate default constructor
I think that's why the default argument is needed earlier than you expect.
> If this is how the standard specifies compiler behavior, I wonder if this
> should be considered as a defect (DR).
I closed this as a dup of PR 96645 which has a DR number right there in the
title. Like I said, see there for more details.
> There is nothing in
> `std::numeric_limits<double>::max()` that depends on the definition of `C`,
> so there is no reason to prevent it from compiling.
Are you sure? What if C::std is declared? Then the initializer means something
very different. Again, see PR 96645 for further discussion of when the
initializer can be compiled (and a possible patch to do it differently).
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2022-04-22 10:42 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
[not found] <bug-88165-4@http.gcc.gnu.org/bugzilla/>
2021-12-14 5:07 ` [Bug c++/88165] error: default member initializer for 'A::B::m' required before the end of its enclosing class pinskia at gcc dot gnu.org
2021-12-14 5:16 ` pinskia at gcc dot gnu.org
2022-01-13 6:55 ` fchelnokov at gmail dot com
2022-04-22 8:18 ` jcl at nvidia dot com
2022-04-22 8:26 ` redi at gcc dot gnu.org
2022-04-22 8:35 ` redi at gcc dot gnu.org
2022-04-22 8:44 ` fchelnokov at gmail dot com
2022-04-22 8:55 ` jcl at nvidia dot com
2022-04-22 10:29 ` andysem at mail dot ru
2022-04-22 10:42 ` redi at gcc dot gnu.org
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).