diff --git a/include/boost/core/swap.hpp b/include/boost/core/swap.hpp index 7add2fbf..90275bb2 100644 --- a/include/boost/core/swap.hpp +++ b/include/boost/core/swap.hpp @@ -73,16 +73,27 @@ namespace boost_swap_impl } namespace boost +{ +namespace swap_detail { template BOOST_GPU_ENABLED - typename enable_if_c< !boost_swap_impl::is_const::value && !boost_swap_impl::is_const::value >::type + typename enable_if_c< !::boost_swap_impl::is_const::value && !::boost_swap_impl::is_const::value >::type swap(T1& left, T2& right) BOOST_CORE_SWAP_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(::boost_swap_impl::swap_impl(left, right))) { ::boost_swap_impl::swap_impl(left, right); } -} +} // namespace swap_detail + +// We need to import the swap name with a using directive here to prevent boost::swap from being found +// via ADL for types defined in namespace boost. This prevents infinite recursion as we use unqualified +// call to swap in noexcept specification and implementation of swap_impl. +// Note: Users should always refer to the swap function as boost::swap, i.e. not unqualified swap +// or boost::swap_detail::swap. The swap_detail namespace is an implementation detail of Boost.Swap. +using namespace swap_detail; + +} // namespace boost #undef BOOST_CORE_SWAP_NOEXCEPT_IF diff --git a/test/swap/Jamfile.v2 b/test/swap/Jamfile.v2 index d7f705e8..1d245210 100644 --- a/test/swap/Jamfile.v2 +++ b/test/swap/Jamfile.v2 @@ -14,6 +14,7 @@ compile swap_lib_header_2.cpp ; compile swap_mixed_headers_1.cpp ; compile swap_mixed_headers_2.cpp ; compile swap_noexcept.cpp ; +compile swap_boost_adl_recursion.cpp ; compile-fail swap_const_wrapper_fail.cpp ; diff --git a/test/swap/swap_boost_adl_recursion.cpp b/test/swap/swap_boost_adl_recursion.cpp new file mode 100644 index 00000000..efec7098 --- /dev/null +++ b/test/swap/swap_boost_adl_recursion.cpp @@ -0,0 +1,43 @@ +// Copyright (c) 2023 Andrey Semashev +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// Tests that boost::swap with types in namespace boost is not +// found via ADL and does not introduce infinite recursion. + +#include +#include + +namespace boost { + +struct some_boost_type {}; + +} + +namespace test_ns { + +template< typename T > +class X +{ +private: + X(X const&); + +public: + X() {} +}; + +template< typename T1, typename T2 > +inline void swap(T1&, T2&) +{ +} + +} + +int main() +{ + test_ns::X< boost::some_boost_type > x; + boost::swap(x, x); + return BOOST_NOEXCEPT_EXPR(boost::swap(x, x)); +}