Resolve integer overflow warnings in GCD and LCM tests

lcm.pass.cpp:
19: Update headers to that actually used in the test.
41: test0 was triggering narrowing warnings for all callers, because the
inputs were always ints, but some of the explicit template arguments were
smaller than that. Instead, have this function accept ints and static_cast
explicitly to the types we want before calling std::lcm.
47: Replace unnecessary ternary.
55: Use foo_t instead of typename foo<>::type
111/116: intX_t were not std::qualified but only <cfoo> headers were included.
141: C1XX has a bug where it interprets 2147483648 as unsigned int. Then the
negation trips "negation of unsigned value, result still unsigned" warnings.
Perma-workaround this issue by saying INT_MIN, which better documents the
intended behavior and avoids triggering warnings on C1XX.

gcd.pass.cpp:
Same changes as lcm.pass.cpp but for GCD.

llvm-svn: 302472
This commit is contained in:
Billy Robert O'Neal III 2017-05-08 21:52:05 +00:00
parent 58a2e0d90b
commit 8c401179a3
2 changed files with 52 additions and 42 deletions

View File

@ -16,8 +16,10 @@
#include <numeric> #include <numeric>
#include <cassert> #include <cassert>
#include <climits>
#include <cstdint>
#include <cstdlib> // for rand() #include <cstdlib> // for rand()
#include <iostream> #include <type_traits>
constexpr struct { constexpr struct {
int x; int x;
@ -36,21 +38,24 @@ constexpr struct {
template <typename Input1, typename Input2, typename Output> template <typename Input1, typename Input2, typename Output>
constexpr bool test0(Input1 in1, Input2 in2, Output out) constexpr bool test0(int in1, int in2, int out)
{ {
static_assert((std::is_same<Output, decltype(std::gcd(in1, in2))>::value), "" ); auto value1 = static_cast<Input1>(in1);
static_assert((std::is_same<Output, decltype(std::gcd(in2, in1))>::value), "" ); auto value2 = static_cast<Input2>(in2);
return out == std::gcd(in1, in2) ? true : (std::abort(), false); static_assert(std::is_same_v<Output, decltype(std::gcd(value1, value2))>, "");
static_assert(std::is_same_v<Output, decltype(std::gcd(value2, value1))>, "");
assert(static_cast<Output>(out) == std::gcd(value1, value2));
return true;
} }
template <typename Input1, typename Input2 = Input1> template <typename Input1, typename Input2 = Input1>
constexpr bool do_test(int = 0) constexpr bool do_test(int = 0)
{ {
using S1 = typename std::make_signed<Input1>::type; using S1 = std::make_signed_t<Input1>;
using S2 = typename std::make_signed<Input2>::type; using S2 = std::make_signed_t<Input2>;
using U1 = typename std::make_unsigned<Input1>::type; using U1 = std::make_unsigned_t<Input1>;
using U2 = typename std::make_unsigned<Input2>::type; using U2 = std::make_unsigned_t<Input2>;
bool accumulate = true; bool accumulate = true;
for (auto TC : Cases) { for (auto TC : Cases) {
{ // Test with two signed types { // Test with two signed types
@ -103,15 +108,15 @@ int main()
assert(do_test<long>(non_cce)); assert(do_test<long>(non_cce));
assert(do_test<long long>(non_cce)); assert(do_test<long long>(non_cce));
static_assert(do_test< int8_t>(), ""); static_assert(do_test<std::int8_t>(), "");
static_assert(do_test<int16_t>(), ""); static_assert(do_test<std::int16_t>(), "");
static_assert(do_test<int32_t>(), ""); static_assert(do_test<std::int32_t>(), "");
static_assert(do_test<int64_t>(), ""); static_assert(do_test<std::int64_t>(), "");
assert(do_test< int8_t>(non_cce)); assert(do_test<std::int8_t>(non_cce));
assert(do_test<int16_t>(non_cce)); assert(do_test<std::int16_t>(non_cce));
assert(do_test<int32_t>(non_cce)); assert(do_test<std::int32_t>(non_cce));
assert(do_test<int64_t>(non_cce)); assert(do_test<std::int64_t>(non_cce));
static_assert(do_test<signed char, int>(), ""); static_assert(do_test<signed char, int>(), "");
static_assert(do_test<int, signed char>(), ""); static_assert(do_test<int, signed char>(), "");
@ -133,8 +138,8 @@ int main()
// LWG#2837 // LWG#2837
{ {
auto res = std::gcd((int64_t)1234, (int32_t)-2147483648); auto res = std::gcd(static_cast<std::int64_t>(1234), INT32_MIN);
static_assert( std::is_same<decltype(res), std::common_type<int64_t, int32_t>::type>::value, ""); static_assert(std::is_same_v<decltype(res), std::int64_t>, "");
assert(res == 2); assert(res == 2);
} }
} }

View File

@ -11,12 +11,14 @@
// <numeric> // <numeric>
// template<class _M, class _N> // template<class _M, class _N>
// constexpr common_type_t<_M,_N> gcd(_M __m, _N __n) // constexpr common_type_t<_M,_N> lcm(_M __m, _N __n)
#include <numeric> #include <numeric>
#include <cassert> #include <cassert>
#include <climits>
#include <cstdint>
#include <cstdlib> #include <cstdlib>
#include <iostream> #include <type_traits>
constexpr struct { constexpr struct {
int x; int x;
@ -34,21 +36,24 @@ constexpr struct {
}; };
template <typename Input1, typename Input2, typename Output> template <typename Input1, typename Input2, typename Output>
constexpr bool test0(Input1 in1, Input2 in2, Output out) constexpr bool test0(int in1, int in2, int out)
{ {
static_assert((std::is_same<Output, decltype(std::lcm(Input1(0), Input2(0)))>::value), "" ); auto value1 = static_cast<Input1>(in1);
static_assert((std::is_same<Output, decltype(std::lcm(Input2(0), Input1(0)))>::value), "" ); auto value2 = static_cast<Input2>(in2);
return out == std::lcm(in1, in2) ? true : (std::abort(), false); static_assert(std::is_same_v<Output, decltype(std::lcm(value1, value2))>, "");
static_assert(std::is_same_v<Output, decltype(std::lcm(value2, value1))>, "");
assert(static_cast<Output>(out) == std::lcm(value1, value2));
return true;
} }
template <typename Input1, typename Input2 = Input1> template <typename Input1, typename Input2 = Input1>
constexpr bool do_test(int = 0) constexpr bool do_test(int = 0)
{ {
using S1 = typename std::make_signed<Input1>::type; using S1 = std::make_signed_t<Input1>;
using S2 = typename std::make_signed<Input2>::type; using S2 = std::make_signed_t<Input2>;
using U1 = typename std::make_unsigned<Input1>::type; using U1 = std::make_unsigned_t<Input1>;
using U2 = typename std::make_unsigned<Input2>::type; using U2 = std::make_unsigned_t<Input2>;
bool accumulate = true; bool accumulate = true;
for (auto TC : Cases) { for (auto TC : Cases) {
{ // Test with two signed types { // Test with two signed types
@ -101,15 +106,15 @@ int main()
assert(do_test<long>(non_cce)); assert(do_test<long>(non_cce));
assert(do_test<long long>(non_cce)); assert(do_test<long long>(non_cce));
static_assert(do_test< int8_t>(), ""); static_assert(do_test<std::int8_t>(), "");
static_assert(do_test<int16_t>(), ""); static_assert(do_test<std::int16_t>(), "");
static_assert(do_test<int32_t>(), ""); static_assert(do_test<std::int32_t>(), "");
static_assert(do_test<int64_t>(), ""); static_assert(do_test<std::int64_t>(), "");
assert(do_test< int8_t>(non_cce)); assert(do_test<std::int8_t>(non_cce));
assert(do_test<int16_t>(non_cce)); assert(do_test<std::int16_t>(non_cce));
assert(do_test<int32_t>(non_cce)); assert(do_test<std::int32_t>(non_cce));
assert(do_test<int64_t>(non_cce)); assert(do_test<std::int64_t>(non_cce));
static_assert(do_test<signed char, int>(), ""); static_assert(do_test<signed char, int>(), "");
static_assert(do_test<int, signed char>(), ""); static_assert(do_test<int, signed char>(), "");
@ -131,9 +136,9 @@ int main()
// LWG#2837 // LWG#2837
{ {
auto res1 = std::lcm((int64_t)1234, (int32_t)-2147483648); auto res1 = std::lcm(static_cast<std::int64_t>(1234), INT32_MIN);
(void) std::lcm<int, unsigned long>(INT_MIN, 2); // this used to trigger UBSAN (void)std::lcm(INT_MIN, 2UL); // this used to trigger UBSAN
static_assert( std::is_same<decltype(res1), std::common_type<int64_t, int32_t>::type>::value, ""); static_assert(std::is_same_v<decltype(res1), std::int64_t>, "");
assert(res1 == 1324997410816LL); assert(res1 == 1324997410816LL);
} }
} }