diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index 62dca33..94dbaf9 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -767,26 +767,15 @@ namespace boost { namespace detail // lcast_to_unsigned { -#if (defined _MSC_VER) -# pragma warning( push ) -// C4146: unary minus operator applied to unsigned type, result still unsigned -# pragma warning( disable : 4146 ) -#elif defined( __BORLANDC__ ) -# pragma option push -w-8041 -#endif template inline BOOST_DEDUCED_TYPENAME make_unsigned::type lcast_to_unsigned(T value) BOOST_NOEXCEPT { - typedef BOOST_DEDUCED_TYPENAME make_unsigned::type result_type; - const result_type uvalue = static_cast(value); - return value < 0 ? -uvalue : uvalue; + typedef BOOST_DEDUCED_TYPENAME boost::make_unsigned::type result_type; + return static_cast( + value < 0 ? 0u - static_cast(value) : value + ); } -#if (defined _MSC_VER) -# pragma warning( pop ) -#elif defined( __BORLANDC__ ) -# pragma option pop -#endif } namespace detail // lcast_put_unsigned @@ -1825,19 +1814,11 @@ namespace boost { } bool const succeed = lcast_ret_unsigned(output, start, finish); -#if (defined _MSC_VER) -# pragma warning( push ) -// C4146: unary minus operator applied to unsigned type, result still unsigned -# pragma warning( disable : 4146 ) -#elif defined( __BORLANDC__ ) -# pragma option push -w-8041 -#endif - if (has_minus) output = static_cast(-output); -#if (defined _MSC_VER) -# pragma warning( pop ) -#elif defined( __BORLANDC__ ) -# pragma option pop -#endif + + if (has_minus) { + output = static_cast(0u - output); + } + return succeed; } @@ -1863,21 +1844,9 @@ namespace boost { bool succeed = lcast_ret_unsigned(out_tmp, start, finish); if (has_minus) { -#if (defined _MSC_VER) -# pragma warning( push ) -// C4146: unary minus operator applied to unsigned type, result still unsigned -# pragma warning( disable : 4146 ) -#elif defined( __BORLANDC__ ) -# pragma option push -w-8041 -#endif - utype const comp_val = static_cast(-(std::numeric_limits::min)()); + utype const comp_val = (static_cast(1) << std::numeric_limits::digits); succeed = succeed && out_tmp<=comp_val; - output = -out_tmp; -#if (defined _MSC_VER) -# pragma warning( pop ) -#elif defined( __BORLANDC__ ) -# pragma option pop -#endif + output = static_cast(0u - out_tmp); } else { utype const comp_val = static_cast((std::numeric_limits::max)()); succeed = succeed && out_tmp<=comp_val; @@ -2295,11 +2264,14 @@ namespace boost { static source_type nearbyint ( argument_type s ) { - const source_type orig_div_round = s / Rounder::nearbyint(s); - const source_type eps = std::numeric_limits::epsilon(); + const source_type near_int = Rounder::nearbyint(s); + if (near_int) { + const source_type orig_div_round = s / near_int; + 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) > eps) + BOOST_LCAST_THROW_BAD_CAST(Source, Target); + } return s ; } @@ -2337,16 +2309,22 @@ namespace boost { { static inline Target lexical_cast_impl(const Source &arg) { + typedef BOOST_DEDUCED_TYPENAME boost::mpl::eval_if_c< + boost::is_float::value, + boost::mpl::identity, + boost::make_unsigned + >::type usource_t; + typedef boost::numeric::converter< Target, - Source, - boost::numeric::conversion_traits, - nothrow_overflow_handler, - detect_precision_loss + usource_t, + boost::numeric::conversion_traits, + nothrow_overflow_handler, + detect_precision_loss > converter_t; return ( - arg < 0 ? -converter_t::convert(-arg) : converter_t::convert(arg) + arg < 0 ? 0u - converter_t::convert(0u - arg) : converter_t::convert(arg) ); } }; diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index ea13e64..5b1447f 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -12,7 +12,9 @@ project : requirements /boost/test//boost_unit_test_framework static - gcc-4.8:BOOST_STL_SUPPORTS_NEW_UNICODE_LOCALES + gcc-4.7:-ftrapv + gcc-4.6:-ftrapv + clang:-ftrapv ; # Thanks to Steven Watanabe for helping with feature @@ -40,11 +42,13 @@ test-suite conversion [ run lexical_cast_typedefed_wchar_test_runtime.cpp : : : msvc:on msvc,stlport:no ] [ run lexical_cast_no_locale_test.cpp : : : BOOST_NO_STD_LOCALE BOOST_LEXICAL_CAST_ASSUME_C_LOCALE ] [ run lexical_cast_no_exceptions_test.cpp : : : BOOST_NO_EXCEPTIONS - gcc-4.3:-fno-exceptions - gcc-4.4:-fno-exceptions - gcc-4.5:-fno-exceptions - gcc-4.6:-fno-exceptions - gcc-4.7:-fno-exceptions + gcc-4.3:-fno-exceptions + gcc-4.4:-fno-exceptions + gcc-4.5:-fno-exceptions + gcc-4.6:-fno-exceptions + gcc-4.7:-fno-exceptions + gcc-4.8:-fno-exceptions + clang:-fno-exceptions ] [ run lexical_cast_iterator_range_test.cpp ] [ run lexical_cast_arrays_test.cpp ] diff --git a/test/lexical_cast_integral_types_test.cpp b/test/lexical_cast_integral_types_test.cpp index 7139ee6..b34cdc4 100644 --- a/test/lexical_cast_integral_types_test.cpp +++ b/test/lexical_cast_integral_types_test.cpp @@ -68,6 +68,7 @@ void test_conversion_from_to_uintmax_t(); void test_conversion_from_to_longlong(); void test_conversion_from_to_ulonglong(); #endif +void test_integral_conversions_on_min_max(); unit_test::test_suite *init_unit_test_suite(int, char *[]) @@ -87,6 +88,7 @@ unit_test::test_suite *init_unit_test_suite(int, char *[]) suite->add(BOOST_TEST_CASE(&test_conversion_from_to_longlong)); suite->add(BOOST_TEST_CASE(&test_conversion_from_to_ulonglong)); #endif + suite->add(BOOST_TEST_CASE(&test_integral_conversions_on_min_max)); return suite; } @@ -230,7 +232,7 @@ void test_conversion_from_integral_to_string(CharT) // Test values around 100, 1000, 10000, ... T ten_power = 100; - for(int e = 2; e <= limits::digits10; ++e, ten_power *= 10) + for(int e = 2; e < limits::digits10; ++e, ten_power *= 10) { // ten_power + 100 probably never overflows for(t = ten_power - 100; t != ten_power + 100; ++t) @@ -327,7 +329,7 @@ void test_conversion_from_string_to_integral(CharT) // Test values around 100, 1000, 10000, ... T ten_power = 100; - for(int e = 2; e <= limits::digits10; ++e, ten_power *= 10) + for(int e = 2; e < limits::digits10; ++e, ten_power *= 10) { // ten_power + 100 probably never overflows for(t = ten_power - 100; t != ten_power + 100; ++t) @@ -534,6 +536,19 @@ void test_conversion_from_to_ulonglong() #endif - +void test_integral_conversions_on_min_max() +{ + typedef std::numeric_limits int_limits; + typedef std::numeric_limits uint_limits; + + BOOST_CHECK_EQUAL(lexical_cast((uint_limits::max)()), (uint_limits::max)()); + BOOST_CHECK_EQUAL(lexical_cast((uint_limits::min)()), (uint_limits::min)()); + + BOOST_CHECK_EQUAL(lexical_cast((int_limits::max)()), (int_limits::max)()); + BOOST_CHECK_EQUAL(lexical_cast((uint_limits::min)()), static_cast((uint_limits::min)())); + + BOOST_CHECK_EQUAL(lexical_cast((int_limits::max)()), static_cast((int_limits::max)())); + BOOST_CHECK_EQUAL(lexical_cast((int_limits::min)()), static_cast((int_limits::min)())); +}