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