diff options
author | Jonathan Wakely <jwakely@redhat.com> | 2020-10-08 14:01:00 +0100 |
---|---|---|
committer | Jonathan Wakely <jwakely@redhat.com> | 2020-10-08 14:45:36 +0100 |
commit | c06617a79b41da37d80d7e88a3dbc56818f3e706 (patch) | |
tree | 254a3bb062025ad8711614a17d487cb414a7bd6d /libstdc++-v3 | |
parent | 629e0547af33221a925f38757b52a9284148b68a (diff) | |
download | gcc-c06617a79b41da37d80d7e88a3dbc56818f3e706.zip gcc-c06617a79b41da37d80d7e88a3dbc56818f3e706.tar.gz gcc-c06617a79b41da37d80d7e88a3dbc56818f3e706.tar.bz2 |
libstdc++: Avoid divide by zero in default template arguments
My previous attempt to fix this only worked when m is a power of two.
There is still a bug when a=00 and !has_single_bit(m).
Instead of trying to make _Mod work for a==0 this change ensures that we
never instantiate it with a==0. For C++17 we can use if-constexpr, but
otherwise we need to use a different multipler. It doesn't matter what
we use, as it won't actually be called, only instantiated.
libstdc++-v3/ChangeLog:
* include/bits/random.h (__detail::_Mod): Revert last change.
(__detail::__mod): Do not use _Mod for a==0 case.
* testsuite/26_numerics/random/linear_congruential_engine/operators/call.cc:
Check other cases with a==0. Also check runtime results.
* testsuite/26_numerics/random/pr60037-neg.cc: Adjust dg-error
line.
Diffstat (limited to 'libstdc++-v3')
3 files changed, 52 insertions, 6 deletions
diff --git a/libstdc++-v3/include/bits/random.h b/libstdc++-v3/include/bits/random.h index 920f3d9..0be1191 100644 --- a/libstdc++-v3/include/bits/random.h +++ b/libstdc++-v3/include/bits/random.h @@ -109,7 +109,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Tp, _Tp __m, _Tp __a, _Tp __c, bool __big_enough = (!(__m & (__m - 1)) || (_Tp(-1) - __c) / __a >= __m - 1), - bool __schrage_ok = __a != 0 && __m % __a < __m / __a> + bool __schrage_ok = __m % __a < __m / __a> struct _Mod { typedef typename _Select_uint_least_t<std::__lg(__a) @@ -146,7 +146,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Tp, _Tp __m, _Tp __a = 1, _Tp __c = 0> inline _Tp __mod(_Tp __x) - { return _Mod<_Tp, __m, __a, __c>::__calc(__x); } + { + if _GLIBCXX17_CONSTEXPR (__a == 0) + return __c; + else + { + // _Mod must not be instantiated with a == 0 + constexpr _Tp __a1 = __a ? __a : 1; + return _Mod<_Tp, __m, __a1, __c>::__calc(__x); + } + } /* * An adaptor class for converting the output of any Generator into diff --git a/libstdc++-v3/testsuite/26_numerics/random/linear_congruential_engine/operators/call.cc b/libstdc++-v3/testsuite/26_numerics/random/linear_congruential_engine/operators/call.cc index d1fff6d..0000aa2 100644 --- a/libstdc++-v3/testsuite/26_numerics/random/linear_congruential_engine/operators/call.cc +++ b/libstdc++-v3/testsuite/26_numerics/random/linear_congruential_engine/operators/call.cc @@ -15,13 +15,50 @@ // with this library; see the file COPYING3. If not see // <http://www.gnu.org/licenses/>. -// { dg-do compile { target c++11 } } +// { dg-do run { target c++11 } } #include <random> +#include <testsuite_hooks.h> -unsigned +void test01() { std::linear_congruential_engine<unsigned, 0, 0, 0> l; - return l(); // this used to result in divide by zero + auto r = l(); // this used to result in divide by zero + VERIFY( r == 0 ); + l.seed(2); + r = l(); + VERIFY( r == 0 ); + VERIFY( l() == 0 ); +} + +void +test02() +{ + std::linear_congruential_engine<unsigned, 0, 0, 3> l; + auto r = l(); // this used to result in a different divide by zero + VERIFY( r == 0 ); + l.seed(2); + r = l(); + VERIFY( r == 0 ); + VERIFY( l() == 0 ); +} + +void +test03() +{ + std::linear_congruential_engine<unsigned, 0, 2, 3> l; + auto r = l(); + VERIFY( r == 2 ); + l.seed(4); + r = l(); + VERIFY( r == 2 ); + VERIFY( l() == 2 ); +} + +int main() +{ + test01(); + test02(); + test03(); } diff --git a/libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc b/libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc index f808132..139abbb 100644 --- a/libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc +++ b/libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc @@ -10,6 +10,6 @@ std::__detail::_Adaptor<std::mt19937, unsigned long> aurng(urng); auto x = std::generate_canonical<std::size_t, std::numeric_limits<std::size_t>::digits>(urng); -// { dg-error "static assertion failed: template argument must be a floating point type" "" { target *-*-* } 158 } +// { dg-error "static assertion failed: template argument must be a floating point type" "" { target *-*-* } 167 } // { dg-error "static assertion failed: template argument must be a floating point type" "" { target *-*-* } 3281 } |