diff --git a/include/boost/throw_exception.hpp b/include/boost/throw_exception.hpp index b8a2e49..44b6ad5 100644 --- a/include/boost/throw_exception.hpp +++ b/include/boost/throw_exception.hpp @@ -7,10 +7,9 @@ # pragma once #endif -// // boost/throw_exception.hpp // -// Copyright (c) 2002, 2018, 2019 Peter Dimov +// Copyright (c) 2002, 2018-2022 Peter Dimov // Copyright (c) 2008-2009 Emil Dotchevski and Reverge Studios, Inc. // // Distributed under the Boost Software License, Version 1.0. (See @@ -18,14 +17,17 @@ // http://www.boost.org/LICENSE_1_0.txt) // // http://www.boost.org/libs/throw_exception -// #include #include #include #include #include +#include #include +#if !defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS) +#include +#endif #if !defined( BOOST_EXCEPTION_DISABLE ) && defined( BOOST_BORLANDC ) && BOOST_WORKAROUND( BOOST_BORLANDC, BOOST_TESTED_AT(0x593) ) # define BOOST_EXCEPTION_DISABLE @@ -178,4 +180,87 @@ template BOOST_NORETURN void throw_exception( E const & e, boost::sourc #define BOOST_THROW_EXCEPTION(x) ::boost::throw_exception(x, BOOST_CURRENT_LOCATION) +namespace boost +{ + +// throw_with_location + +namespace detail +{ + +struct BOOST_SYMBOL_VISIBLE throw_location +{ + boost::source_location location_; + + explicit throw_location( boost::source_location const & loc ): location_( loc ) + { + } +}; + +template class BOOST_SYMBOL_VISIBLE with_throw_location: public E, public throw_location +{ +public: + + with_throw_location( E const & e, boost::source_location const & loc ): E( e ), throw_location( loc ) + { + } + +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + + with_throw_location( E && e, boost::source_location const & loc ): E( std::move( e ) ), throw_location( loc ) + { + } + +#endif +}; + +} // namespace detail + +#if !defined(BOOST_NO_EXCEPTIONS) + +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS) + +template BOOST_NORETURN void throw_with_location( E && e, boost::source_location const & loc = BOOST_CURRENT_LOCATION ) +{ + throw_exception_assert_compatibility( e ); + throw detail::with_throw_location::type>( std::forward( e ), loc ); +} + +#else + +template BOOST_NORETURN void throw_with_location( E const & e, boost::source_location const & loc = BOOST_CURRENT_LOCATION ) +{ + throw_exception_assert_compatibility( e ); + throw detail::with_throw_location( e, loc ); +} + +#endif + +#else + +template BOOST_NORETURN void throw_with_location( E const & e, boost::source_location const & loc = BOOST_CURRENT_LOCATION ) +{ + boost::throw_exception( e, loc ); +} + +#endif + +// get_throw_location + +template boost::source_location get_throw_location( E const & e ) +{ +#if defined(BOOST_NO_RTTI) + + return boost::source_location(); + +#else + + detail::throw_location const* p = dynamic_cast< detail::throw_location const* >( &e ); + return p? p->location_: boost::source_location(); + +#endif +} + +} // namespace boost + #endif // #ifndef BOOST_THROW_EXCEPTION_HPP_INCLUDED diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 99f2963..3a13aff 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -31,9 +31,10 @@ run throw_exception_test5.cpp ; lib lib1_throw : lib1_throw.cpp : LIB1_SOURCE=1 shared:LIB1_DYN_LINK=1 : : shared:LIB1_DYN_LINK=1 ; lib lib2_throw : lib2_throw.cpp : LIB2_SOURCE=1 shared:LIB2_DYN_LINK=1 : : shared:LIB2_DYN_LINK=1 ; lib lib3_throw : lib3_throw.cpp : LIB3_SOURCE=1 shared:LIB3_DYN_LINK=1 : : shared:LIB3_DYN_LINK=1 ; +lib lib4_throw : lib4_throw.cpp : LIB4_SOURCE=1 shared:LIB4_DYN_LINK=1 : : shared:LIB4_DYN_LINK=1 ; -run throw_from_library_test.cpp lib1_throw lib2_throw lib3_throw : : : static : throw_from_library_static ; -run throw_from_library_test.cpp lib1_throw lib2_throw lib3_throw : : : shared : throw_from_library_shared ; +run throw_from_library_test.cpp lib1_throw lib2_throw lib3_throw lib4_throw : : : static : throw_from_library_static ; +run throw_from_library_test.cpp lib1_throw lib2_throw lib3_throw lib4_throw : : : shared : throw_from_library_shared ; run throw_exception_nx_test.cpp : : : off ; run throw_exception_nx_test2.cpp : : : off ; @@ -44,3 +45,9 @@ run make_exception_ptr_test2.cpp ; run make_exception_ptr_nx_test.cpp : : : off ; run make_exception_ptr_nx_test2.cpp : : : off ; + +run throw_with_location_test.cpp ; +run throw_with_location_test2.cpp ; +run throw_with_location_test3.cpp ; + +run throw_with_location_nx_test.cpp : : : off ; diff --git a/test/lib4_throw.cpp b/test/lib4_throw.cpp new file mode 100644 index 0000000..9014002 --- /dev/null +++ b/test/lib4_throw.cpp @@ -0,0 +1,14 @@ +// Copyright 2018, 2022 Peter Dimov +// +// 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 + +#include "lib4_throw.hpp" +#include + +void lib4::f() +{ + boost::throw_with_location( lib4::exception() ); +} diff --git a/test/lib4_throw.hpp b/test/lib4_throw.hpp new file mode 100644 index 0000000..67bc03f --- /dev/null +++ b/test/lib4_throw.hpp @@ -0,0 +1,35 @@ +#ifndef LIB4_THROW_HPP_INCLUDED +#define LIB4_THROW_HPP_INCLUDED + +// Copyright 2018, 2022 Peter Dimov +// +// 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 + +#include +#include + +#if defined(LIB4_DYN_LINK) +# if defined(LIB4_SOURCE) +# define LIB4_DECL BOOST_SYMBOL_EXPORT +# else +# define LIB4_DECL BOOST_SYMBOL_IMPORT +# endif +#else +# define LIB4_DECL +#endif + +namespace lib4 +{ + +struct BOOST_SYMBOL_VISIBLE exception: public std::exception +{ +}; + +LIB4_DECL void f(); + +} // namespace lib4 + +#endif // #ifndef LIB4_THROW_HPP_INCLUDED diff --git a/test/throw_from_library_test.cpp b/test/throw_from_library_test.cpp index af2a673..8690a8b 100644 --- a/test/throw_from_library_test.cpp +++ b/test/throw_from_library_test.cpp @@ -20,6 +20,7 @@ #include "lib1_throw.hpp" #include "lib2_throw.hpp" #include "lib3_throw.hpp" +#include "lib4_throw.hpp" #include #include #include @@ -30,6 +31,7 @@ void test_catch_by_type() BOOST_TEST_THROWS( lib1::f(), lib1::exception ); BOOST_TEST_THROWS( lib2::f(), lib2::exception ); BOOST_TEST_THROWS( lib3::f(), lib3::exception ); + BOOST_TEST_THROWS( lib4::f(), lib4::exception ); } void test_catch_by_exception() @@ -78,6 +80,25 @@ void test_throw_line() BOOST_TEST( line != 0 ); BOOST_TEST_EQ( *line, 13 ); } + catch( ... ) + { + BOOST_ERROR( "lib3::f failed to throw boost::exception" ); + } + + try + { + lib4::f(); + } + catch( std::exception const & x ) + { + boost::source_location loc = boost::get_throw_location( x ); + + BOOST_TEST_NE( loc.line(), 0 ); + } + catch( ... ) + { + BOOST_ERROR( "lib4::f failed to throw std::exception" ); + } } int main() diff --git a/test/throw_with_location_nx_test.cpp b/test/throw_with_location_nx_test.cpp new file mode 100644 index 0000000..e93e600 --- /dev/null +++ b/test/throw_with_location_nx_test.cpp @@ -0,0 +1,30 @@ +// Copyright 2019, 2022 Peter Dimov +// Distributed under the Boost Software License, Version 1.0. +// http://www.boost.org/LICENSE_1_0.txt + +#if defined(_MSC_VER) +# pragma warning(disable: 4702) // unreachable code +# pragma warning(disable: 4577) // noexcept used without /EHsc +# pragma warning(disable: 4530) // C++ exception handler used +#endif + +#include +#include + +class my_exception: public std::exception {}; + +int main() +{ + boost::throw_with_location( my_exception() ); + return 1; +} + +namespace boost +{ + +void throw_exception( std::exception const &, boost::source_location const & ) +{ + std::exit( 0 ); +} + +} // namespace boost diff --git a/test/throw_with_location_test.cpp b/test/throw_with_location_test.cpp new file mode 100644 index 0000000..e225440 --- /dev/null +++ b/test/throw_with_location_test.cpp @@ -0,0 +1,22 @@ +// Copyright 2022 Peter Dimov +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include + +#if defined(_MSC_VER) +# pragma warning(disable: 4702) // unreachable code +#endif + +class my_exception: public std::exception +{ +}; + +int main() +{ + BOOST_TEST_THROWS( boost::throw_with_location( my_exception() ), my_exception ); + BOOST_TEST_THROWS( boost::throw_with_location( my_exception() ), std::exception ); + + return boost::report_errors(); +} diff --git a/test/throw_with_location_test2.cpp b/test/throw_with_location_test2.cpp new file mode 100644 index 0000000..d52a3cd --- /dev/null +++ b/test/throw_with_location_test2.cpp @@ -0,0 +1,64 @@ +// Copyright 2022 Peter Dimov +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include + +#if defined(_MSC_VER) +# pragma warning(disable: 4702) // unreachable code +#endif + +class my_exception: public std::exception +{ +}; + +int main() +{ + try + { + boost::throw_with_location( my_exception() ); + + BOOST_ERROR( "boost::throw_with_location failed to throw" ); + } + catch( std::exception const & x ) + { + boost::source_location loc = boost::get_throw_location( x ); + + // When not supplied explicitly, the source location is best effort. + // It should be the location of the throw_with_location call on + // recent compilers, but that's not guaranteed for every compiler. + // So we can't be more specific in testing it. + + BOOST_TEST_CSTR_NE( loc.file_name(), "" ); + BOOST_TEST_NE( loc.line(), 0 ); + } + catch( ... ) + { + BOOST_ERROR( "boost::throw_with_location failed to throw std::exception" ); + } + + boost::source_location location = BOOST_CURRENT_LOCATION; + + try + { + boost::throw_with_location( my_exception(), location ); + + BOOST_ERROR( "boost::throw_with_location failed to throw" ); + } + catch( std::exception const & x ) + { + boost::source_location loc = boost::get_throw_location( x ); + + BOOST_TEST_CSTR_EQ( loc.file_name(), location.file_name() ); + BOOST_TEST_CSTR_EQ( loc.function_name(), location.function_name() ); + BOOST_TEST_EQ( loc.line(), location.line() ); + BOOST_TEST_EQ( loc.column(), location.column() ); + } + catch( ... ) + { + BOOST_ERROR( "boost::throw_with_location failed to throw std::exception" ); + } + + return boost::report_errors(); +} diff --git a/test/throw_with_location_test3.cpp b/test/throw_with_location_test3.cpp new file mode 100644 index 0000000..c37071f --- /dev/null +++ b/test/throw_with_location_test3.cpp @@ -0,0 +1,33 @@ +// Copyright 2022 Peter Dimov +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include + +#if defined(_MSC_VER) +# pragma warning(disable: 4702) // unreachable code +#endif + +class my_exception: public std::exception +{ +}; + +int main() +{ + try + { + throw my_exception(); + } + catch( std::exception const & x ) + { + boost::source_location loc = boost::get_throw_location( x ); + + BOOST_TEST_CSTR_EQ( loc.file_name(), "" ); + BOOST_TEST_CSTR_EQ( loc.function_name(), "" ); + BOOST_TEST_EQ( loc.line(), 0 ); + BOOST_TEST_EQ( loc.column(), 0 ); + } + + return boost::report_errors(); +}