Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add BOOST_SYSTEM_CURRENT_LOCATION_PTR #84

Open
wants to merge 10 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions include/boost/system/detail/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
23 changes: 13 additions & 10 deletions include/boost/system/detail/error_code.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <boost/system/detail/append_int.hpp>
#include <boost/system/detail/snprintf.hpp>
#include <boost/system/detail/config.hpp>
#include <boost/system/detail/source_location.hpp>

#if defined(BOOST_SYSTEM_HAS_SYSTEM_ERROR)
# include <boost/system/detail/std_category.hpp>
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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<boost::uintptr_t>( 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;
Expand All @@ -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<boost::uintptr_t>( loc ): 2 ) | ( ec.lc_flags_ & 1 );
lc_flags_ = ( loc.value()? loc.value(): 2 ) | ( ec.lc_flags_ & 1 );
}
}

Expand Down Expand Up @@ -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 );
}
Expand Down Expand Up @@ -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<source_location const*>( lc_flags_ &~ static_cast<boost::uintptr_t>( 1 ) ): loc;
source_location loc;
if( lc_flags_ >= 4 )
std::memcpy( &loc, reinterpret_cast<source_location const*>( lc_flags_ &~ static_cast<boost::uintptr_t>( 1 ) ), sizeof loc );
return loc;
}

// relationals:
Expand Down
106 changes: 106 additions & 0 deletions include/boost/system/detail/source_location.hpp
Original file line number Diff line number Diff line change
@@ -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 <boost/system/detail/config.hpp>
#include <boost/assert/source_location.hpp>
#include <boost/cstdint.hpp>
#include <boost/config.hpp>

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<boost::uintptr_t>( 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
7 changes: 7 additions & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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)

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

Expand Down
62 changes: 62 additions & 0 deletions test/ec_location_test5.cpp
Original file line number Diff line number Diff line change
@@ -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 <boost/system.hpp>
#include <boost/core/lightweight_test.hpp>
#include <cerrno>

#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<std::source_location::__impl>;
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
}
4 changes: 2 additions & 2 deletions test/ec_what_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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() + "]" );
}
Expand All @@ -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() + "]" );
}
Expand Down