[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[lmi-commits] [lmi] master 6ceb6c0 1/2: Resolve more '-Wconversion' issu
From: |
Greg Chicares |
Subject: |
[lmi-commits] [lmi] master 6ceb6c0 1/2: Resolve more '-Wconversion' issues |
Date: |
Wed, 30 May 2018 22:21:03 -0400 (EDT) |
branch: master
commit 6ceb6c0ba5b6650d12d39be9c89b31f989a77a69
Author: Gregory W. Chicares <address@hidden>
Commit: Gregory W. Chicares <address@hidden>
Resolve more '-Wconversion' issues
* bourn_cast.hpp: Intruded static_cast into the integral-to-floating
conversion, giving the rationale in a comment block. Incidentally
aligned range comparisons thus:
if(x < y)
if( y < z)
to make it easier to see that 'y' is the same when it's a complicated
expression. Similarly, added a static_cast to the floating-to-integral
code, making it look more like 'narrow_cast' in TC++PL4 [11.5].
* bourn_cast_test.cpp: Suppressed compiler warnings with pragmata. The
static_cast workaround seemed less appealing here, in particular because
one test converts a value both explicitly (with static_cast) and
implicitly, then compares the converted values. (Perhaps that test can
never fail, but, this close to the edge of UB, it could conceivably find
a compiler defect.)
---
bourn_cast.hpp | 18 +++++++++++++-----
bourn_cast_test.cpp | 14 ++++++++++++++
2 files changed, 27 insertions(+), 5 deletions(-)
diff --git a/bourn_cast.hpp b/bourn_cast.hpp
index 407649a..b48e443 100644
--- a/bourn_cast.hpp
+++ b/bourn_cast.hpp
@@ -83,7 +83,7 @@ constexpr inline To bourn_cast(From from, std::false_type,
std::false_type)
? -to_traits::infinity()
: to_traits::infinity()
;
- if(from < to_traits::lowest())
+ if( from < to_traits::lowest())
throw std::runtime_error("Cast would transgress lower limit.");
if(to_traits::max() < from)
throw std::runtime_error("Cast would transgress upper limit.");
@@ -91,6 +91,15 @@ constexpr inline To bourn_cast(From from, std::false_type,
std::false_type)
}
/// Integral to floating.
+///
+/// The inequality comparisons in the 'if' statements cannot exhibit
+/// UB because of the static assertion immediately preceding them.
+/// Writing static_cast in these comparisons looks unnatural, because
+/// it doesn't change the outcome (without it, integral-to-floating
+/// conversion would take place anyway); it serves only to suppress
+/// compiler warnings, for which purpose it seems less unnatural (and
+/// is certainly more portable) than surrounding the 'if' statements
+/// with pragmata.
template<typename To, typename From>
constexpr inline To bourn_cast(From from, std::false_type, std::true_type)
@@ -99,12 +108,11 @@ constexpr inline To bourn_cast(From from, std::false_type,
std::true_type)
using from_traits = std::numeric_limits<From>;
static_assert(!to_traits::is_integer && from_traits::is_integer);
- // If this assertion fails, the comparisons below may be UB.
static_assert(from_traits::digits < to_traits::max_exponent);
- if(from < to_traits::lowest())
+ if( static_cast<To>(from) < to_traits::lowest())
throw std::runtime_error("Cast would transgress lower limit.");
- if(to_traits::max() < from)
+ if(to_traits::max() < static_cast<To>(from))
throw std::runtime_error("Cast would transgress upper limit.");
return static_cast<To>(from);
}
@@ -180,7 +188,7 @@ constexpr inline To bourn_cast(From from, std::true_type,
std::false_type)
if(limit <= from)
throw std::runtime_error("Cast would transgress upper limit.");
To const r = static_cast<To>(from);
- if(r != from)
+ if(static_cast<From>(r) != from)
{
throw std::runtime_error("Cast would not preserve value.");
}
diff --git a/bourn_cast_test.cpp b/bourn_cast_test.cpp
index ed360bb..8fc25ba 100644
--- a/bourn_cast_test.cpp
+++ b/bourn_cast_test.cpp
@@ -463,7 +463,14 @@ void test_m64_neighborhood()
// unsigned integer is UB.
unsigned long long int const ull_max = ull_traits::max();
+#if defined __GNUC__
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wfloat-conversion"
+#endif // defined __GNUC__
float const f_ull_max = ull_max;
+#if defined __GNUC__
+# pragma GCC diagnostic pop
+#endif // defined __GNUC__
BOOST_TEST(f_ull_max == static_cast<float>(ull_max));
// Suppressed because behavior is undefined:
// BOOST_TEST(ull_max == static_cast<unsigned long long int>(f_ull_max));
@@ -495,8 +502,15 @@ void test_m64_neighborhood()
// about half a trillion units.
double const d_2_64 = nonstd::power(2.0, 64);
+#if defined __GNUC__
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wfloat-conversion"
+#endif // defined __GNUC__
double const d_interesting = 0.5 * (d_2_64 + std::nextafterf(d_2_64, 0));
unsigned long long int const ull_interesting = d_interesting;
+#if defined __GNUC__
+# pragma GCC diagnostic pop
+#endif // defined __GNUC__
float const f_interesting = bourn_cast<float>(ull_interesting);
BOOST_TEST_THROW
(bourn_cast<unsigned long long int>(f_interesting)