std::abs isn't suitable for these functions because we need something that works in constexpr functions and with unsigned types.
Also, <experimental/numeric> is supposed to include <numeric>. PR libstdc++/77801 * include/experimental/numeric: Include <numeric>. (__abs): Define. (gcd, lcm): Use __abs instead of std::abs. * testsuite/experimental/numeric/77801.cc: New test. * testsuite/experimental/numeric/gcd.cc: Test unsigned inputs. * testsuite/experimental/numeric/lcm.cc: Likewise. Tested powerpc64le-linux, committed to trunk. Backport to gcc-6 coming too.
commit 49396c6b134c5994e6a7e5dff766dc8cf1290dc1 Author: Jonathan Wakely <jwak...@redhat.com> Date: Fri Sep 30 14:20:10 2016 +0100 Remove use of std::abs in experimental::{gcd,lcm} PR libstdc++/77801 * include/experimental/numeric: Include <numeric>. (__abs): Define. (gcd, lcm): Use __abs instead of std::abs. * testsuite/experimental/numeric/77801.cc: New test. * testsuite/experimental/numeric/gcd.cc: Test unsigned inputs. * testsuite/experimental/numeric/lcm.cc: Likewise. diff --git a/libstdc++-v3/include/experimental/numeric b/libstdc++-v3/include/experimental/numeric index 21878f3..5089772 100644 --- a/libstdc++-v3/include/experimental/numeric +++ b/libstdc++-v3/include/experimental/numeric @@ -39,8 +39,8 @@ # include <bits/c++14_warning.h> #else +#include <numeric> #include <experimental/type_traits> -#include <cmath> namespace std _GLIBCXX_VISIBILITY(default) { @@ -52,6 +52,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #define __cpp_lib_experimental_gcd_lcm 201411 + // std::abs is not constexpr and doesn't support unsigned integers. + template<typename _Tp> + constexpr + enable_if_t<__and_<is_integral<_Tp>, is_signed<_Tp>>::value, _Tp> + __abs(_Tp __val) + { return __val < 0 ? -__val : __val; } + + template<typename _Tp> + constexpr + enable_if_t<__and_<is_integral<_Tp>, is_unsigned<_Tp>>::value, _Tp> + __abs(_Tp __val) + { return __val; } + // Greatest common divisor template<typename _Mn, typename _Nn> constexpr common_type_t<_Mn, _Nn> @@ -60,8 +73,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION static_assert(is_integral<_Mn>::value, "arguments to gcd are integers"); static_assert(is_integral<_Nn>::value, "arguments to gcd are integers"); - return __m == 0 ? std::abs(__n) - : __n == 0 ? std::abs(__m) + return __m == 0 ? fundamentals_v2::__abs(__n) + : __n == 0 ? fundamentals_v2::__abs(__m) : fundamentals_v2::gcd(__n, __m % __n); } @@ -74,7 +87,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION static_assert(is_integral<_Nn>::value, "arguments to lcm are integers"); return (__m != 0 && __n != 0) - ? (std::abs(__m) / fundamentals_v2::gcd(__m, __n)) * std::abs(__n) + ? (fundamentals_v2::__abs(__m) / fundamentals_v2::gcd(__m, __n)) + * fundamentals_v2::__abs(__n) : 0; } diff --git a/libstdc++-v3/testsuite/experimental/numeric/77801.cc b/libstdc++-v3/testsuite/experimental/numeric/77801.cc new file mode 100644 index 0000000..c4c8bfb --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/numeric/77801.cc @@ -0,0 +1,22 @@ +// Copyright (C) 2016 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// { dg-do compile { target c++14 } } + +#include <cstdlib> +#include <experimental/numeric> +constexpr int i = std::experimental::gcd(4L, 5L); // PR libstdc++/77801 diff --git a/libstdc++-v3/testsuite/experimental/numeric/gcd.cc b/libstdc++-v3/testsuite/experimental/numeric/gcd.cc index 038f12d..b3345dc 100644 --- a/libstdc++-v3/testsuite/experimental/numeric/gcd.cc +++ b/libstdc++-v3/testsuite/experimental/numeric/gcd.cc @@ -25,3 +25,7 @@ static_assert(lcm(21, 6) == 42, ""); static_assert(lcm(41, 0) == 0, "LCD with zero is zero"); static_assert(lcm(0, 7) == 0, "LCD with zero is zero"); static_assert(lcm(0, 0) == 0, "no division by zero"); + +static_assert(lcm(1u, 2) == 2, "unsigned and signed"); +static_assert(lcm(3, 4u) == 12, "signed and unsigned"); +static_assert(lcm(5u, 6u) == 30, "unsigned and unsigned"); diff --git a/libstdc++-v3/testsuite/experimental/numeric/lcm.cc b/libstdc++-v3/testsuite/experimental/numeric/lcm.cc index 2c969b0..d90c152 100644 --- a/libstdc++-v3/testsuite/experimental/numeric/lcm.cc +++ b/libstdc++-v3/testsuite/experimental/numeric/lcm.cc @@ -29,3 +29,6 @@ static_assert( gcd(0, 13) == 13, "GCD of any number and 0 is that number" ); static_assert( gcd(29, 0) == 29, "GCD of any number and 0 is that number" ); static_assert( gcd(0, 0) == 0, "" ); +static_assert(gcd(1u, 2) == 1, "unsigned and signed"); +static_assert(gcd(3, 4u) == 1, "signed and unsigned"); +static_assert(gcd(5u, 6u) == 1, "unsigned and unsigned");