aboutsummaryrefslogtreecommitdiff
path: root/libstdc++-v3
diff options
context:
space:
mode:
authorJonathan Wakely <jwakely@redhat.com>2020-10-08 14:01:00 +0100
committerJonathan Wakely <jwakely@redhat.com>2020-10-08 14:45:36 +0100
commitc06617a79b41da37d80d7e88a3dbc56818f3e706 (patch)
tree254a3bb062025ad8711614a17d487cb414a7bd6d /libstdc++-v3
parent629e0547af33221a925f38757b52a9284148b68a (diff)
downloadgcc-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')
-rw-r--r--libstdc++-v3/include/bits/random.h13
-rw-r--r--libstdc++-v3/testsuite/26_numerics/random/linear_congruential_engine/operators/call.cc43
-rw-r--r--libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc2
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 }