https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87855

Jonathan Wakely <redi at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |ASSIGNED

--- Comment #18 from Jonathan Wakely <redi at gcc dot gnu.org> ---
The minimal fix is:

    PR libstdc++/87855 fix optional for types with non-trivial copy/move

    When the contained value is not trivially copy (or move) constructible
    the union's copy (or move) constructor will be deleted, and so the
    _Optional_payload delegating constructors are invalid. G++ fails to
    diagnose this because it incorrectly performs copy elision in the
    delegating constructors. Clang does diagnose it (llvm.org/PR40245).

    The solution is to avoid performing any copy (or move) when the
    contained value's copy (or move) constructor isn't trivial. Instead the
    contained value can be constructed by calling _M_construct. This is OK,
    because the relevant constructor doesn't need to be constexpr when the
    contained value isn't trivially copy (or move) constructible.

        PR libstdc++/87855
        * include/std/optional: Adjust whitespace.
        (_Optional_payload<_Tp, true, C, M>): Use _M_construct to construct
        the contained object when it isn't trivially copy/move constructible.


--- a/libstdc++-v3/include/std/optional
+++ b/libstdc++-v3/include/std/optional
@@ -334,11 +334,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION

       constexpr
       _Optional_payload(bool __engaged, const _Optional_payload& __other)
-      : _Optional_payload(__engaged ?
-                         _Optional_payload(__ctor_tag<bool>{},
-                                           __other._M_payload) :
-                         _Optional_payload(__ctor_tag<void>{}))
-      { }
+      : _M_engaged(__engaged)
+      {
+       if (__engaged)
+         _M_construct(__other._M_payload);
+      }

       constexpr
       _Optional_payload(bool __engaged, _Optional_payload&& __other)
@@ -453,20 +453,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION

       constexpr
       _Optional_payload(bool __engaged, const _Optional_payload& __other)
-      : _Optional_payload(__engaged ?
-                         _Optional_payload(__ctor_tag<bool>{},
-                                           __other._M_payload) :
-                         _Optional_payload(__ctor_tag<void>{}))
-      { }
-
-      constexpr
-      _Optional_payload(bool __engaged, _Optional_payload&& __other)
       : _Optional_payload(__engaged
                          ? _Optional_payload(__ctor_tag<bool>{},
-                                             std::move(__other._M_payload))
+                                             __other._M_payload)
                          : _Optional_payload(__ctor_tag<void>{}))
       { }

+      constexpr
+      _Optional_payload(bool __engaged, _Optional_payload&& __other)
+      : _M_engaged(__engaged)
+      {
+       if (__engaged)
+         _M_construct(std::move(__other._M_payload));
+      }
+
       _Optional_payload(const _Optional_payload&) = default;
       _Optional_payload(_Optional_payload&&) = default;

@@ -573,19 +573,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION

       constexpr
       _Optional_payload(bool __engaged, const _Optional_payload& __other)
-      : _Optional_payload(__engaged ?
-                         _Optional_payload(__ctor_tag<bool>{},
-                                           __other._M_payload) :
-                         _Optional_payload(__ctor_tag<void>{}))
-      { }
+      : _M_engaged(__engaged)
+      {
+       if (__engaged)
+         _M_construct(std::move(__other._M_payload));
+      }

       constexpr
       _Optional_payload(bool __engaged, _Optional_payload&& __other)
-      : _Optional_payload(__engaged
-                         ? _Optional_payload(__ctor_tag<bool>{},
-                                             std::move(__other._M_payload))
-                         : _Optional_payload(__ctor_tag<void>{}))
-      { }
+      : _M_engaged(__engaged)
+      {
+       if (__engaged)
+         _M_construct(std::move(__other._M_payload));
+      }

       _Optional_payload(const _Optional_payload&) = default;
       _Optional_payload(_Optional_payload&&) = default;



However, I have a better patch on the way, which hoists all those constructors
into a new base so we only need to fi it in one place (not three).

Reply via email to