PR libstdc++/85749 constrain seed sequences for random number engines
authorJonathan Wakely <jwakely@redhat.com>
Tue, 15 May 2018 15:36:46 +0000 (16:36 +0100)
committerJonathan Wakely <redi@gcc.gnu.org>
Tue, 15 May 2018 15:36:46 +0000 (16:36 +0100)
Constrain constructors and member functions of random number engines so
that functions taking seed sequences can only be called with types that
meet the seed sequence requirements.

PR libstdc++/85749
* include/bits/random.h (__detail::__is_seed_seq): New SFINAE helper.
(linear_congruential_engine, mersenne_twister_engine)
(subtract_with_carry_engine, discard_block_engine)
(independent_bits_engine, shuffle_order_engine): Use __is_seed_seq to
constrain function templates taking seed sequences.
* include/bits/random.tcc (linear_congruential_engine::seed(_Sseq&))
(mersenne_twister_engine::seed(_Sseq&))
(subtract_with_carry_engine::seed(_Sseq&)): Change return types to
match declarations.
* include/ext/random (simd_fast_mersenne_twister_engine): Use
__is_seed_seq to constrain function templates taking seed sequences.
* include/ext/random.tcc (simd_fast_mersenne_twister_engine::seed):
Change return type to match declaration.
* testsuite/26_numerics/random/discard_block_engine/cons/seed_seq2.cc:
New.
* testsuite/26_numerics/random/independent_bits_engine/cons/
seed_seq2.cc: New.
* testsuite/26_numerics/random/linear_congruential_engine/cons/
seed_seq2.cc: New.
* testsuite/26_numerics/random/mersenne_twister_engine/cons/
seed_seq2.cc: New.
* testsuite/26_numerics/random/pr60037-neg.cc: Adjust dg-error lineno.
* testsuite/26_numerics/random/shuffle_order_engine/cons/seed_seq2.cc:
New.
* testsuite/26_numerics/random/subtract_with_carry_engine/cons/
seed_seq2.cc: New.
* testsuite/ext/random/simd_fast_mersenne_twister_engine/cons/
seed_seq2.cc: New.

From-SVN: r260263

13 files changed:
libstdc++-v3/ChangeLog
libstdc++-v3/include/bits/random.h
libstdc++-v3/include/bits/random.tcc
libstdc++-v3/include/ext/random
libstdc++-v3/include/ext/random.tcc
libstdc++-v3/testsuite/26_numerics/random/discard_block_engine/cons/seed_seq2.cc [new file with mode: 0644]
libstdc++-v3/testsuite/26_numerics/random/independent_bits_engine/cons/seed_seq2.cc [new file with mode: 0644]
libstdc++-v3/testsuite/26_numerics/random/linear_congruential_engine/cons/seed_seq2.cc [new file with mode: 0644]
libstdc++-v3/testsuite/26_numerics/random/mersenne_twister_engine/cons/seed_seq2.cc [new file with mode: 0644]
libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc
libstdc++-v3/testsuite/26_numerics/random/shuffle_order_engine/cons/seed_seq2.cc [new file with mode: 0644]
libstdc++-v3/testsuite/26_numerics/random/subtract_with_carry_engine/cons/seed_seq2.cc [new file with mode: 0644]
libstdc++-v3/testsuite/ext/random/simd_fast_mersenne_twister_engine/cons/seed_seq2.cc [new file with mode: 0644]

index 03d4e51..8359f4f 100644 (file)
@@ -1,5 +1,35 @@
 2018-05-15  Jonathan Wakely  <jwakely@redhat.com>
 
+       PR libstdc++/85749
+       * include/bits/random.h (__detail::__is_seed_seq): New SFINAE helper.
+       (linear_congruential_engine, mersenne_twister_engine)
+       (subtract_with_carry_engine, discard_block_engine)
+       (independent_bits_engine, shuffle_order_engine): Use __is_seed_seq to
+       constrain function templates taking seed sequences.
+       * include/bits/random.tcc (linear_congruential_engine::seed(_Sseq&))
+       (mersenne_twister_engine::seed(_Sseq&))
+       (subtract_with_carry_engine::seed(_Sseq&)): Change return types to
+       match declarations.
+       * include/ext/random (simd_fast_mersenne_twister_engine): Use
+       __is_seed_seq to constrain function templates taking seed sequences.
+       * include/ext/random.tcc (simd_fast_mersenne_twister_engine::seed):
+       Change return type to match declaration.
+       * testsuite/26_numerics/random/discard_block_engine/cons/seed_seq2.cc:
+       New.
+       * testsuite/26_numerics/random/independent_bits_engine/cons/
+       seed_seq2.cc: New.
+       * testsuite/26_numerics/random/linear_congruential_engine/cons/
+       seed_seq2.cc: New.
+       * testsuite/26_numerics/random/mersenne_twister_engine/cons/
+       seed_seq2.cc: New.
+       * testsuite/26_numerics/random/pr60037-neg.cc: Adjust dg-error lineno.
+       * testsuite/26_numerics/random/shuffle_order_engine/cons/seed_seq2.cc:
+       New.
+       * testsuite/26_numerics/random/subtract_with_carry_engine/cons/
+       seed_seq2.cc: New.
+       * testsuite/ext/random/simd_fast_mersenne_twister_engine/cons/
+       seed_seq2.cc: New.
+
        PR libstdc++/83891
        * include/bits/fs_path.h (path::is_absolute()): Use same definition
        for all operating systems.
index f812bbf..b76cfbb 100644 (file)
@@ -185,6 +185,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        _Engine& _M_g;
       };
 
+    template<typename _Sseq>
+      using __seed_seq_generate_t = decltype(
+         std::declval<_Sseq&>().generate(std::declval<uint_least32_t*>(),
+                                         std::declval<uint_least32_t*>()));
+
+    // Detect whether _Sseq is a valid seed sequence for
+    // a random number engine _Engine with result type _Res.
+    template<typename _Sseq, typename _Engine, typename _Res,
+            typename _GenerateCheck = __seed_seq_generate_t<_Sseq>>
+      using __is_seed_seq = __and_<
+        __not_<is_same<__remove_cvref_t<_Sseq>, _Engine>>,
+       is_unsigned<typename _Sseq::result_type>,
+       __not_<is_convertible<_Sseq, _Res>>
+      >;
+
   } // namespace __detail
 
   /**
@@ -233,6 +248,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       static_assert(__m == 0u || (__a < __m && __c < __m),
                    "template argument substituting __m out of bounds");
 
+      template<typename _Sseq>
+       using _If_seed_seq = typename enable_if<__detail::__is_seed_seq<
+         _Sseq, linear_congruential_engine, _UIntType>::value>::type;
+
     public:
       /** The type of the generated random value. */
       typedef _UIntType result_type;
@@ -262,9 +281,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        *
        * @param __q the seed sequence.
        */
-      template<typename _Sseq, typename = typename
-       std::enable_if<!std::is_same<_Sseq, linear_congruential_engine>::value>
-              ::type>
+      template<typename _Sseq, typename = _If_seed_seq<_Sseq>>
         explicit
         linear_congruential_engine(_Sseq& __q)
         { seed(__q); }
@@ -286,7 +303,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        * @param __q the seed sequence.
        */
       template<typename _Sseq>
-        typename std::enable_if<std::is_class<_Sseq>::value>::type
+        _If_seed_seq<_Sseq>
         seed(_Sseq& __q);
 
       /**
@@ -463,6 +480,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       static_assert(__f <= (__detail::_Shift<_UIntType, __w>::__value - 1),
                    "template argument substituting __f out of bound");
 
+      template<typename _Sseq>
+       using _If_seed_seq = typename enable_if<__detail::__is_seed_seq<
+         _Sseq, mersenne_twister_engine, _UIntType>::value>::type;
+
     public:
       /** The type of the generated random value. */
       typedef _UIntType result_type;
@@ -494,9 +515,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        *
        * @param __q the seed sequence.
        */
-      template<typename _Sseq, typename = typename
-        std::enable_if<!std::is_same<_Sseq, mersenne_twister_engine>::value>
-              ::type>
+      template<typename _Sseq, typename = _If_seed_seq<_Sseq>>
         explicit
         mersenne_twister_engine(_Sseq& __q)
         { seed(__q); }
@@ -505,7 +524,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       seed(result_type __sd = default_seed);
 
       template<typename _Sseq>
-       typename std::enable_if<std::is_class<_Sseq>::value>::type
+        _If_seed_seq<_Sseq>
         seed(_Sseq& __q);
 
       /**
@@ -658,6 +677,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       static_assert(0u < __w && __w <= std::numeric_limits<_UIntType>::digits,
                    "template argument substituting __w out of bounds");
 
+      template<typename _Sseq>
+       using _If_seed_seq = typename enable_if<__detail::__is_seed_seq<
+         _Sseq, subtract_with_carry_engine, _UIntType>::value>::type;
+
     public:
       /** The type of the generated random value. */
       typedef _UIntType result_type;
@@ -682,9 +705,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        *
        * @param __q the seed sequence.
        */
-      template<typename _Sseq, typename = typename
-        std::enable_if<!std::is_same<_Sseq, subtract_with_carry_engine>::value>
-              ::type>
+      template<typename _Sseq, typename = _If_seed_seq<_Sseq>>
         explicit
         subtract_with_carry_engine(_Sseq& __q)
         { seed(__q); }
@@ -709,7 +730,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        * % subtract_with_carry_engine random number generator.
        */
       template<typename _Sseq>
-       typename std::enable_if<std::is_class<_Sseq>::value>::type
+       _If_seed_seq<_Sseq>
         seed(_Sseq& __q);
 
       /**
@@ -845,6 +866,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       /** The type of the generated random value. */
       typedef typename _RandomNumberEngine::result_type result_type;
 
+      template<typename _Sseq>
+       using _If_seed_seq = typename enable_if<__detail::__is_seed_seq<
+         _Sseq, discard_block_engine, result_type>::value>::type;
+
       // parameter values
       static constexpr size_t block_size = __p;
       static constexpr size_t used_block = __r;
@@ -892,10 +917,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        *
        * @param __q A seed sequence.
        */
-      template<typename _Sseq, typename = typename
-       std::enable_if<!std::is_same<_Sseq, discard_block_engine>::value
-                      && !std::is_same<_Sseq, _RandomNumberEngine>::value>
-              ::type>
+      template<typename _Sseq, typename = _If_seed_seq<_Sseq>>
         explicit
         discard_block_engine(_Sseq& __q)
        : _M_b(__q), _M_n(0)
@@ -929,7 +951,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        * @param __q A seed generator function.
        */
       template<typename _Sseq>
-        void
+        _If_seed_seq<_Sseq>
         seed(_Sseq& __q)
         {
          _M_b.seed(__q);
@@ -1063,6 +1085,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       static_assert(0u < __w && __w <= std::numeric_limits<_UIntType>::digits,
                    "template argument substituting __w out of bounds");
 
+      template<typename _Sseq>
+       using _If_seed_seq = typename enable_if<__detail::__is_seed_seq<
+         _Sseq, independent_bits_engine, _UIntType>::value>::type;
+
     public:
       /** The type of the generated random value. */
       typedef _UIntType result_type;
@@ -1110,10 +1136,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        *
        * @param __q A seed sequence.
        */
-      template<typename _Sseq, typename = typename
-       std::enable_if<!std::is_same<_Sseq, independent_bits_engine>::value
-                      && !std::is_same<_Sseq, _RandomNumberEngine>::value>
-               ::type>
+      template<typename _Sseq, typename = _If_seed_seq<_Sseq>>
         explicit
         independent_bits_engine(_Sseq& __q)
         : _M_b(__q)
@@ -1141,7 +1164,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        * @param __q A seed generator function.
        */
       template<typename _Sseq>
-        void
+        _If_seed_seq<_Sseq>
         seed(_Sseq& __q)
         { _M_b.seed(__q); }
 
@@ -1283,6 +1306,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       /** The type of the generated random value. */
       typedef typename _RandomNumberEngine::result_type result_type;
 
+      template<typename _Sseq>
+       using _If_seed_seq = typename enable_if<__detail::__is_seed_seq<
+         _Sseq, shuffle_order_engine, result_type>::value>::type;
+
       static constexpr size_t table_size = __k;
 
       /**
@@ -1332,10 +1359,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        *
        * @param __q A seed sequence.
        */
-      template<typename _Sseq, typename = typename
-       std::enable_if<!std::is_same<_Sseq, shuffle_order_engine>::value
-                      && !std::is_same<_Sseq, _RandomNumberEngine>::value>
-              ::type>
+      template<typename _Sseq, typename = _If_seed_seq<_Sseq>>
         explicit
         shuffle_order_engine(_Sseq& __q)
         : _M_b(__q)
@@ -1369,7 +1393,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        * @param __q A seed generator function.
        */
       template<typename _Sseq>
-        void
+        _If_seed_seq<_Sseq>
         seed(_Sseq& __q)
         {
          _M_b.seed(__q);
index f398150..9ec2989 100644 (file)
@@ -128,9 +128,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
    */
   template<typename _UIntType, _UIntType __a, _UIntType __c, _UIntType __m>
     template<typename _Sseq>
-      typename std::enable_if<std::is_class<_Sseq>::value>::type
+      auto
       linear_congruential_engine<_UIntType, __a, __c, __m>::
       seed(_Sseq& __q)
+      -> _If_seed_seq<_Sseq>
       {
        const _UIntType __k0 = __m == 0 ? std::numeric_limits<_UIntType>::digits
                                        : std::__lg(__m);
@@ -346,10 +347,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
           _UIntType __b, size_t __t, _UIntType __c, size_t __l,
           _UIntType __f>
     template<typename _Sseq>
-      typename std::enable_if<std::is_class<_Sseq>::value>::type
+      auto
       mersenne_twister_engine<_UIntType, __w, __n, __m, __r, __a, __u, __d,
                              __s, __b, __t, __c, __l, __f>::
       seed(_Sseq& __q)
+      -> _If_seed_seq<_Sseq>
       {
        const _UIntType __upper_mask = (~_UIntType()) << __r;
        const size_t __k = (__w + 31) / 32;
@@ -564,9 +566,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   template<typename _UIntType, size_t __w, size_t __s, size_t __r>
     template<typename _Sseq>
-      typename std::enable_if<std::is_class<_Sseq>::value>::type
+      auto
       subtract_with_carry_engine<_UIntType, __w, __s, __r>::
       seed(_Sseq& __q)
+      -> _If_seed_seq<_Sseq>
       {
        const size_t __k = (__w + 31) / 32;
        uint_least32_t __arr[__r * __k];
index 0a98b35..7e93186 100644 (file)
@@ -85,6 +85,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       static_assert(16 % sizeof(_UIntType) == 0,
                    "UIntType size must divide 16");
 
+      template<typename _Sseq>
+       using _If_seed_seq
+         = typename std::enable_if<std::__detail::__is_seed_seq<
+           _Sseq, simd_fast_mersenne_twister_engine, result_type>::value
+           >::type;
+
     public:
       static constexpr size_t state_size = _M_nstate * (16
                                                        / sizeof(result_type));
@@ -95,10 +101,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       simd_fast_mersenne_twister_engine(result_type __sd = default_seed)
       { seed(__sd); }
 
-      template<typename _Sseq, typename = typename
-       std::enable_if<!std::is_same<_Sseq,
-                                    simd_fast_mersenne_twister_engine>::value>
-              ::type>
+      template<typename _Sseq, typename = _If_seed_seq<_Sseq>>
        explicit
        simd_fast_mersenne_twister_engine(_Sseq& __q)
        { seed(__q); }
@@ -107,7 +110,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       seed(result_type __sd = default_seed);
 
       template<typename _Sseq>
-       typename std::enable_if<std::is_class<_Sseq>::value>::type
+       _If_seed_seq<_Sseq>
        seed(_Sseq& __q);
 
       static constexpr result_type
index 07857dd..d845f25 100644 (file)
@@ -85,13 +85,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
           uint32_t __parity1, uint32_t __parity2,
           uint32_t __parity3, uint32_t __parity4>
     template<typename _Sseq>
-      typename std::enable_if<std::is_class<_Sseq>::value>::type
+      auto
       simd_fast_mersenne_twister_engine<_UIntType, __m,
                                        __pos1, __sl1, __sl2, __sr1, __sr2,
                                        __msk1, __msk2, __msk3, __msk4,
                                        __parity1, __parity2, __parity3,
                                        __parity4>::
       seed(_Sseq& __q)
+      -> _If_seed_seq<_Sseq>
       {
        size_t __lag;
 
diff --git a/libstdc++-v3/testsuite/26_numerics/random/discard_block_engine/cons/seed_seq2.cc b/libstdc++-v3/testsuite/26_numerics/random/discard_block_engine/cons/seed_seq2.cc
new file mode 100644 (file)
index 0000000..0e44fff
--- /dev/null
@@ -0,0 +1,87 @@
+// Copyright (C) 2018 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 run { target c++11 } }
+// { dg-require-cstdint "" }
+
+#include <random>
+#include <testsuite_hooks.h>
+
+template<typename T>
+struct seed_seq
+{
+  using result_type = unsigned;
+
+  seed_seq() { }
+
+  template<class U>
+    seed_seq(std::initializer_list<U>) { }
+
+  template<class InputIterator>
+    seed_seq(InputIterator, InputIterator) { }
+
+  template<class RandomAccessIterator>
+    void generate(RandomAccessIterator first, RandomAccessIterator last)
+    {
+      called = true;
+      if (first != last)
+       *first = 42;
+    }
+
+  size_t size() const { called = true; return 1; }
+
+  template<class OutputIterator>
+    void param(OutputIterator dest) const { called = true; dest = 42; }
+
+  // Prevents this type being considered as a seed sequence when
+  // T is convertible to the engine's result_type:
+  operator T() const noexcept { return T(); }
+
+  bool called = false;
+};
+
+using engine_type
+  = std::discard_block_engine
+    <
+      std::subtract_with_carry_engine<unsigned long, 24, 10, 24>,
+      389, 24
+    >;
+
+void
+test01()
+{
+  seed_seq<unsigned> seed;
+  engine_type x(seed);
+  VERIFY( ! seed.called );
+}
+
+void
+test02()
+{
+  seed_seq<void*> seed;
+  engine_type x(seed);
+  VERIFY( seed.called );
+
+  static_assert(!std::is_constructible<engine_type, const seed_seq<void>&>(),
+      "Cannot construct from a const seed_seq");
+}
+
+int main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/26_numerics/random/independent_bits_engine/cons/seed_seq2.cc b/libstdc++-v3/testsuite/26_numerics/random/independent_bits_engine/cons/seed_seq2.cc
new file mode 100644 (file)
index 0000000..4fad651
--- /dev/null
@@ -0,0 +1,88 @@
+// Copyright (C) 2018 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 run { target c++11 } }
+// { dg-require-cstdint "" }
+
+#include <random>
+#include <testsuite_hooks.h>
+
+template<typename T>
+struct seed_seq
+{
+  using result_type = unsigned;
+
+  seed_seq() { }
+
+  template<class U>
+    seed_seq(std::initializer_list<U>) { }
+
+  template<class InputIterator>
+    seed_seq(InputIterator, InputIterator) { }
+
+  template<class RandomAccessIterator>
+    void generate(RandomAccessIterator first, RandomAccessIterator last)
+    {
+      called = true;
+      if (first != last)
+       *first = 42;
+    }
+
+  size_t size() const { called = true; return 1; }
+
+  template<class OutputIterator>
+    void param(OutputIterator dest) const { called = true; dest = 42; }
+
+  // Prevents this type being considered as a seed sequence when
+  // T is convertible to the engine's result_type:
+  operator T() const noexcept { return T(); }
+
+  bool called = false;
+};
+
+using engine_type
+  = std::independent_bits_engine
+    <
+      std::subtract_with_carry_engine<uint_fast64_t, 48, 5, 12>,
+      48,
+      uint_fast64_t
+    >;
+
+void
+test01()
+{
+  seed_seq<unsigned> seed;
+  engine_type x(seed);
+  VERIFY( ! seed.called );
+}
+
+void
+test02()
+{
+  seed_seq<void*> seed;
+  engine_type x(seed);
+  VERIFY( seed.called );
+
+  static_assert(!std::is_constructible<engine_type, const seed_seq<void>&>(),
+      "Cannot construct from a const seed_seq");
+}
+
+int main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/26_numerics/random/linear_congruential_engine/cons/seed_seq2.cc b/libstdc++-v3/testsuite/26_numerics/random/linear_congruential_engine/cons/seed_seq2.cc
new file mode 100644 (file)
index 0000000..3330b47
--- /dev/null
@@ -0,0 +1,83 @@
+// Copyright (C) 2018 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 run { target c++11 } }
+// { dg-require-cstdint "" }
+
+#include <random>
+#include <testsuite_hooks.h>
+
+template<typename T>
+struct seed_seq
+{
+  using result_type = unsigned;
+
+  seed_seq() { }
+
+  template<class U>
+    seed_seq(std::initializer_list<U>) { }
+
+  template<class InputIterator>
+    seed_seq(InputIterator, InputIterator) { }
+
+  template<class RandomAccessIterator>
+    void generate(RandomAccessIterator first, RandomAccessIterator last)
+    {
+      called = true;
+      if (first != last)
+       *first = 42;
+    }
+
+  size_t size() const { called = true; return 1; }
+
+  template<class OutputIterator>
+    void param(OutputIterator dest) const { called = true; dest = 42; }
+
+  // Prevents this type being considered as a seed sequence when
+  // T is convertible to the engine's result_type:
+  operator T() const noexcept { return T(); }
+
+  bool called = false;
+};
+
+using engine_type
+  = std::linear_congruential_engine<unsigned, 48271, 0, 2147483647>;
+
+void
+test01()
+{
+  seed_seq<unsigned> seed;
+  engine_type x(seed);
+  VERIFY( ! seed.called );
+}
+
+void
+test02()
+{
+  seed_seq<void*> seed;
+  engine_type x(seed);
+  VERIFY( seed.called );
+
+  static_assert(!std::is_constructible<engine_type, const seed_seq<void>&>(),
+      "Cannot construct from a const seed_seq");
+}
+
+int main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/26_numerics/random/mersenne_twister_engine/cons/seed_seq2.cc b/libstdc++-v3/testsuite/26_numerics/random/mersenne_twister_engine/cons/seed_seq2.cc
new file mode 100644 (file)
index 0000000..d900bc3
--- /dev/null
@@ -0,0 +1,88 @@
+// Copyright (C) 2018 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 run { target c++11 } }
+// { dg-require-cstdint "" }
+
+#include <random>
+#include <testsuite_hooks.h>
+
+template<typename T>
+struct seed_seq
+{
+  using result_type = unsigned;
+
+  seed_seq() { }
+
+  template<class U>
+    seed_seq(std::initializer_list<U>) { }
+
+  template<class InputIterator>
+    seed_seq(InputIterator, InputIterator) { }
+
+  template<class RandomAccessIterator>
+    void generate(RandomAccessIterator first, RandomAccessIterator last)
+    {
+      called = true;
+      if (first != last)
+       *first = 42;
+    }
+
+  size_t size() const { called = true; return 1; }
+
+  template<class OutputIterator>
+    void param(OutputIterator dest) const { called = true; dest = 42; }
+
+  // Prevents this type being considered as a seed sequence when
+  // T is convertible to the engine's result_type:
+  operator T() const noexcept { return T(); }
+
+  bool called = false;
+};
+
+using engine_type
+  = std::mersenne_twister_engine<
+    unsigned long, 32, 624, 397, 31,
+    0x9908b0dful, 11,
+    0xfffffffful, 7,
+    0x9d2c5680ul, 15,
+    0xefc60000ul, 18, 1812433253ul>;
+
+void
+test01()
+{
+  seed_seq<unsigned> seed;
+  engine_type x(seed);
+  VERIFY( ! seed.called );
+}
+
+void
+test02()
+{
+  seed_seq<void*> seed;
+  engine_type x(seed);
+  VERIFY( seed.called );
+
+  static_assert(!std::is_constructible<engine_type, const seed_seq<void>&>(),
+      "Cannot construct from a const seed_seq");
+}
+
+int main()
+{
+  test01();
+  test02();
+}
index 13c052d..1ead99c 100644 (file)
@@ -11,4 +11,4 @@ auto x = std::generate_canonical<std::size_t,
 
 // { dg-error "static assertion failed: template argument must be a floating point type" "" { target *-*-* } 156 }
 
-// { dg-error "static assertion failed: template argument must be a floating point type" "" { target *-*-* } 3317 }
+// { dg-error "static assertion failed: template argument must be a floating point type" "" { target *-*-* } 3320 }
diff --git a/libstdc++-v3/testsuite/26_numerics/random/shuffle_order_engine/cons/seed_seq2.cc b/libstdc++-v3/testsuite/26_numerics/random/shuffle_order_engine/cons/seed_seq2.cc
new file mode 100644 (file)
index 0000000..13ad5e5
--- /dev/null
@@ -0,0 +1,87 @@
+// Copyright (C) 2018 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 run { target c++11 } }
+// { dg-require-cstdint "" }
+
+#include <random>
+#include <testsuite_hooks.h>
+
+template<typename T>
+struct seed_seq
+{
+  using result_type = unsigned;
+
+  seed_seq() { }
+
+  template<class U>
+    seed_seq(std::initializer_list<U>) { }
+
+  template<class InputIterator>
+    seed_seq(InputIterator, InputIterator) { }
+
+  template<class RandomAccessIterator>
+    void generate(RandomAccessIterator first, RandomAccessIterator last)
+    {
+      called = true;
+      if (first != last)
+       *first = 42;
+    }
+
+  size_t size() const { called = true; return 1; }
+
+  template<class OutputIterator>
+    void param(OutputIterator dest) const { called = true; dest = 42; }
+
+  // Prevents this type being considered as a seed sequence when
+  // T is convertible to the engine's result_type:
+  operator T() const noexcept { return T(); }
+
+  bool called = false;
+};
+
+using engine_type
+  = std::shuffle_order_engine
+    <
+      std::linear_congruential_engine<uint_fast32_t,16807UL, 0UL, 2147483647UL>,
+      256
+    >;
+
+void
+test01()
+{
+  seed_seq<unsigned> seed;
+  engine_type x(seed);
+  VERIFY( ! seed.called );
+}
+
+void
+test02()
+{
+  seed_seq<void*> seed;
+  engine_type x(seed);
+  VERIFY( seed.called );
+
+  static_assert(!std::is_constructible<engine_type, const seed_seq<void>&>(),
+      "Cannot construct from a const seed_seq");
+}
+
+int main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/26_numerics/random/subtract_with_carry_engine/cons/seed_seq2.cc b/libstdc++-v3/testsuite/26_numerics/random/subtract_with_carry_engine/cons/seed_seq2.cc
new file mode 100644 (file)
index 0000000..e4a13a7
--- /dev/null
@@ -0,0 +1,83 @@
+// Copyright (C) 2018 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 run { target c++11 } }
+// { dg-require-cstdint "" }
+
+#include <random>
+#include <testsuite_hooks.h>
+
+template<typename T>
+struct seed_seq
+{
+  using result_type = unsigned;
+
+  seed_seq() { }
+
+  template<class U>
+    seed_seq(std::initializer_list<U>) { }
+
+  template<class InputIterator>
+    seed_seq(InputIterator, InputIterator) { }
+
+  template<class RandomAccessIterator>
+    void generate(RandomAccessIterator first, RandomAccessIterator last)
+    {
+      called = true;
+      if (first != last)
+       *first = 42;
+    }
+
+  size_t size() const { called = true; return 1; }
+
+  template<class OutputIterator>
+    void param(OutputIterator dest) const { called = true; dest = 42; }
+
+  // Prevents this type being considered as a seed sequence when
+  // T is convertible to the engine's result_type:
+  operator T() const noexcept { return T(); }
+
+  bool called = false;
+};
+
+using engine_type
+  = std::subtract_with_carry_engine<unsigned long, 24, 10, 24>;
+
+void
+test01()
+{
+  seed_seq<unsigned> seed;
+  engine_type x(seed);
+  VERIFY( ! seed.called );
+}
+
+void
+test02()
+{
+  seed_seq<void*> seed;
+  engine_type x(seed);
+  VERIFY( seed.called );
+
+  static_assert(!std::is_constructible<engine_type, const seed_seq<void>&>(),
+      "Cannot construct from a const seed_seq");
+}
+
+int main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/ext/random/simd_fast_mersenne_twister_engine/cons/seed_seq2.cc b/libstdc++-v3/testsuite/ext/random/simd_fast_mersenne_twister_engine/cons/seed_seq2.cc
new file mode 100644 (file)
index 0000000..325e275
--- /dev/null
@@ -0,0 +1,90 @@
+// Copyright (C) 2018 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 run { target c++11 } }
+// { dg-require-cstdint "" }
+// { dg-require-little-endian "" }
+
+#include <ext/random>
+#include <testsuite_hooks.h>
+
+template<typename T>
+struct seed_seq
+{
+  using result_type = unsigned;
+
+  seed_seq() { }
+
+  template<class U>
+    seed_seq(std::initializer_list<U>) { }
+
+  template<class InputIterator>
+    seed_seq(InputIterator, InputIterator) { }
+
+  template<class RandomAccessIterator>
+    void generate(RandomAccessIterator first, RandomAccessIterator last)
+    {
+      called = true;
+      if (first != last)
+       *first = 42;
+    }
+
+  size_t size() const { called = true; return 1; }
+
+  template<class OutputIterator>
+    void param(OutputIterator dest) const { called = true; dest = 42; }
+
+  // Prevents this type being considered as a seed sequence when
+  // T is convertible to the engine's result_type:
+  operator T() const noexcept { return T(); }
+
+  bool called = false;
+};
+
+using engine_type
+  = __gnu_cxx::simd_fast_mersenne_twister_engine<
+    uint32_t, 607, 2,
+    15, 3, 13, 3,
+    0xfdff37ffU, 0xef7f3f7dU,
+    0xff777b7dU, 0x7ff7fb2fU,
+    0x00000001U, 0x00000000U,
+    0x00000000U, 0x5986f054U>;
+
+void
+test01()
+{
+  seed_seq<unsigned> seed;
+  engine_type x(seed);
+  VERIFY( ! seed.called );
+}
+
+void
+test02()
+{
+  seed_seq<void*> seed;
+  engine_type x(seed);
+  VERIFY( seed.called );
+
+  static_assert(!std::is_constructible<engine_type, const seed_seq<void>&>(),
+      "Cannot construct from a const seed_seq");
+}
+
+int main()
+{
+  test01();
+  test02();
+}