The code: ``` struct S { std::size_t len{s.size()}; std::string s{"A rather long string"}; }; ``` warns on clang, but not on GCC. https://compiler-explorer.com/z/5qf3WbdY7 The equivalent code using a constructor _does_ warn on both compilers: ``` struct S { std::size_t len; std::string s; S() : s{"A rather long string"}, len{s.size()} {} }; ``` ( https://compiler-explorer.com/z/Wov4Tx93v )
We diagnose this at -O1 now but not -O0, -O2 or -O3. We rely on the late uninit diagnostic pass here but that's faced with optimized code. Interestingly an older version of libstdc++ warned at -O2 and -O3 as well.
In fact with trunk we diagnose this properly with -std=c++17 but not -std=c++20. With -std=c++20 we see <bb 2> [local count: 1073741824]: _35 = operator new (21); __builtin_memcpy (_35, "A rather long string", 20); MEM[(char_type &)_35 + 20] = 0; operator delete (_35, 21); s ={v} {CLOBBER}; s ={v} {CLOBBER(eol)}; return 0; at the point we would be supposed to diagnose the init but you can see that 's' was elided. One issue is probably that we elide the standalone S::S() during IPA (because we inline it) and thus fail to run the late diagnostic passes on its optimized body: void S::S (struct S * const this) { struct allocator D.46788; struct string * _1; struct string * _2; long unsigned int _8; <bb 2> [local count: 1073741824]: _8 = MEM[(const struct basic_string *)this_3(D) + 8B]._M_string_length; *this_3(D).len = _8; _1 = &this_3(D)->s; std::__cxx11::basic_string<char>::basic_string<> (_1, "A rather long string", &D.46788); D.46788 ={v} {CLOBBER(eol)}; return; of course we lack a start-of-live CLOBBER of *this here (I think I've seen this before), so we'd fail to diagnose this body as well.
(In reply to Richard Biener from comment #2) > In fact with trunk we diagnose this properly with -std=c++17 but not > -std=c++20. So it's probably because c++17 uses extern template for std::string and C++20 doesn't. This could probably be done in the front end. The rule about init order is purely lexical, and so if the initializer odr-uses another member declared later, we should warn.
The FE already has to do lookup for s in that initializer, so it knows that another member was found.