Skip to content

Commit

Permalink
Moved boost::swap into a detail namespace to avoid it being found via…
Browse files Browse the repository at this point in the history
… ADL.

This resolves infinite recursion when boost::swap is called on types that
are defined in namespace boost. The swap_impl implementation and noexcept
specification is using an unqualified call to swap, so if the argument types
are defined in namespace boost then our boost::swap function may be found
and selected to resolve the call.

Fixes #148.
  • Loading branch information
Lastique committed Jul 9, 2023
1 parent 216999e commit 987ffb3
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 2 deletions.
15 changes: 13 additions & 2 deletions include/boost/core/swap.hpp
Expand Up @@ -73,16 +73,27 @@ namespace boost_swap_impl
}

namespace boost
{
namespace swap_detail
{
template<class T1, class T2>
BOOST_GPU_ENABLED
typename enable_if_c< !boost_swap_impl::is_const<T1>::value && !boost_swap_impl::is_const<T2>::value >::type
typename enable_if_c< !::boost_swap_impl::is_const<T1>::value && !::boost_swap_impl::is_const<T2>::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

Expand Down
1 change: 1 addition & 0 deletions test/swap/Jamfile.v2
Expand Up @@ -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 ;

Expand Down
40 changes: 40 additions & 0 deletions test/swap/swap_boost_adl_recursion.cpp
@@ -0,0 +1,40 @@
// 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 <boost/core/swap.hpp>

namespace boost {

struct boost_type {};

}

namespace test_ns {

template<class T> class X
{
X( X const& );

public:

X() {}
};

template< typename T1, typename T2 >
inline void swap(T1&, T2&)
{
}

}

int main()
{
test_ns::X< boost::boost_type > x;
return noexcept( boost::swap( x, x ) );
}

0 comments on commit 987ffb3

Please sign in to comment.