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).