Compare commits

..

7 Commits

6 changed files with 88 additions and 52 deletions

View File

@@ -24,10 +24,6 @@ environment:
TOOLSET: msvc-14.1
CXXSTD: 14,17,latest
ADDRMD: 32,64
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
TOOLSET: clang-win
CXXSTD: 14,17,latest
ADDRMD: 32,64
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
ADDPATH: C:\cygwin\bin;
TOOLSET: gcc

View File

@@ -13,7 +13,7 @@
// BOOST_SYSTEM_HAS_SYSTEM_ERROR
#if !defined(BOOST_NO_CXX11_HDR_SYSTEM_ERROR) && !defined(BOOST_NO_CXX11_HDR_ATOMIC)
#if !defined(BOOST_NO_CXX11_HDR_SYSTEM_ERROR) && !defined(BOOST_NO_CXX11_HDR_ATOMIC) && !defined(BOOST_NO_CXX11_HDR_MUTEX)
# define BOOST_SYSTEM_HAS_SYSTEM_ERROR
#endif

View File

@@ -48,6 +48,11 @@ class std_category;
#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
#endif
#if defined(BOOST_MSVC)
#pragma warning(push)
#pragma warning(disable: 4351) // new behavior: elements of array will be default initialized
#endif
class BOOST_SYMBOL_VISIBLE error_category
{
private:
@@ -76,13 +81,21 @@ private:
boost::ulong_long_type id_;
static std::size_t const stdcat_size_ = 4 * sizeof( void const* );
union
{
mutable unsigned char stdcat_[ stdcat_size_ ];
void const* stdcat_align_;
};
#if defined(BOOST_SYSTEM_HAS_SYSTEM_ERROR)
mutable std::atomic< boost::system::detail::std_category* > ps_;
mutable std::atomic< unsigned > sc_init_;
#else
boost::system::detail::std_category* ps_;
unsigned sc_init_;
#endif
@@ -103,11 +116,11 @@ protected:
#endif
BOOST_SYSTEM_CONSTEXPR error_category() BOOST_NOEXCEPT: id_( 0 ), ps_()
BOOST_SYSTEM_CONSTEXPR error_category() BOOST_NOEXCEPT: id_( 0 ), stdcat_(), sc_init_()
{
}
explicit BOOST_SYSTEM_CONSTEXPR error_category( boost::ulong_long_type id ) BOOST_NOEXCEPT: id_( id ), ps_()
explicit BOOST_SYSTEM_CONSTEXPR error_category( boost::ulong_long_type id ) BOOST_NOEXCEPT: id_( id ), stdcat_(), sc_init_()
{
}
@@ -158,14 +171,22 @@ public:
}
#if defined(BOOST_SYSTEM_HAS_SYSTEM_ERROR)
void init_stdcat() const;
# if defined(__SUNPRO_CC) // trailing __global is not supported
operator std::error_category const & () const;
# else
operator std::error_category const & () const BOOST_SYMBOL_VISIBLE;
# endif
#endif
};
#if defined(BOOST_MSVC)
#pragma warning(pop)
#endif
#if ( defined( BOOST_GCC ) && BOOST_GCC >= 40600 ) || defined( BOOST_CLANG )
#pragma GCC diagnostic pop
#endif

View File

@@ -98,25 +98,65 @@ inline char const * error_category::message( int ev, char * buffer, std::size_t
#if defined(BOOST_SYSTEM_HAS_SYSTEM_ERROR)
#include <boost/system/detail/std_category_impl.hpp>
#include <mutex>
#include <new>
namespace boost
{
namespace system
{
inline error_category::operator std::error_category const & () const
namespace detail
{
template<class = void> struct stdcat_mx_holder
{
static std::mutex mx_;
};
template<class T> std::mutex stdcat_mx_holder<T>::mx_;
} // namespace detail
inline void error_category::init_stdcat() const
{
static_assert( sizeof( stdcat_ ) >= sizeof( boost::system::detail::std_category ), "sizeof(stdcat_) is not enough for std_category" );
#if defined(BOOST_MSVC) && BOOST_MSVC < 1900
// no alignof
#else
static_assert( alignof( decltype(stdcat_align_) ) >= alignof( boost::system::detail::std_category ), "alignof(stdcat_) is not enough for std_category" );
#endif
std::lock_guard<std::mutex> lk( boost::system::detail::stdcat_mx_holder<>::mx_ );
if( sc_init_.load( std::memory_order_acquire ) == 0 )
{
::new( static_cast<void*>( stdcat_ ) ) boost::system::detail::std_category( this, 0 );
sc_init_.store( 1, std::memory_order_release );
}
}
#if defined( BOOST_GCC ) && BOOST_GCC >= 40800 && BOOST_GCC < 70000
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif
inline BOOST_NOINLINE error_category::operator std::error_category const & () const
{
if( id_ == detail::generic_category_id )
{
// This condition must be the same as the one in error_condition.hpp
#if defined(BOOST_SYSTEM_AVOID_STD_GENERIC_CATEGORY)
static const boost::system::detail::std_category generic_instance( this, 0x1F4D3 );
return generic_instance;
static const boost::system::detail::std_category generic_instance( this, 0x1F4D3 );
return generic_instance;
#else
return std::generic_category();
return std::generic_category();
#endif
}
@@ -126,49 +166,28 @@ inline error_category::operator std::error_category const & () const
// This condition must be the same as the one in error_code.hpp
#if defined(BOOST_SYSTEM_AVOID_STD_SYSTEM_CATEGORY)
static const boost::system::detail::std_category system_instance( this, 0x1F4D7 );
return system_instance;
static const boost::system::detail::std_category system_instance( this, 0x1F4D7 );
return system_instance;
#else
return std::system_category();
return std::system_category();
#endif
}
detail::std_category* p = ps_.load( std::memory_order_acquire );
if( p != 0 )
if( sc_init_.load( std::memory_order_acquire ) == 0 )
{
return *p;
init_stdcat();
}
// One `std_category` object is allocated for every
// user-defined `error_category` that is converted to
// `std::error_category`.
//
// This one-time allocation will show up on leak checkers.
// That's unavoidable. There is no way to deallocate the
// `std_category` object because first, `error_category`
// is a literal type (so it can't have a destructor) and
// second, `error_category` needs to be usable during program
// shutdown.
//
// https://github.com/boostorg/system/issues/78
detail::std_category* q = new detail::std_category( this, 0 );
if( ps_.compare_exchange_strong( p, q, std::memory_order_release, std::memory_order_acquire ) )
{
return *q;
}
else
{
delete q;
return *p;
}
return *static_cast<boost::system::detail::std_category const*>( static_cast<void const*>( stdcat_ ) );
}
#if defined( BOOST_GCC ) && BOOST_GCC >= 40800 && BOOST_GCC < 70000
#pragma GCC diagnostic pop
#endif
} // namespace system
} // namespace boost

View File

@@ -62,13 +62,13 @@ int main()
BOOST_TEST( !r.has_value() );
BOOST_TEST( r.has_error() );
BOOST_TEST_EQ( r.error(), std::error_code( EINVAL, generic_category() ) );
BOOST_TEST_EQ( r.error(), error_code( EINVAL, generic_category() ) );
}
{
auto ec = make_error_code( errc::invalid_argument );
result<std::error_code> r( in_place_error, ec );
result<error_code> r( in_place_error, ec );
BOOST_TEST( !r.has_value() );
BOOST_TEST( r.has_error() );
@@ -77,12 +77,12 @@ int main()
}
{
result<std::error_code> r( in_place_error, EINVAL, generic_category() );
result<error_code> r( in_place_error, EINVAL, generic_category() );
BOOST_TEST( !r.has_value() );
BOOST_TEST( r.has_error() );
BOOST_TEST_EQ( r.error(), std::error_code( EINVAL, generic_category() ) );
BOOST_TEST_EQ( r.error(), error_code( EINVAL, generic_category() ) );
}
BOOST_TEST_EQ( X::instances, 0 );
@@ -140,8 +140,8 @@ int main()
BOOST_TEST_EQ( X::instances, 0 );
{
BOOST_TEST_TRAIT_TRUE((std::is_constructible<result<int>, std::error_code>));
BOOST_TEST_TRAIT_TRUE((std::is_convertible<std::error_code, result<int>>));
BOOST_TEST_TRAIT_TRUE((std::is_constructible<result<int>, error_code>));
BOOST_TEST_TRAIT_TRUE((std::is_convertible<error_code, result<int>>));
BOOST_TEST_TRAIT_TRUE((std::is_constructible<result<std::string, X>, int>));
BOOST_TEST_TRAIT_FALSE((std::is_convertible<int, result<std::string, X>>));
@@ -178,7 +178,7 @@ int main()
BOOST_TEST( !r.has_value() );
BOOST_TEST( r.has_error() );
BOOST_TEST_EQ( r.error(), std::error_code( EINVAL, generic_category() ) );
BOOST_TEST_EQ( r.error(), error_code( EINVAL, generic_category() ) );
}
return boost::report_errors();

View File

@@ -41,7 +41,7 @@ int main()
BOOST_TEST( !r.has_value() );
BOOST_TEST( r.has_error() );
BOOST_TEST_EQ( r.error(), std::error_code( EINVAL, generic_category() ) );
BOOST_TEST_EQ( r.error(), error_code( EINVAL, generic_category() ) );
}
{