diff --git a/libcxx/benchmarks/GenerateInput.h b/libcxx/benchmarks/GenerateInput.h --- a/libcxx/benchmarks/GenerateInput.h +++ b/libcxx/benchmarks/GenerateInput.h @@ -36,10 +36,9 @@ } template -inline IntT getRandomInteger(IntT Min = 0, - IntT Max = std::numeric_limits::max()) { - std::uniform_int_distribution dist(Min, Max); - return dist(getRandomEngine()); +inline IntT getRandomInteger(IntT Min, IntT Max) { + std::uniform_int_distribution dist(Min, Max); + return static_cast(dist(getRandomEngine())); } inline std::string getRandomString(std::size_t Len) { @@ -102,7 +101,7 @@ std::vector getRandomIntegerInputs(size_t N) { std::vector inputs; for (size_t i=0; i < N; ++i) { - inputs.push_back(getRandomInteger()); + inputs.push_back(getRandomInteger(0, std::numeric_limits::max())); } return inputs; } diff --git a/libcxx/benchmarks/algorithms.partition_point.bench.cpp b/libcxx/benchmarks/algorithms.partition_point.bench.cpp --- a/libcxx/benchmarks/algorithms.partition_point.bench.cpp +++ b/libcxx/benchmarks/algorithms.partition_point.bench.cpp @@ -30,7 +30,7 @@ static std::vector generateInput(size_t size) { std::vector Res(size); std::generate(Res.begin(), Res.end(), - [] { return getRandomInteger(); }); + [] { return getRandomInteger(0, std::numeric_limits::max()); }); return Res; } }; diff --git a/libcxx/benchmarks/allocation.bench.cpp b/libcxx/benchmarks/allocation.bench.cpp --- a/libcxx/benchmarks/allocation.bench.cpp +++ b/libcxx/benchmarks/allocation.bench.cpp @@ -97,7 +97,6 @@ const size_t alloc_size = st.range(0); const auto NumAllocs = st.max_iterations; - using PtrT = void*; std::vector Pointers(NumAllocs); for (auto& p : Pointers) { p = AllocWrapper::Allocate(alloc_size); diff --git a/libcxx/docs/ReleaseNotes.rst b/libcxx/docs/ReleaseNotes.rst --- a/libcxx/docs/ReleaseNotes.rst +++ b/libcxx/docs/ReleaseNotes.rst @@ -97,6 +97,13 @@ from all modes. Their symbols are still provided by the dynamic library for the benefit of existing compiled code. All of these functions have always behaved as no-ops. +- The integer distributions ``binomial_distribution``, ``discrete_distribution``, + ``geometric_distribution``, ``negative_binomial_distribution``, ``poisson_distribution``, + and ``uniform_int_distribution`` now conform to the Standard by rejecting + template parameter types other than ``short``, ``int``, ``long``, ``long long``, + (as an extension) ``__int128_t``, and the unsigned versions thereof. + In particular, ``uniform_int_distribution`` is no longer supported. + ABI Changes ----------- diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -298,6 +298,7 @@ __random/geometric_distribution.h __random/independent_bits_engine.h __random/is_seed_sequence.h + __random/is_valid.h __random/knuth_b.h __random/linear_congruential_engine.h __random/log2.h diff --git a/libcxx/include/__random/bernoulli_distribution.h b/libcxx/include/__random/bernoulli_distribution.h --- a/libcxx/include/__random/bernoulli_distribution.h +++ b/libcxx/include/__random/bernoulli_distribution.h @@ -10,6 +10,7 @@ #define _LIBCPP___RANDOM_BERNOULLI_DISTRIBUTION_H #include <__config> +#include <__random/is_valid.h> #include <__random/uniform_real_distribution.h> #include @@ -103,6 +104,7 @@ bernoulli_distribution::result_type bernoulli_distribution::operator()(_URNG& __g, const param_type& __p) { + static_assert(__libcpp_random_is_valid_urng<_URNG>::value, ""); uniform_real_distribution __gen; return __gen(__g) < __p.p(); } diff --git a/libcxx/include/__random/binomial_distribution.h b/libcxx/include/__random/binomial_distribution.h --- a/libcxx/include/__random/binomial_distribution.h +++ b/libcxx/include/__random/binomial_distribution.h @@ -10,6 +10,7 @@ #define _LIBCPP___RANDOM_BINOMIAL_DISTRIBUTION_H #include <__config> +#include <__random/is_valid.h> #include <__random/uniform_real_distribution.h> #include #include @@ -26,6 +27,7 @@ template class _LIBCPP_TEMPLATE_VIS binomial_distribution { + static_assert(__libcpp_random_is_valid_inttype<_IntType>::value, "IntType must be an integer type larger than char"); public: // types typedef _IntType result_type; @@ -146,6 +148,7 @@ _IntType binomial_distribution<_IntType>::operator()(_URNG& __g, const param_type& __pr) { + static_assert(__libcpp_random_is_valid_urng<_URNG>::value, ""); if (__pr.__t_ == 0 || __pr.__p_ == 0) return 0; if (__pr.__p_ == 1) diff --git a/libcxx/include/__random/cauchy_distribution.h b/libcxx/include/__random/cauchy_distribution.h --- a/libcxx/include/__random/cauchy_distribution.h +++ b/libcxx/include/__random/cauchy_distribution.h @@ -10,6 +10,7 @@ #define _LIBCPP___RANDOM_CAUCHY_DISTRIBUTION_H #include <__config> +#include <__random/is_valid.h> #include <__random/uniform_real_distribution.h> #include #include @@ -116,6 +117,7 @@ _RealType cauchy_distribution<_RealType>::operator()(_URNG& __g, const param_type& __p) { + static_assert(__libcpp_random_is_valid_urng<_URNG>::value, ""); uniform_real_distribution __gen; // purposefully let tan arg get as close to pi/2 as it wants, tan will return a finite return __p.a() + __p.b() * _VSTD::tan(3.1415926535897932384626433832795 * __gen(__g)); diff --git a/libcxx/include/__random/discrete_distribution.h b/libcxx/include/__random/discrete_distribution.h --- a/libcxx/include/__random/discrete_distribution.h +++ b/libcxx/include/__random/discrete_distribution.h @@ -11,6 +11,7 @@ #include <__algorithm/upper_bound.h> #include <__config> +#include <__random/is_valid.h> #include <__random/uniform_real_distribution.h> #include #include @@ -29,6 +30,7 @@ template class _LIBCPP_TEMPLATE_VIS discrete_distribution { + static_assert(__libcpp_random_is_valid_inttype<_IntType>::value, "IntType must be an integer type larger than char"); public: // types typedef _IntType result_type; @@ -211,6 +213,7 @@ _IntType discrete_distribution<_IntType>::operator()(_URNG& __g, const param_type& __p) { + static_assert(__libcpp_random_is_valid_urng<_URNG>::value, ""); uniform_real_distribution __gen; return static_cast<_IntType>( _VSTD::upper_bound(__p.__p_.begin(), __p.__p_.end(), __gen(__g)) - diff --git a/libcxx/include/__random/exponential_distribution.h b/libcxx/include/__random/exponential_distribution.h --- a/libcxx/include/__random/exponential_distribution.h +++ b/libcxx/include/__random/exponential_distribution.h @@ -11,6 +11,7 @@ #include <__config> #include <__random/generate_canonical.h> +#include <__random/is_valid.h> #include <__random/uniform_real_distribution.h> #include #include @@ -109,6 +110,7 @@ _RealType exponential_distribution<_RealType>::operator()(_URNG& __g, const param_type& __p) { + static_assert(__libcpp_random_is_valid_urng<_URNG>::value, ""); return -_VSTD::log ( result_type(1) - diff --git a/libcxx/include/__random/extreme_value_distribution.h b/libcxx/include/__random/extreme_value_distribution.h --- a/libcxx/include/__random/extreme_value_distribution.h +++ b/libcxx/include/__random/extreme_value_distribution.h @@ -10,6 +10,7 @@ #define _LIBCPP___RANDOM_EXTREME_VALUE_DISTRIBUTION_H #include <__config> +#include <__random/is_valid.h> #include <__random/uniform_real_distribution.h> #include #include @@ -116,6 +117,7 @@ _RealType extreme_value_distribution<_RealType>::operator()(_URNG& __g, const param_type& __p) { + static_assert(__libcpp_random_is_valid_urng<_URNG>::value, ""); return __p.a() - __p.b() * _VSTD::log(-_VSTD::log(1-uniform_real_distribution()(__g))); } diff --git a/libcxx/include/__random/fisher_f_distribution.h b/libcxx/include/__random/fisher_f_distribution.h --- a/libcxx/include/__random/fisher_f_distribution.h +++ b/libcxx/include/__random/fisher_f_distribution.h @@ -11,6 +11,7 @@ #include <__config> #include <__random/gamma_distribution.h> +#include <__random/is_valid.h> #include #include @@ -114,6 +115,7 @@ _RealType fisher_f_distribution<_RealType>::operator()(_URNG& __g, const param_type& __p) { + static_assert(__libcpp_random_is_valid_urng<_URNG>::value, ""); gamma_distribution __gdm(__p.m() * result_type(.5)); gamma_distribution __gdn(__p.n() * result_type(.5)); return __p.n() * __gdm(__g) / (__p.m() * __gdn(__g)); diff --git a/libcxx/include/__random/gamma_distribution.h b/libcxx/include/__random/gamma_distribution.h --- a/libcxx/include/__random/gamma_distribution.h +++ b/libcxx/include/__random/gamma_distribution.h @@ -11,6 +11,7 @@ #include <__config> #include <__random/exponential_distribution.h> +#include <__random/is_valid.h> #include <__random/uniform_real_distribution.h> #include #include @@ -117,6 +118,7 @@ _RealType gamma_distribution<_RealType>::operator()(_URNG& __g, const param_type& __p) { + static_assert(__libcpp_random_is_valid_urng<_URNG>::value, ""); result_type __a = __p.alpha(); uniform_real_distribution __gen(0, 1); exponential_distribution __egen; diff --git a/libcxx/include/__random/geometric_distribution.h b/libcxx/include/__random/geometric_distribution.h --- a/libcxx/include/__random/geometric_distribution.h +++ b/libcxx/include/__random/geometric_distribution.h @@ -10,6 +10,7 @@ #define _LIBCPP___RANDOM_GEOMETRIC_DISTRIBUTION_H #include <__config> +#include <__random/is_valid.h> #include <__random/negative_binomial_distribution.h> #include #include @@ -26,6 +27,7 @@ template class _LIBCPP_TEMPLATE_VIS geometric_distribution { + static_assert(__libcpp_random_is_valid_inttype<_IntType>::value, "IntType must be an integer type larger than char"); public: // types typedef _IntType result_type; diff --git a/libcxx/include/__random/is_valid.h b/libcxx/include/__random/is_valid.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__random/is_valid.h @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___RANDOM_IS_VALID_H +#define _LIBCPP___RANDOM_IS_VALID_H + +#include <__config> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +#pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +// [rand.req.genl]/1.5: +// The effect of instantiating a template that has a template type parameter +// named IntType is undefined unless the corresponding template argument is +// cv-unqualified and is one of short, int, long, long long, unsigned short, +// unsigned int, unsigned long, or unsigned long long. + +template struct __libcpp_random_is_valid_inttype : false_type {}; +template<> struct __libcpp_random_is_valid_inttype : true_type {}; +template<> struct __libcpp_random_is_valid_inttype : true_type {}; +template<> struct __libcpp_random_is_valid_inttype : true_type {}; +template<> struct __libcpp_random_is_valid_inttype : true_type {}; +template<> struct __libcpp_random_is_valid_inttype : true_type {}; +template<> struct __libcpp_random_is_valid_inttype : true_type {}; +template<> struct __libcpp_random_is_valid_inttype : true_type {}; +template<> struct __libcpp_random_is_valid_inttype : true_type {}; + +#ifndef _LIBCPP_HAS_NO_INT128 +template<> struct __libcpp_random_is_valid_inttype<__int128_t> : true_type {}; +template<> struct __libcpp_random_is_valid_inttype<__uint128_t> : true_type {}; +#endif // _LIBCPP_HAS_NO_INT128 + +// [rand.req.urng]/3: +// A class G meets the uniform random bit generator requirements if G models +// uniform_random_bit_generator, invoke_result_t is an unsigned integer type, +// and G provides a nested typedef-name result_type that denotes the same type +// as invoke_result_t. +// (In particular, reject URNGs with signed result_types; our distributions cannot +// handle such generator types.) + +template struct __libcpp_random_is_valid_urng : false_type {}; +template struct __libcpp_random_is_valid_urng<_Gp, __enable_if_t< + is_unsigned::value && + _IsSame()()), typename _Gp::result_type>::value +> > : true_type {}; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___RANDOM_IS_VALID_H diff --git a/libcxx/include/__random/negative_binomial_distribution.h b/libcxx/include/__random/negative_binomial_distribution.h --- a/libcxx/include/__random/negative_binomial_distribution.h +++ b/libcxx/include/__random/negative_binomial_distribution.h @@ -12,6 +12,7 @@ #include <__config> #include <__random/bernoulli_distribution.h> #include <__random/gamma_distribution.h> +#include <__random/is_valid.h> #include <__random/poisson_distribution.h> #include #include @@ -28,6 +29,7 @@ template class _LIBCPP_TEMPLATE_VIS negative_binomial_distribution { + static_assert(__libcpp_random_is_valid_inttype<_IntType>::value, "IntType must be an integer type larger than char"); public: // types typedef _IntType result_type; @@ -116,6 +118,7 @@ _IntType negative_binomial_distribution<_IntType>::operator()(_URNG& __urng, const param_type& __pr) { + static_assert(__libcpp_random_is_valid_urng<_URNG>::value, ""); result_type __k = __pr.k(); double __p = __pr.p(); if (__k <= 21 * __p) diff --git a/libcxx/include/__random/normal_distribution.h b/libcxx/include/__random/normal_distribution.h --- a/libcxx/include/__random/normal_distribution.h +++ b/libcxx/include/__random/normal_distribution.h @@ -10,6 +10,7 @@ #define _LIBCPP___RANDOM_NORMAL_DISTRIBUTION_H #include <__config> +#include <__random/is_valid.h> #include <__random/uniform_real_distribution.h> #include #include @@ -131,6 +132,7 @@ _RealType normal_distribution<_RealType>::operator()(_URNG& __g, const param_type& __p) { + static_assert(__libcpp_random_is_valid_urng<_URNG>::value, ""); result_type _Up; if (_V_hot_) { diff --git a/libcxx/include/__random/piecewise_constant_distribution.h b/libcxx/include/__random/piecewise_constant_distribution.h --- a/libcxx/include/__random/piecewise_constant_distribution.h +++ b/libcxx/include/__random/piecewise_constant_distribution.h @@ -11,6 +11,7 @@ #include <__algorithm/upper_bound.h> #include <__config> +#include <__random/is_valid.h> #include <__random/uniform_real_distribution.h> #include #include @@ -284,6 +285,7 @@ _RealType piecewise_constant_distribution<_RealType>::operator()(_URNG& __g, const param_type& __p) { + static_assert(__libcpp_random_is_valid_urng<_URNG>::value, ""); typedef uniform_real_distribution _Gen; result_type __u = _Gen()(__g); ptrdiff_t __k = _VSTD::upper_bound(__p.__areas_.begin(), __p.__areas_.end(), diff --git a/libcxx/include/__random/piecewise_linear_distribution.h b/libcxx/include/__random/piecewise_linear_distribution.h --- a/libcxx/include/__random/piecewise_linear_distribution.h +++ b/libcxx/include/__random/piecewise_linear_distribution.h @@ -11,6 +11,7 @@ #include <__algorithm/upper_bound.h> #include <__config> +#include <__random/is_valid.h> #include <__random/uniform_real_distribution.h> #include #include @@ -289,6 +290,7 @@ _RealType piecewise_linear_distribution<_RealType>::operator()(_URNG& __g, const param_type& __p) { + static_assert(__libcpp_random_is_valid_urng<_URNG>::value, ""); typedef uniform_real_distribution _Gen; result_type __u = _Gen()(__g); ptrdiff_t __k = _VSTD::upper_bound(__p.__areas_.begin(), __p.__areas_.end(), diff --git a/libcxx/include/__random/poisson_distribution.h b/libcxx/include/__random/poisson_distribution.h --- a/libcxx/include/__random/poisson_distribution.h +++ b/libcxx/include/__random/poisson_distribution.h @@ -12,6 +12,7 @@ #include <__config> #include <__random/clamp_to_integral.h> #include <__random/exponential_distribution.h> +#include <__random/is_valid.h> #include <__random/normal_distribution.h> #include <__random/uniform_real_distribution.h> #include @@ -30,6 +31,7 @@ template class _LIBCPP_TEMPLATE_VIS poisson_distribution { + static_assert(__libcpp_random_is_valid_inttype<_IntType>::value, "IntType must be an integer type larger than char"); public: // types typedef _IntType result_type; @@ -157,6 +159,7 @@ _IntType poisson_distribution<_IntType>::operator()(_URNG& __urng, const param_type& __pr) { + static_assert(__libcpp_random_is_valid_urng<_URNG>::value, ""); double __tx; uniform_real_distribution __urd; if (__pr.__mean_ < 10) diff --git a/libcxx/include/__random/student_t_distribution.h b/libcxx/include/__random/student_t_distribution.h --- a/libcxx/include/__random/student_t_distribution.h +++ b/libcxx/include/__random/student_t_distribution.h @@ -11,6 +11,7 @@ #include <__config> #include <__random/gamma_distribution.h> +#include <__random/is_valid.h> #include <__random/normal_distribution.h> #include #include @@ -111,6 +112,7 @@ _RealType student_t_distribution<_RealType>::operator()(_URNG& __g, const param_type& __p) { + static_assert(__libcpp_random_is_valid_urng<_URNG>::value, ""); gamma_distribution __gd(__p.n() * .5, 2); return __nd_(__g) * _VSTD::sqrt(__p.n()/__gd(__g)); } diff --git a/libcxx/include/__random/uniform_int_distribution.h b/libcxx/include/__random/uniform_int_distribution.h --- a/libcxx/include/__random/uniform_int_distribution.h +++ b/libcxx/include/__random/uniform_int_distribution.h @@ -11,6 +11,7 @@ #include <__bits> #include <__config> +#include <__random/is_valid.h> #include <__random/log2.h> #include #include @@ -155,9 +156,10 @@ return _Sp; } -template // __int128_t is also supported as an extension here +template class uniform_int_distribution { + static_assert(__libcpp_random_is_valid_inttype<_IntType>::value, "IntType must be an integer type larger than char"); public: // types typedef _IntType result_type; @@ -230,6 +232,7 @@ uniform_int_distribution<_IntType>::operator()(_URNG& __g, const param_type& __p) _LIBCPP_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK { + static_assert(__libcpp_random_is_valid_urng<_URNG>::value, ""); typedef typename conditional::type>::type _UIntType; const _UIntType _Rp = _UIntType(__p.b()) - _UIntType(__p.a()) + _UIntType(1); diff --git a/libcxx/include/__random/uniform_real_distribution.h b/libcxx/include/__random/uniform_real_distribution.h --- a/libcxx/include/__random/uniform_real_distribution.h +++ b/libcxx/include/__random/uniform_real_distribution.h @@ -11,6 +11,7 @@ #include <__config> #include <__random/generate_canonical.h> +#include <__random/is_valid.h> #include #include #include @@ -115,6 +116,7 @@ typename uniform_real_distribution<_RealType>::result_type uniform_real_distribution<_RealType>::operator()(_URNG& __g, const param_type& __p) { + static_assert(__libcpp_random_is_valid_urng<_URNG>::value, ""); return (__p.b() - __p.a()) * _VSTD::generate_canonical<_RealType, numeric_limits<_RealType>::digits>(__g) + __p.a(); diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -757,6 +757,7 @@ module geometric_distribution { private header "__random/geometric_distribution.h" } module independent_bits_engine { private header "__random/independent_bits_engine.h" } module is_seed_sequence { private header "__random/is_seed_sequence.h" } + module is_valid { private header "__random/is_valid.h" } module knuth_b { private header "__random/knuth_b.h" } module linear_congruential_engine { private header "__random/linear_congruential_engine.h" } module log2 { private header "__random/log2.h" } diff --git a/libcxx/include/random b/libcxx/include/random --- a/libcxx/include/random +++ b/libcxx/include/random @@ -1694,6 +1694,7 @@ #include <__random/geometric_distribution.h> #include <__random/independent_bits_engine.h> #include <__random/is_seed_sequence.h> +#include <__random/is_valid.h> #include <__random/knuth_b.h> #include <__random/linear_congruential_engine.h> #include <__random/log2.h> diff --git a/libcxx/test/libcxx/diagnostics/detail.headers/random/is_valid.module.verify.cpp b/libcxx/test/libcxx/diagnostics/detail.headers/random/is_valid.module.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/diagnostics/detail.headers/random/is_valid.module.verify.cpp @@ -0,0 +1,15 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: modules-build + +// WARNING: This test was generated by 'generate_private_header_tests.py' +// and should not be edited manually. + +// expected-error@*:* {{use of private header from outside its module: '__random/is_valid.h'}} +#include <__random/is_valid.h>