From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 48) id 904B43856DC5; Fri, 22 Apr 2022 08:55:15 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 904B43856DC5 From: "jcl at nvidia dot com" To: gcc-bugs@gcc.gnu.org Subject: [Bug c++/88165] error: default member initializer for 'A::B::m' required before the end of its enclosing class Date: Fri, 22 Apr 2022 08:55:15 +0000 X-Bugzilla-Reason: CC X-Bugzilla-Type: changed X-Bugzilla-Watch-Reason: None X-Bugzilla-Product: gcc X-Bugzilla-Component: c++ X-Bugzilla-Version: 8.2.0 X-Bugzilla-Keywords: rejects-valid X-Bugzilla-Severity: normal X-Bugzilla-Who: jcl at nvidia dot com X-Bugzilla-Status: RESOLVED X-Bugzilla-Resolution: DUPLICATE X-Bugzilla-Priority: P3 X-Bugzilla-Assigned-To: unassigned at gcc dot gnu.org X-Bugzilla-Target-Milestone: --- X-Bugzilla-Flags: X-Bugzilla-Changed-Fields: Message-ID: In-Reply-To: References: Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-Bugzilla-URL: http://gcc.gnu.org/bugzilla/ Auto-Submitted: auto-generated MIME-Version: 1.0 X-BeenThere: gcc-bugs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-bugs mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 22 Apr 2022 08:55:15 -0000 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=3D88165 --- Comment #12 from JC Liang --- (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 =3D 0; > > B() {} >=20 > This declares default constructor, meaning that the type is default > constructible. Period. >=20 > By declaring B(); you assert that B is default constructible. >=20 > > }; > > A(B =3D {}); >=20 > This is valid, because the user-provided default constructor for B is all > the compiler needs to see to know that B=3D{} is valid. >=20 > > }; > > ``` > > is accepted by GCC, but another one ({} replaced with =3D default) is n= ot: > > ``` > > struct C { > > struct D { > > int i =3D 0; > > D() =3D default; >=20 > This declares a default constructor that might be defined implicitly by t= he > 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). >=20 > 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. >=20 >=20 > > }; > > C(D =3D {}); >=20 > 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. >=20 > > }; > > ``` > > Demo: https://gcc.godbolt.org/z/WTPdTn1Yf > >=20 > > Could you please explain why? I though that both must be same accepted = or > > same rejected. >=20 > I hope the explanation above helps. >=20 > 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::max(); has to perform name lookup > and overload resolution, and so is still delayed until the class is compl= ete. This is an excellent explanation, hope it benefits everyone who got here fr= om Google search.=