public inbox for gcc-bugs@sourceware.org help / color / mirror / Atom feed
* [Bug c++/114076] New: list-initialization with assignment expression triggers wrong template instanciation @ 2024-02-23 12:17 benni.buch at gmail dot com 2024-02-23 14:42 ` [Bug c++/114076] " de34 at live dot cn ` (2 more replies) 0 siblings, 3 replies; 4+ messages in thread From: benni.buch at gmail dot com @ 2024-02-23 12:17 UTC (permalink / raw) To: gcc-bugs https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114076 Bug ID: 114076 Summary: list-initialization with assignment expression triggers wrong template instanciation Product: gcc Version: 13.2.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: benni.buch at gmail dot com Target Milestone: --- I come from this Bug Report to Visual C++: - https://github.com/microsoft/STL/issues/4417 I think that GCC has a similar bug here. ```cpp template <typename T> struct holder { holder() = default; constexpr ~holder() { static_assert(sizeof(T) || true); } }; struct Incomplete; struct Class { Class(); ~Class(); holder<Incomplete> a{}; holder<Incomplete> b = {}; //holder<Incomplete> c = holder<Incomplete>{}; }; int main() { [[maybe_unused]] Class v; } ``` - https://godbolt.org/z/ds3WYK55f Cases a and b can both be compiled with Clang. GCC rejects b, which is wrong in my opinion. If I understand it correctly, then cases a and b should result in absolutely identical initializations. The destructor of holder should not be instantiated. In case c, the rejection seems to me to be correct, since here the temporary value must be destroyed by a destructor call. Among other things, this error affects unique_ptr. ^ permalink raw reply [flat|nested] 4+ messages in thread
* [Bug c++/114076] list-initialization with assignment expression triggers wrong template instanciation 2024-02-23 12:17 [Bug c++/114076] New: list-initialization with assignment expression triggers wrong template instanciation benni.buch at gmail dot com @ 2024-02-23 14:42 ` de34 at live dot cn 2024-02-23 14:47 ` de34 at live dot cn 2024-03-05 12:26 ` benni.buch at gmail dot com 2 siblings, 0 replies; 4+ messages in thread From: de34 at live dot cn @ 2024-02-23 14:42 UTC (permalink / raw) To: gcc-bugs https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114076 Jiang An <de34 at live dot cn> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |de34 at live dot cn --- Comment #1 from Jiang An <de34 at live dot cn> --- Looks like a duplicate of Bug 104850 to me. GCC cares about the difference between direct/copy of initialization, not whether list-initialization or not (however, it's unfortunately that direct-non-list-initialization can't be used). > In case c, the rejection seems to me to be correct, since here the temporary > value must be destroyed by a destructor call. I don't see why there's even a temporary value since C++17. The prvalue is used to initialize the data member (via temporary materialization). The potential invocation of destructor should be in the body of constructors. ^ permalink raw reply [flat|nested] 4+ messages in thread
* [Bug c++/114076] list-initialization with assignment expression triggers wrong template instanciation 2024-02-23 12:17 [Bug c++/114076] New: list-initialization with assignment expression triggers wrong template instanciation benni.buch at gmail dot com 2024-02-23 14:42 ` [Bug c++/114076] " de34 at live dot cn @ 2024-02-23 14:47 ` de34 at live dot cn 2024-03-05 12:26 ` benni.buch at gmail dot com 2 siblings, 0 replies; 4+ messages in thread From: de34 at live dot cn @ 2024-02-23 14:47 UTC (permalink / raw) To: gcc-bugs https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114076 --- Comment #2 from Jiang An <de34 at live dot cn> --- The "templatization" trick also works for GCC. https://godbolt.org/z/8PeMMzsbb ``` template <typename T> struct holder { holder() = default; constexpr ~holder() { static_assert(sizeof(T) || true); } }; struct Incomplete; template<class = void> // templated struct Class { Class(); ~Class(); holder<Incomplete> a{}; // all accept holder<Incomplete> b = {}; // all accept holder<Incomplete> c = holder<Incomplete>{}; // only Clang rejects }; int main() { [[maybe_unused]] Class v; // CTAD } ``` It's unclear to me what is not yet instantiated after the object definition. ^ permalink raw reply [flat|nested] 4+ messages in thread
* [Bug c++/114076] list-initialization with assignment expression triggers wrong template instanciation 2024-02-23 12:17 [Bug c++/114076] New: list-initialization with assignment expression triggers wrong template instanciation benni.buch at gmail dot com 2024-02-23 14:42 ` [Bug c++/114076] " de34 at live dot cn 2024-02-23 14:47 ` de34 at live dot cn @ 2024-03-05 12:26 ` benni.buch at gmail dot com 2 siblings, 0 replies; 4+ messages in thread From: benni.buch at gmail dot com @ 2024-03-05 12:26 UTC (permalink / raw) To: gcc-bugs 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. ^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2024-03-05 12:26 UTC | newest] Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2024-02-23 12:17 [Bug c++/114076] New: list-initialization with assignment expression triggers wrong template instanciation benni.buch at gmail dot com 2024-02-23 14:42 ` [Bug c++/114076] " de34 at live dot cn 2024-02-23 14:47 ` de34 at live dot cn 2024-03-05 12:26 ` benni.buch at gmail dot com
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).