https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96645
--- Comment #8 from Jason Merrill <jason at gcc dot gnu.org> --- (In reply to Patrick Palka from comment #7) > > Maybe the note in [class.mem.general]/7 is relevant: > > A complete-class context of a nested class is also a complete-class > context of any enclosing class, if the nested class is defined within the > member-specification of the enclosing class. > > We can't determine if A is constructible until we parse the initializer for > DataWithStruct::A::number. And according to the above, we can't parse this > initializer until DataWithStruct is complete. Right. > Looks like PR81359 is closely related. Yes. Perhaps PR81359 or PR88368, or both, were wrongly resolved. We cannot correctly resolve is_nothrow_constructible<A> until we've parsed the DMI. Given that, we have three options: 1) Conservatively say no. 2) Optimistically guess yes. 3) Non-SFINAE error. PR81359 changed our behavior from 3 to 1. #2 seems the clear worst choice, as it can lead to things unexpectedly throwing. #3 means people have to jump through hoops to make their code compile. #1 means silently pessimized code for anything that relies on std::is_nothrow_constructible<A> in the rest of the translation, since the value is permanently cached. If we choose #1, we have another choice for is_constructible<A>: should it be true (giving A() a throwing exception-spec) or false? PR88368 changed our choice from true to false. Any opinions on what our behavior should be? Should there be an LWG issue? This is related to CWG1890, and the general issue that we don't currently parse on demand like we do instantiate on demand for templates. So one workaround is to wrap DataWith* in a dummy template: #include <type_traits> using namespace std; template <class Dummy = void> struct DataWithStruct { struct A { int number = 5; }; /*typename*/ is_nothrow_constructible<A>::type t = true_type{}; }; DataWithStruct<> d; // OK or move the nested class out so we can finish parsing it before the use: #include <variant> void testVarStruct() { struct A { int number = 5; }; struct B { bool flag = false; }; struct DataWithStruct { using Member = std::variant<A, B>; Member data; }; auto d = DataWithStruct{}; }