https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114076
--- Comment #3 from Benjamin Buch <benni.buch at gmail dot com> --- I [created an overview](https://stackoverflow.com/a/78101462/4821621) with all cases that currently work on StackOverflow. I think that all these cases should be valid. For a properly formated version with links to Compiler Explorer please use my stackoverflow post. Here is the relevant part GitHub user [frederick-vs-ja](https://github.com/microsoft/STL/issues/4417#issuecomment-1960976417) has reduced the problem in the MS STL Bug Report to a minimal example. ```cpp template <typename T> struct Holder { Holder() = default; constexpr ~Holder() { static_assert(sizeof(T) || true); } }; struct Incomplete; struct Class { Class(); ~Class(); Holder<Incomplete> v{}; }; int main() { [[maybe_unused]] Class v; } ``` I have extended this example with some variants and tested the compilers with them. Syntactically, there are 7 ways to call the default constructor of Holder: - `Holder<Incomplete> a;` default-initialization - `Holder<Incomplete> b{};` direct-list-initialization - `Holder<Incomplete> c = {};` copy-list-initialization - `Holder<Incomplete> d = Holder<Incomplete>();` copy-direct-initialization - `Holder<Incomplete> e = {Holder<Incomplete>()};` copy-list-initialization - `Holder<Incomplete> f = Holder<Incomplete>{};` copy-direct-initialization - `Holder<Incomplete> g = {Holder<Incomplete>{}};` copy-list-initialization Then we can change `Holder` in two ways. (Thanks to Github user [fsb4000](https://github.com/microsoft/STL/issues/4417#issuecomment-1959604006) in the MS STL bug report!) First we can remove the explicit constructor definition, so the compiler generates this constructor implicitly: ```cpp template <typename T> struct Holder { constexpr ~Holder() { static_assert(sizeof(T) || true); } }; ``` Second we can remove the constexpr from the destructor: ```cpp template <typename T> struct Holder { Holder() = default; ~Holder() { static_assert(sizeof(T) || true); } }; ``` A third relevant change can be applied to `B`. (Thanks to [Jiang An](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114076#c1) in the GCC bug report!) We can make it a template, by giving it a default template argument: ```cpp template <typename = void> struct Class { Class(); ~Class(); Holder<Incomplete> v{}; }; ``` So we have 8 code examples with 7 kinds of initialization. I created a table with what works with which compiler. I tested with MSVC 19.38, GCC 13.2 and clang 17.0.1. Each table cell links to the live code, where the trunk versions of the compilers are used additionally. - Case 1: *Implicit `Holder` ctor*, *non-`constexpr` dtor*, *non-template `Class`* - Case 2: Explicit `Holder` ctor, *non-`constexpr` dtor*, *non-template `Class`* - Case 3: *Implicit `Holder` ctor*, `constexpr` dtor, *non-template `Class`* - Case 4: Explicit `Holder` ctor, `constexpr` dtor, *non-template `Class`* - Case 5: *Implicit `Holder` ctor*, *non-`constexpr` dtor*, template `Class` - Case 6: Explicit `Holder` ctor, *non-`constexpr` dtor*, template `Class` - Case 7: *Implicit `Holder` ctor*, `constexpr` dtor, template `Class` - Case 8: Explicit `Holder` ctor, `constexpr` dtor, template `Class` The order is: ✅/❌ MSVC ; ✅/❌ GCC ; ✅/❌ clang ||Case a|Case b|Case c|Case d|Case e|Case f|Case g| |-|-|-|-|-|-|-|-| |Case 1:|✅✅✅|✅✅✅|✅✅✅|✅❌✅|✅❌✅|✅❌✅|✅❌✅| |Case 2:|✅✅✅|✅✅✅|✅❌✅|✅❌✅|✅❌✅|✅❌✅|✅❌✅| |Case 3:|✅✅✅|❌✅✅|❌✅✅|❌❌❌|❌❌❌|❌❌❌|❌❌❌| |Case 4:|✅✅✅|❌✅✅|❌❌✅|❌❌❌|❌❌❌|❌❌❌|❌❌❌| |Case 5:|✅✅✅|✅✅✅|✅✅✅|✅✅✅|✅✅✅|✅✅✅|✅✅✅| |Case 6:|✅✅✅|✅✅✅|✅✅✅|✅✅✅|✅✅✅|✅✅✅|✅✅✅| |Case 7:|✅✅✅|✅✅✅|✅✅✅|✅✅❌|✅✅❌|✅✅❌|✅✅❌| |Case 8:|✅✅✅|✅✅✅|✅✅✅|✅✅❌|✅✅❌|✅✅❌|✅✅❌| Cases d, e, f and g can apparently be considered as one case.