diff --git a/include/boost/system/detail/config.hpp b/include/boost/system/detail/config.hpp index 2dbb2f99b..b172d3f21 100644 --- a/include/boost/system/detail/config.hpp +++ b/include/boost/system/detail/config.hpp @@ -62,6 +62,14 @@ # define BOOST_SYSTEM_DEPRECATED(msg) #endif +// BOOST_SYSTEM_IMPLICIT + +#if __cplusplus >= 202002L +# define BOOST_SYSTEM_IMPLICIT explicit( false ) +#else +# define BOOST_SYSTEM_IMPLICIT +#endif + // BOOST_SYSTEM_CLANG_6 #if defined(__clang__) && (__clang_major__ < 7 || (defined(__APPLE__) && __clang_major__ < 11)) diff --git a/include/boost/system/detail/error_code.hpp b/include/boost/system/detail/error_code.hpp index 1189fb449..50d9b41a2 100644 --- a/include/boost/system/detail/error_code.hpp +++ b/include/boost/system/detail/error_code.hpp @@ -21,6 +21,7 @@ #include #include #include +#include #if defined(BOOST_SYSTEM_HAS_SYSTEM_ERROR) # include @@ -88,7 +89,7 @@ class error_code // 1: holds std::error_code in d2_ // 2: holds error code in d1_, failed == false // 3: holds error code in d1_, failed == true - // >3: pointer to source_location, failed_ in lsb + // >3: pointer to source_location or layout-compatible type, failed_ in lsb boost::uintptr_t lc_flags_; private: @@ -132,8 +133,8 @@ class error_code d1_.cat_ = &cat; } - error_code( int val, const error_category & cat, source_location const * loc ) BOOST_NOEXCEPT: - d1_(), lc_flags_( ( loc? reinterpret_cast( loc ): 2 ) | +detail::failed_impl( val, cat ) ) + BOOST_SYSTEM_CONSTEXPR error_code( int val, const error_category & cat, detail::source_location_ptr loc ) BOOST_NOEXCEPT: + d1_(), lc_flags_( ( loc.value()? loc.value(): 2 ) | +detail::failed_impl( val, cat ) ) { d1_.val_ = val; d1_.cat_ = &cat; @@ -150,14 +151,14 @@ class error_code *this = make_error_code( e ); } - error_code( error_code const& ec, source_location const * loc ) BOOST_NOEXCEPT: + error_code( error_code const& ec, detail::source_location_ptr loc ) BOOST_NOEXCEPT: d1_(), lc_flags_( 0 ) { *this = ec; if( ec.lc_flags_ != 0 && ec.lc_flags_ != 1 ) { - lc_flags_ = ( loc? reinterpret_cast( loc ): 2 ) | ( ec.lc_flags_ & 1 ); + lc_flags_ = ( loc.value()? loc.value(): 2 ) | ( ec.lc_flags_ & 1 ); } } @@ -190,12 +191,12 @@ class error_code *this = error_code( val, cat ); } - void assign( int val, const error_category & cat, source_location const * loc ) BOOST_NOEXCEPT + void assign( int val, const error_category & cat, detail::source_location_ptr loc ) BOOST_NOEXCEPT { *this = error_code( val, cat, loc ); } - void assign( error_code const& ec, source_location const * loc ) BOOST_NOEXCEPT + void assign( error_code const& ec, detail::source_location_ptr loc ) BOOST_NOEXCEPT { *this = error_code( ec, loc ); } @@ -364,10 +365,12 @@ class error_code return lc_flags_ >= 4; } - source_location const & location() const BOOST_NOEXCEPT + source_location location() const BOOST_NOEXCEPT { - BOOST_STATIC_CONSTEXPR source_location loc; - return lc_flags_ >= 4? *reinterpret_cast( lc_flags_ &~ static_cast( 1 ) ): loc; + source_location loc; + if( lc_flags_ >= 4 ) + std::memcpy( &loc, reinterpret_cast( lc_flags_ &~ static_cast( 1 ) ), sizeof loc ); + return loc; } // relationals: diff --git a/include/boost/system/detail/source_location.hpp b/include/boost/system/detail/source_location.hpp new file mode 100644 index 000000000..9b54a6f75 --- /dev/null +++ b/include/boost/system/detail/source_location.hpp @@ -0,0 +1,106 @@ +#ifndef BOOST_SYSTEM_DETAIL_SOURCE_LOCATION_HPP_INCLUDED +#define BOOST_SYSTEM_DETAIL_SOURCE_LOCATION_HPP_INCLUDED + +// Copyright Beman Dawes 2006, 2007 +// Copyright Christoper Kohlhoff 2007 +// Copyright Peter Dimov 2017-2021 +// +// 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) +// +// See library home page at http://www.boost.org/libs/system + +#include +#include +#include +#include + +namespace boost +{ + +namespace system +{ + +namespace detail +{ + +class source_location_ptr +{ +public: + + BOOST_SYSTEM_CONSTEXPR source_location_ptr() BOOST_NOEXCEPT: + value_( 0u ) + { + } + + // Implicit (converting) constructor to allow passing source_location const* to error_code ctors and modifiers. + BOOST_SYSTEM_IMPLICIT source_location_ptr( source_location const* ptr ) BOOST_NOEXCEPT: + value_( reinterpret_cast( ptr ) ) + { + } + + BOOST_SYSTEM_CONSTEXPR boost::uintptr_t value() const BOOST_NOEXCEPT + { + return value_; + } + +private: + + boost::uintptr_t value_; + +}; + +} // namespace detail + +} // namespace system + +} // namespace boost + +#if defined(BOOST_DISABLE_CURRENT_LOCATION) + +# define BOOST_SYSTEM_CURRENT_LOCATION_PTR ::boost::system::detail::source_location_ptr() + +#elif defined(__cpp_lib_source_location) && __cpp_lib_source_location >= 201907L && defined(BOOST_GCC) + +// gcc __builtin_source_location() returns std::source_location::__impl const* cast to void const*; we test that +// boost::source_location is layout-compatible with std::source_location::__impl, avoiding UB via memcpy. +# define BOOST_SYSTEM_CURRENT_LOCATION_PTR ::boost::system::detail::source_location_ptr( \ + static_cast<::boost::source_location const*>( __builtin_source_location() ) ) + +#elif defined(__cpp_lib_source_location) && __cpp_lib_source_location >= 201907L && defined(BOOST_CLANG) + +// Clang __builtin_source_location() returns std::source_location::__impl const*; same considerations as gcc. +# define BOOST_SYSTEM_CURRENT_LOCATION_PTR ::boost::system::detail::source_location_ptr( \ + reinterpret_cast<::boost::source_location const*>( __builtin_source_location() ) ) + +#elif (defined(__cpp_lib_source_location) && __cpp_lib_source_location >= 201907L) \ + || (defined(BOOST_MSVC) && BOOST_MSVC >= 1926) \ + || (defined(BOOST_CLANG) && BOOST_CLANG_VERSION >= 90000 && !defined(BOOST_NO_CXX11_LAMBDAS)) \ + || (defined(BOOST_GCC) && BOOST_GCC >= 50000 && !defined(BOOST_NO_CXX11_LAMBDAS)) + +// BOOST_CURRENT_LOCATION has function_name(), so we have to collect it outside the lambda. +# define BOOST_SYSTEM_CURRENT_LOCATION_PTR ::boost::system::detail::source_location_ptr( \ + []( ::boost::source_location loc ) -> ::boost::source_location const* \ + { \ + static const ::boost::source_location loc_ = loc; \ + return &loc_; \ + }( BOOST_CURRENT_LOCATION ) ) + +#elif defined(BOOST_NO_CXX11_LAMBDAS) + +// Not implementable without C++11 lambdas. +# define BOOST_SYSTEM_NO_CURRENT_LOCATION_PTR 1 + +#else + +// no function_name(), so it's OK to collect BOOST_CURRENT_LOCATION inside the lambda. +# define BOOST_SYSTEM_CURRENT_LOCATION_PTR ::boost::system::detail::source_location_ptr( \ + []() -> ::boost::source_location const* \ + { \ + static BOOST_SYSTEM_CONSTEXPR ::boost::source_location loc_ = BOOST_CURRENT_LOCATION; \ + return &loc_; \ + }() ) + +#endif + +#endif // #ifndef BOOST_SYSTEM_DETAIL_SOURCE_LOCATION_HPP_INCLUDED diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index eeab9c482..4d85cdbcb 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -62,6 +62,12 @@ system_run(system_category_test.cpp) system_run(after_main_test.cpp) system_run(failed_test.cpp) system_run(failed_constexpr_test.cpp) +if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND + CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 6 AND + CMAKE_CXX_COMPILER_VERSION VERSION_LESS 13) + # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71962 + set_source_files_properties(failed_constexpr_test.cpp PROPERTIES COMPILE_OPTIONS -fno-sanitize=undefined) +endif() boost_test(SOURCES warnings_test.cpp COMPILE_OPTIONS -Wall -Werror) @@ -124,6 +130,7 @@ boost_test(TYPE run SOURCES std_interop_test14.cpp) boost_test(TYPE run SOURCES ec_location_test3.cpp) boost_test(TYPE run SOURCES ec_location_test4.cpp) +boost_test(TYPE run SOURCES ec_location_test5.cpp) boost_test(TYPE compile SOURCES constexpr_test2.cpp) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 7a8d1853e..2139291cf 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -152,6 +152,7 @@ run std_interop_test14.cpp ; run ec_location_test3.cpp ; run ec_location_test4.cpp ; +run ec_location_test5.cpp ; compile constexpr_test2.cpp ; diff --git a/test/ec_location_test5.cpp b/test/ec_location_test5.cpp new file mode 100644 index 000000000..96029b746 --- /dev/null +++ b/test/ec_location_test5.cpp @@ -0,0 +1,62 @@ +// Copyright 2021, 2022 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include + +#if defined(__cpp_lib_source_location) && __cpp_lib_source_location >= 201907L && defined(BOOST_GCC) + +struct get_std_source_location_impl_tag {}; +template< class T > +struct get_std_source_location_impl_t +{ + friend auto get_std_source_location_impl( get_std_source_location_impl_tag ) { return T(); } +}; +template struct get_std_source_location_impl_t; +auto get_std_source_location_impl( get_std_source_location_impl_tag ); +using std_source_location_impl = decltype( get_std_source_location_impl( get_std_source_location_impl_tag() ) ); + +static_assert( static_cast< const std_source_location_impl* >( __builtin_source_location() )->_M_line == __LINE__ ); + +# if __cpp_lib_is_layout_compatible >= 201907L +static_assert( std::is_layout_compatible_v< boost::source_location, std_source_location_impl > ); +# endif + +#elif defined(__cpp_lib_source_location) && __cpp_lib_source_location >= 201907L && defined(BOOST_CLANG) + +static_assert( __builtin_source_location()->_M_line == __LINE__ ); + +# if __cpp_lib_is_layout_compatible >= 201907L +static_assert( std::is_layout_compatible_v< boost::source_location, + std::remove_cvref_t< decltype( *__builtin_source_location() ) > > ); +# endif + +#endif + +int main() +{ +#if !defined(BOOST_SYSTEM_NO_CURRENT_LOCATION_PTR) + int const val = ENOENT; + boost::system::error_category const & cat = boost::system::generic_category(); + + { + BOOST_STATIC_CONSTEXPR boost::source_location loc = BOOST_CURRENT_LOCATION; + + boost::system::error_code ec( val, cat, BOOST_SYSTEM_CURRENT_LOCATION_PTR ); + + BOOST_TEST_EQ( ec.value(), val ); + BOOST_TEST_EQ( &ec.category(), &cat ); + + BOOST_TEST( ec.failed() ); + + BOOST_TEST( ec.has_location() ); + BOOST_TEST_EQ( std::strcmp( ec.location().file_name(), loc.file_name() ), 0 ); + BOOST_TEST_EQ( std::strcmp( ec.location().function_name(), loc.function_name() ), 0 ); + BOOST_TEST_EQ( ec.location().line(), loc.line() + 2 ); + } + + return boost::report_errors(); +#endif +} diff --git a/test/ec_what_test.cpp b/test/ec_what_test.cpp index 35c1e039a..798b40bf8 100644 --- a/test/ec_what_test.cpp +++ b/test/ec_what_test.cpp @@ -45,7 +45,7 @@ int main() BOOST_TEST_EQ( ec.value(), 5 ); BOOST_TEST( ec.category() == sys::generic_category() ); - BOOST_TEST_EQ( &ec.location(), &loc ); + BOOST_TEST_EQ( ec.location().line(), loc.line() ); BOOST_TEST_EQ( ec.what(), ec.message() + " [generic:5 at " + loc.to_string() + "]" ); } @@ -57,7 +57,7 @@ int main() BOOST_TEST_EQ( ec.value(), 5 ); BOOST_TEST( ec.category() == sys::system_category() ); - BOOST_TEST_EQ( &ec.location(), &loc ); + BOOST_TEST_EQ( ec.location().line(), loc.line() ); BOOST_TEST_EQ( ec.what(), ec.message() + " [system:5 at " + loc.to_string() + "]" ); }