Use diagnostic pragmas to allow using `if constexpr` in C++11 mode, so that we don't need to use tag dispatching.
The _M_move_assign overloads that were previously used for tag dispatching are no longer used, but are retained here (at least for the default config) so that an explicit instantiation will still define those members. This ensures that old code which expects an explicit instantiation in some other translation unit will still link. I'm not sure if that's really needed, we should probably have a policy about whether we support explicit instantiations where the declaration and definition use different versions of the headers. libstdc++-v3/ChangeLog: * include/bits/stl_list.h (operator=(list&&)): Use if constexpr instead of dispatching to _M_move_assign. (_M_move_assign): Do not define for versioned namespace. --- Tested x86_64-linux. Pushed to trunk. I don't know if we really need to keep the unused functions around. We should decide and document whether or not we support explicit instantiations across releases. libstdc++-v3/include/bits/stl_list.h | 29 ++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/libstdc++-v3/include/bits/stl_list.h b/libstdc++-v3/include/bits/stl_list.h index 7deb04b4bfe..3f92de42996 100644 --- a/libstdc++-v3/include/bits/stl_list.h +++ b/libstdc++-v3/include/bits/stl_list.h @@ -935,6 +935,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 operator=(const list& __x); #if __cplusplus >= 201103L +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr /** * @brief %List move assignment operator. * @param __x A %list of identical element and allocator types. @@ -952,9 +954,29 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 constexpr bool __move_storage = _Node_alloc_traits::_S_propagate_on_move_assign() || _Node_alloc_traits::_S_always_equal(); - _M_move_assign(std::move(__x), __bool_constant<__move_storage>()); + if constexpr (!__move_storage) + { + if (__x._M_get_Node_allocator() != this->_M_get_Node_allocator()) + { + // The rvalue's allocator cannot be moved, or is not equal, + // so we need to individually move each element. + _M_assign_dispatch(std::make_move_iterator(__x.begin()), + std::make_move_iterator(__x.end()), + __false_type{}); + return *this; + } + } + + this->clear(); + this->_M_move_nodes(std::move(__x)); + + if constexpr (_Node_alloc_traits::_S_propagate_on_move_assign()) + this->_M_get_Node_allocator() + = std::move(__x._M_get_Node_allocator()); + return *this; } +#pragma GCC diagnostic pop /** * @brief %List initializer list assignment operator. @@ -2156,7 +2178,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 const_iterator _M_resize_pos(size_type& __new_size) const; -#if __cplusplus >= 201103L +#if __cplusplus >= 201103L && ! _GLIBCXX_INLINE_VERSION + // XXX GLIBCXX_ABI Deprecated + // These are unused and only kept so that explicit instantiations will + // continue to define the symbols. void _M_move_assign(list&& __x, true_type) noexcept { -- 2.47.0