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

            Bug ID: 85183
           Summary: [8 Regression] std::variant move assignment mishandles
                    move-only types
           Product: gcc
           Version: 8.0
            Status: UNCONFIRMED
          Keywords: rejects-valid
          Severity: normal
          Priority: P3
         Component: libstdc++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: rs2740 at gmail dot com
  Target Milestone: ---

Repro:
#include <variant>

struct moveonly {
    moveonly() noexcept { }
    moveonly(moveonly&&) noexcept { }
    moveonly& operator=(moveonly&&) noexcept { return *this; } 
    ~moveonly() { }
};


void test() {
    std::variant<moveonly> m1, m2;
    m1 = std::move(m2);
}

Compiles with 7. Breaks with 8:

In file included from prog.cc:1:
/opt/wandbox/gcc-head/include/c++/8.0.1/variant: In instantiation of 'void
std::__detail::__variant::__erased_assign(void*, void*) [with _Lhs = moveonly&;
_Rhs = const moveonly&]':
/opt/wandbox/gcc-head/include/c++/8.0.1/variant:607:27:   required from
'std::__detail::__variant::_Move_assign_base<<anonymous>, _Types>&
std::__detail::__variant::_Move_assign_base<<anonymous>,
_Types>::operator=(std::__detail::__variant::_Move_assign_base<<anonymous>,
_Types>&&) [with bool <anonymous> = false; _Types = {moveonly}]'
/opt/wandbox/gcc-head/include/c++/8.0.1/variant:648:12:   required from here
/opt/wandbox/gcc-head/include/c++/8.0.1/variant:258:42: error: use of deleted
function 'constexpr moveonly& moveonly::operator=(const moveonly&)'
       __variant::__ref_cast<_Lhs>(__lhs) = __variant::__ref_cast<_Rhs>(__rhs);
       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
prog.cc:3:8: note: 'constexpr moveonly& moveonly::operator=(const moveonly&)'
is implicitly declared as deleted because 'moveonly' declares a move
constructor or move assignment operator
 struct moveonly {
        ^~~~~~~~
In file included from prog.cc:1:
/opt/wandbox/gcc-head/include/c++/8.0.1/variant: In instantiation of 'void
std::__detail::__variant::__erased_ctor(void*, void*) [with _Lhs = moveonly&;
_Rhs = const moveonly&]':
/opt/wandbox/gcc-head/include/c++/8.0.1/variant:468:30:   required from
'std::__detail::__variant::_Copy_ctor_base<<anonymous>,
_Types>::_Copy_ctor_base(const
std::__detail::__variant::_Copy_ctor_base<<anonymous>, _Types>&) [with bool
<anonymous> = false; _Types = {moveonly}]'
/opt/wandbox/gcc-head/include/c++/8.0.1/variant:509:7:   required from
'std::__detail::__variant::_Move_assign_base<<anonymous>, _Types>&
std::__detail::__variant::_Move_assign_base<<anonymous>,
_Types>::operator=(std::__detail::__variant::_Move_assign_base<<anonymous>,
_Types>&&) [with bool <anonymous> = false; _Types = {moveonly}]'
/opt/wandbox/gcc-head/include/c++/8.0.1/variant:648:12:   required from here
/opt/wandbox/gcc-head/include/c++/8.0.1/variant:246:7: error: use of deleted
function 'constexpr moveonly::moveonly(const moveonly&)'
       ::new (__lhs) _Type(__variant::__ref_cast<_Rhs>(__rhs));
       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
prog.cc:3:8: note: 'constexpr moveonly::moveonly(const moveonly&)' is
implicitly declared as deleted because 'moveonly' declares a move constructor
or move assignment operator
 struct moveonly {

----
There are two bugs in the move assignment operator of _Move_assign_base primary
template, presumably caused by copy-paste:
* in the matching index case, it uses __erased_assign<_Types&, const _Types&>
when it should be using __erased_assign<_Types&, _Types&&>.
* in the mismatched index case, it copies __rhs to create __tmp
(`_Move_assign_base __tmp(__rhs);`) when it should have moved from it.

Reply via email to