Bug 114898 - Converting {} to a tag type should be ill-formed SFINAE-friendly
Summary: Converting {} to a tag type should be ill-formed SFINAE-friendly
Status: RESOLVED DUPLICATE of bug 102257
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: unknown
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2024-04-30 14:47 UTC by Arthur O'Dwyer
Modified: 2024-05-02 09:24 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2024-04-30 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Arthur O'Dwyer 2024-04-30 14:47:55 UTC
See LWG 2510, "Tag types should not be DefaultConstructible":
https://cplusplus.github.io/LWG/issue2510

WG21 seems convinced that there's also a core-language issue here: https://cplusplus.github.io/CWG/issues/1518.html

In the notes for LWG2510, I see:
> JW [i.e. jwakely] explains that it's important that tag types cannot be constructed from "{}" (e.g. the allocator tag in the tuple constructors).

However, it looks like GCC+libstdc++ violates LWG2510 by allowing tag types to be constructible from `{}` (or at least to fail in a SFINAE-unfriendly way).

    // https://godbolt.org/z/cMzar8Ehf
    struct Widget {
      int i[1];
    };
    std::optional<Widget> r1( {{}} );
      // Bug 1: GCC complains about nullopt_t's explicit ctor
    std::optional<Widget> r2{ {} };
      // Bug 2: GCC complains about in_place_t's explicit ctor

Now, according to Clang+libstdc++, Clang+libc++, and MSVC+STL, both examples should be well-formed, and should mean:

- r1 is direct-initialized from {{}} i.e. a Widget with one element {} i.e. a value-initialized array of int[1].

- r2 is direct-list-initialized from {} i.e. a value-initialized Widget.

In the April 2024 WG21 mailing, Brian Bi brings a paper P3112 "Specify Constructor of std::nullopt_t" motivated by this bad behavior of GCC's,
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3112r0.html
but really I think it should just be a bug report, since GCC is the one compiler currently misbehaving, and jwakely was already quoted above as wanting `{}` _not_ to construct a tag type.

I don't much care whether this is treated as a GCC compiler bug or a libstdc++ library bug, but at first glance it _looks_ like a compiler bug (since libstdc++ works fine with Clang). If it _is_ treated as a libstdc++ bug, you might take this opportunity to audit all of the tag types in the entire library and just make sure they're all implemented using the same consistent technique, whatever it is.
Comment 1 Jonathan Wakely 2024-04-30 15:00:36 UTC
Standalone testcase:

struct nullopt_t {
    enum class Hidden { Token };
    explicit constexpr nullopt_t(Hidden) noexcept { }
};

struct in_place_t {
    explicit constexpr in_place_t() = default;
};

template<typename T>
struct optional
{
    template<typename U = T>
    optional(U&&) { }

    optional(in_place_t);

    optional(nullopt_t);
};

struct Widget {
    int i[1];
};

optional<Widget> r1( {{}} );

optional<Widget> r2{ {} };
Comment 2 Jonathan Wakely 2024-04-30 15:06:38 UTC
Might be related to Bug 113300 and/or Bug 102257
Comment 3 Jonathan Wakely 2024-05-02 09:23:51 UTC
Dup of Bug 102257, which might be what CWG 2586 says should happen, sadly.

*** This bug has been marked as a duplicate of bug 102257 ***
Comment 4 Jonathan Wakely 2024-05-02 09:24:10 UTC
(In reply to Jonathan Wakely from comment #3)
> Dup of Bug 102257, which might be what CWG 2586 says should happen, sadly.

Oops 2856