From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 48) id 96E2B3856DF7; Fri, 22 Apr 2022 08:35:10 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 96E2B3856DF7 From: "redi at gcc dot gnu.org" 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:35:10 +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: redi at gcc dot gnu.org 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:35:10 -0000 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=3D88165 --- Comment #10 from Jonathan Wakely --- (In reply to Fedor Chelnokov from comment #7) > This struct definition: > ``` > struct A { > struct B { > int i =3D 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 =3D {}); This is valid, because the user-provided default constructor for B is all t= he compiler needs to see to know that B=3D{} is valid. > }; > ``` > is accepted by GCC, but another one ({} replaced with =3D default) is not: > ``` > struct C { > struct D { > int i =3D 0; > D() =3D 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 differe= nt 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 compl= ete. 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 complet= e. > }; > C(D =3D {}); This requires checking whether C::D is default constructible, but we are st= ill in the body of C, so C is not complete, which means C::D is not complete, w= hich means we don't know if C::D is default constructible. > }; > ``` > Demo: https://gcc.godbolt.org/z/WTPdTn1Yf >=20 > 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::max(); has to perform name lookup = and overload resolution, and so is still delayed until the class is complete.=