From 25d880f5ebc1e22ea0c85c86ac6f4a2358107f6d Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Sat, 25 Feb 2012 16:58:46 +0000 Subject: [PATCH] Updates #5800 (partially fix lexical cast compilation with disabled exceptions) [SVN r77116] --- doc/lexical_cast.qbk | 7 +- include/boost/lexical_cast.hpp | 88 ++++++++++------------ test/Jamfile.v2 | 5 +- test/lexical_cast_no_exceptions_test.cpp | 95 ++++++++++++++++++++++++ 4 files changed, 145 insertions(+), 50 deletions(-) create mode 100755 test/lexical_cast_no_exceptions_test.cpp diff --git a/doc/lexical_cast.qbk b/doc/lexical_cast.qbk index 4715803..5d45446 100644 --- a/doc/lexical_cast.qbk +++ b/doc/lexical_cast.qbk @@ -3,7 +3,7 @@ [version 1.0] [copyright 2000-2005 Kevlin Henney] [copyright 2006-2010 Alexander Nasonov] - [copyright 2011 Antony Polukhin] + [copyright 2011-2012 Antony Polukhin] [category String and text processing] [category Miscellaneous] [license @@ -170,6 +170,11 @@ limitation of compiler options that you use. [endsect] [section Changes] +* [*boost 1.50.0 :] + + * `boost::bad_lexical_cast` exception is now globaly visible and can be catched even if code is compiled with -fvisibility=hidden. + * Now it is possible to compile library with disabled exceptions. + * [*boost 1.49.0 :] * Restored work with typedefed wchar_t (compilation flag /Zc:wchar_t- for Visual Studio). diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index 398fa25..a68152b 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -104,7 +104,7 @@ _CRTIMP int __cdecl vswprintf(wchar_t * __restrict__ , const wchar_t * __restric namespace boost { // exception used to indicate runtime lexical_cast failure - class bad_lexical_cast : + class BOOST_SYMBOL_VISIBLE bad_lexical_cast : // workaround MSVC bug with std::bad_cast when _HAS_EXCEPTIONS == 0 #if defined(BOOST_MSVC) && defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS public std::exception @@ -1958,52 +1958,52 @@ namespace boost } }; - class precision_loss_error : public boost::numeric::bad_numeric_cast + template + struct detect_precision_loss { - public: - virtual const char * what() const throw() - { return "bad numeric conversion: precision loss error"; } - }; + typedef boost::numeric::Trunc Rounder; + typedef Source source_type ; - template - struct throw_on_precision_loss - { - typedef boost::numeric::Trunc Rounder; - typedef S source_type ; - - typedef typename mpl::if_< is_arithmetic,S,S const&>::type argument_type ; + typedef BOOST_DEDUCED_TYPENAME mpl::if_< + is_arithmetic, Source, Source const& + >::type argument_type ; static source_type nearbyint ( argument_type s ) { - source_type orig_div_round = s / Rounder::nearbyint(s); + const source_type orig_div_round = s / Rounder::nearbyint(s); + const source_type eps = std::numeric_limits::epsilon(); + + if ((orig_div_round > 1 ? orig_div_round - 1 : 1 - orig_div_round) > eps) + BOOST_LCAST_THROW_BAD_CAST(Source, Target); - if ( (orig_div_round > 1 ? orig_div_round - 1 : 1 - orig_div_round) > std::numeric_limits::epsilon() ) - BOOST_THROW_EXCEPTION( precision_loss_error() ); return s ; } typedef typename Rounder::round_style round_style; } ; + template + struct nothrow_overflow_handler + { + void operator() ( boost::numeric::range_check_result r ) + { + if (r != boost::numeric::cInRange) + BOOST_LCAST_THROW_BAD_CAST(Source, Target); + } + } ; + template struct lexical_cast_dynamic_num_not_ignoring_minus { static inline Target lexical_cast_impl(const Source &arg) { - try{ - typedef boost::numeric::converter< - Target, - Source, - boost::numeric::conversion_traits, - boost::numeric::def_overflow_handler, - throw_on_precision_loss - > Converter ; - - return Converter::convert(arg); - } catch( ::boost::numeric::bad_numeric_cast const& ) { - BOOST_LCAST_THROW_BAD_CAST(Source, Target); - } - BOOST_UNREACHABLE_RETURN(static_cast(0)); + return boost::numeric::converter< + Target, + Source, + boost::numeric::conversion_traits, + nothrow_overflow_handler, + detect_precision_loss + >::convert(arg); } }; @@ -2012,25 +2012,17 @@ namespace boost { static inline Target lexical_cast_impl(const Source &arg) { - try{ - typedef boost::numeric::converter< - Target, - Source, - boost::numeric::conversion_traits, - boost::numeric::def_overflow_handler, - throw_on_precision_loss - > Converter ; + typedef boost::numeric::converter< + Target, + Source, + boost::numeric::conversion_traits, + nothrow_overflow_handler, + detect_precision_loss + > converter_t; - bool has_minus = ( arg < 0); - if ( has_minus ) { - return static_cast(-Converter::convert(-arg)); - } else { - return Converter::convert(arg); - } - } catch( ::boost::numeric::bad_numeric_cast const& ) { - BOOST_LCAST_THROW_BAD_CAST(Source, Target); - } - BOOST_UNREACHABLE_RETURN(static_cast(0)); + return ( + arg < 0 ? -converter_t::convert(-arg) : converter_t::convert(arg) + ); } }; diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 0618516..5078436 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -39,5 +39,8 @@ test-suite conversion [ compile lexical_cast_typedefed_wchar_test.cpp : msvc:on ] [ run lexical_cast_typedefed_wchar_test_runtime.cpp ../../test/build//boost_unit_test_framework/static : : : msvc:on ] [ run lexical_cast_no_locale_test.cpp ../../test/build//boost_unit_test_framework/static : : : BOOST_NO_STD_LOCALE ] + [ run lexical_cast_no_exceptions_test.cpp ../../test/build//boost_unit_test_framework/static : : : BOOST_NO_EXCEPTIONS ] ; - +#Add missing flags, when numeric_cast compilation with exceptions disabled will be fixed: +# [ run lexical_cast_no_exceptions_test.cpp ../../test/build//boost_unit_test_framework/static : : : BOOST_NO_EXCEPTIONS gcc:-fno-exceptions ] + diff --git a/test/lexical_cast_no_exceptions_test.cpp b/test/lexical_cast_no_exceptions_test.cpp new file mode 100755 index 0000000..8431c3a --- /dev/null +++ b/test/lexical_cast_no_exceptions_test.cpp @@ -0,0 +1,95 @@ +// Unit test for boost::lexical_cast. +// +// See http://www.boost.org for most recent version, including documentation. +// +// Copyright Antony Polukhin, 2012. +// +// 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 + +#if defined(__INTEL_COMPILER) +#pragma warning(disable: 193 383 488 981 1418 1419) +#elif defined(BOOST_MSVC) +#pragma warning(disable: 4097 4100 4121 4127 4146 4244 4245 4511 4512 4701 4800) +#endif + +#include +#include +#include + +#ifndef BOOST_NO_EXCEPTIONS +#error "This test must be compiled with -DBOOST_NO_EXCEPTIONS" +#endif + +bool g_was_exception = false; + +namespace boost { + +void throw_exception(std::exception const & ) { + g_was_exception = true; +} + +} + +using namespace boost; + + +struct Escape +{ + Escape(){} + Escape(const std::string& s) + : str_(s) + {} + + std::string str_; +}; + +inline std::ostream& operator<< (std::ostream& o, const Escape& rhs) +{ + return o << rhs.str_; +} + +inline std::istream& operator>> (std::istream& i, Escape& rhs) +{ + return i >> rhs.str_; +} + +void test_exceptions_off() +{ + Escape v(""); + + g_was_exception = false; + lexical_cast(v); + BOOST_CHECK(g_was_exception); + + g_was_exception = false; + lexical_cast(v); + BOOST_CHECK(g_was_exception); + + v = lexical_cast(100); + BOOST_CHECK_EQUAL(lexical_cast(v), 100); + BOOST_CHECK_EQUAL(lexical_cast(v), 100u); + + v = lexical_cast(0.0); + BOOST_CHECK_EQUAL(lexical_cast(v), 0.0); + + BOOST_CHECK_EQUAL(lexical_cast(100), 100); + BOOST_CHECK_EQUAL(lexical_cast(0.0), 0.0); + + g_was_exception = false; + lexical_cast(700000); + BOOST_CHECK(g_was_exception); +} + +unit_test::test_suite *init_unit_test_suite(int, char *[]) +{ + unit_test::test_suite *suite = + BOOST_TEST_SUITE("lexical_cast. Testing with BOOST_NO_EXCEPTIONS"); + suite->add(BOOST_TEST_CASE(&test_exceptions_off)); + + return suite; +} +