Index: include/algorithm =================================================================== --- include/algorithm +++ include/algorithm @@ -1672,7 +1672,8 @@ _Size __count, const _Tp& __value_, _BinaryPredicate __pred) { return _VSTD::__search_n::type> - (__first, __last, __count, __value_, __pred, typename iterator_traits<_ForwardIterator>::iterator_category()); + (__first, __last, __convert_to_integral(__count), __value_, __pred, + typename iterator_traits<_ForwardIterator>::iterator_category()); } template @@ -1681,7 +1682,8 @@ search_n(_ForwardIterator __first, _ForwardIterator __last, _Size __count, const _Tp& __value_) { typedef typename iterator_traits<_ForwardIterator>::value_type __v; - return _VSTD::search_n(__first, __last, __count, __value_, __equal_to<__v, _Tp>()); + return _VSTD::search_n(__first, __last, __convert_to_integral(__count), + __value_, __equal_to<__v, _Tp>()); } // copy @@ -1839,8 +1841,10 @@ !__is_random_access_iterator<_InputIterator>::value, _OutputIterator >::type -copy_n(_InputIterator __first, _Size __n, _OutputIterator __result) +copy_n(_InputIterator __first, _Size __orig_n, _OutputIterator __result) { + typedef decltype(__convert_to_integral(__orig_n)) _IntegralSize; + _IntegralSize __n = __orig_n; if (__n > 0) { *__result = *__first; @@ -1862,8 +1866,10 @@ __is_random_access_iterator<_InputIterator>::value, _OutputIterator >::type -copy_n(_InputIterator __first, _Size __n, _OutputIterator __result) +copy_n(_InputIterator __first, _Size __orig_n, _OutputIterator __result) { + typedef decltype(__convert_to_integral(__orig_n)) _IntegralSize; + _IntegralSize __n = __orig_n; return _VSTD::copy(__first, __first + __n, __result); } @@ -2055,7 +2061,7 @@ _OutputIterator fill_n(_OutputIterator __first, _Size __n, const _Tp& __value_) { - return _VSTD::__fill_n(__first, __n, __value_); + return _VSTD::__fill_n(__first, __convert_to_integral(__n), __value_); } // fill @@ -2101,8 +2107,10 @@ template inline _LIBCPP_INLINE_VISIBILITY _OutputIterator -generate_n(_OutputIterator __first, _Size __n, _Generator __gen) +generate_n(_OutputIterator __first, _Size __orig_n, _Generator __gen) { + typedef decltype(__convert_to_integral(__orig_n)) _IntegralSize; + _IntegralSize __n = __orig_n; for (; __n > 0; ++__first, (void) --__n) *__first = __gen(); return __first; Index: include/type_traits =================================================================== --- include/type_traits +++ include/type_traits @@ -3646,6 +3646,48 @@ #endif // _LIBCPP_UNDERLYING_TYPE + +template ::value> +struct __sfinae_underlying_type +{ + typedef typename underlying_type<_Tp>::type type; + typedef decltype(((type)1) + 0) __promoted_type; +}; + +template +struct __sfinae_underlying_type<_Tp, false> {}; + +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE +int __convert_to_integral(int __val) { return __val; } + +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE +unsigned __convert_to_integral(unsigned __val) { return __val; } + +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE +long __convert_to_integral(long __val) { return __val; } + +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE +unsigned long __convert_to_integral(unsigned long __val) { return __val; } + +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE +long long __convert_to_integral(long long __val) { return __val; } + +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE +unsigned long long __convert_to_integral(unsigned long long __val) {return __val; } + +#ifndef _LIBCPP_HAS_NO_INT128 +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE +__int128_t __convert_to_integral(__int128_t __val) { return __val; } + +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE +__uint128_t __convert_to_integral(__uint128_t __val) { return __val; } +#endif + +template +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE +typename __sfinae_underlying_type<_Tp>::__promoted_type +__convert_to_integral(_Tp __val) { return __val; } + #ifndef _LIBCPP_HAS_NO_ADVANCED_SFINAE template Index: test/libcxx/type_traits/convert_to_integral.pass.cpp =================================================================== --- /dev/null +++ test/libcxx/type_traits/convert_to_integral.pass.cpp @@ -0,0 +1,89 @@ + +#include +#include +#include +#include + +#include "user_defined_integral.hpp" + +template +struct EnumType +{ + enum type : T {E_zero, E_one}; +}; + + +template +void check_integral_types() +{ + typedef std::numeric_limits Limits; + const From max = Limits::max(); + const From min = Limits::min(); + { + auto ret = std::__convert_to_integral((From)max); + assert(ret == max); + ret = std::__convert_to_integral((From)min); + assert(ret == min); + static_assert(std::is_same::value, ""); + } + { + UserDefinedIntegral f(max); + auto ret = std::__convert_to_integral(f); + assert(ret == max); + f.value = min; + ret = std::__convert_to_integral(f); + assert(ret == min); + static_assert(std::is_same::value, ""); + } + { + typedef typename EnumType::type Enum; + Enum e(static_cast(max)); + auto ret = std::__convert_to_integral(e); + assert(ret == max); + e = static_cast(min); + ret = std::__convert_to_integral(min); + assert(ret == min); + static_assert(std::is_same::value, ""); + } +} + + +template +void check_enum_types() +{ + auto ret = std::__convert_to_integral((From)1); + assert(ret == 1); + static_assert(std::is_same::value, ""); +} + + +enum enum1 {}; +enum enum2 { + value = std::numeric_limits::max() +}; + +int main() +{ + check_integral_types(); + check_integral_types(); + check_integral_types(); + check_integral_types(); + check_integral_types(); + check_integral_types(); + check_integral_types(); + check_integral_types(); + check_integral_types(); + check_integral_types(); + check_integral_types(); + check_integral_types(); + check_integral_types(); + check_integral_types(); + check_integral_types(); +#ifndef _LIBCPP_HAS_NO_INT128 + check_integral_types<__int128_t, __int128_t>(); + check_integral_types<__uint128_t, __uint128_t>(); +#endif + // TODO(ericwf): Not standard + check_enum_types(); + check_enum_types(); +} Index: test/std/algorithms/alg.modifying.operations/alg.copy/copy_n.pass.cpp =================================================================== --- test/std/algorithms/alg.modifying.operations/alg.copy/copy_n.pass.cpp +++ test/std/algorithms/alg.modifying.operations/alg.copy/copy_n.pass.cpp @@ -17,6 +17,9 @@ #include #include "test_iterators.h" +#include "user_defined_integral.hpp" + +typedef UserDefinedIntegral UDI; template void @@ -28,7 +31,7 @@ ia[i] = i; int ib[N] = {0}; - OutIter r = std::copy_n(InIter(ia), N/2, OutIter(ib)); + OutIter r = std::copy_n(InIter(ia), UDI(N/2), OutIter(ib)); assert(base(r) == ib+N/2); for (unsigned i = 0; i < N/2; ++i) assert(ia[i] == ib[i]); Index: test/std/algorithms/alg.modifying.operations/alg.fill/fill_n.pass.cpp =================================================================== --- test/std/algorithms/alg.modifying.operations/alg.fill/fill_n.pass.cpp +++ test/std/algorithms/alg.modifying.operations/alg.fill/fill_n.pass.cpp @@ -18,6 +18,9 @@ #include #include "test_iterators.h" +#include "user_defined_integral.hpp" + +typedef UserDefinedIntegral UDI; template void @@ -25,7 +28,7 @@ { const unsigned n = 4; char ca[n] = {0}; - assert(std::fill_n(Iter(ca), n, char(1)) == std::next(Iter(ca), n)); + assert(std::fill_n(Iter(ca), UDI(n), char(1)) == std::next(Iter(ca), n)); assert(ca[0] == 1); assert(ca[1] == 1); assert(ca[2] == 1); @@ -38,7 +41,7 @@ { const unsigned n = 4; int ia[n] = {0}; - assert(std::fill_n(Iter(ia), n, 1) == std::next(Iter(ia), n)); + assert(std::fill_n(Iter(ia), UDI(n), 1) == std::next(Iter(ia), n)); assert(ia[0] == 1); assert(ia[1] == 1); assert(ia[2] == 1); @@ -50,7 +53,7 @@ { const unsigned n = 4; int ia[n] = {0}; - assert(std::fill_n(ia, n, static_cast(1)) == std::next(ia, n)); + assert(std::fill_n(ia, UDI(n), static_cast(1)) == std::next(ia, n)); assert(ia[0] == 1); assert(ia[1] == 1); assert(ia[2] == 1); @@ -69,7 +72,7 @@ { const unsigned n = 4; int ia[n] = {0}; - assert(std::fill_n(ia, n, source()) == std::next(ia, n)); + assert(std::fill_n(ia, UDI(n), source()) == std::next(ia, n)); assert(ia[0] == 0); assert(ia[1] == 1); assert(ia[2] == 2); @@ -87,7 +90,7 @@ { const unsigned n = 4; test1 test1a[n] = {0}; - assert(std::fill_n(test1a, n, static_cast(10)) == std::next(test1a, n)); + assert(std::fill_n(test1a, UDI(n), static_cast(10)) == std::next(test1a, n)); assert(test1a[0].c == 11); assert(test1a[1].c == 11); assert(test1a[2].c == 11); @@ -110,7 +113,7 @@ test5() { A a[3]; - assert(std::fill_n(&a[0], 3, A('a')) == a+3); + assert(std::fill_n(&a[0], UDI(3), A('a')) == a+3); assert(a[0] == A('a')); assert(a[1] == A('a')); assert(a[2] == A('a')); @@ -124,11 +127,11 @@ unsigned char b; }; }; - + void test6() { Storage foo[5]; - std::fill_n(&foo[0], 5, Storage()); + std::fill_n(&foo[0], UDI(5), Storage()); } @@ -143,7 +146,7 @@ test_int >(); test_int >(); test_int(); - + test_int_array(); test_int_array_struct_source(); test_struct_array(); Index: test/std/algorithms/alg.modifying.operations/alg.generate/generate_n.pass.cpp =================================================================== --- test/std/algorithms/alg.modifying.operations/alg.generate/generate_n.pass.cpp +++ test/std/algorithms/alg.modifying.operations/alg.generate/generate_n.pass.cpp @@ -19,6 +19,9 @@ #include #include "test_iterators.h" +#include "user_defined_integral.hpp" + +typedef UserDefinedIntegral UDI; struct gen_test { @@ -31,7 +34,7 @@ { const unsigned n = 4; int ia[n] = {0}; - assert(std::generate_n(Iter(ia), n, gen_test()) == Iter(ia+n)); + assert(std::generate_n(Iter(ia), UDI(n), gen_test()) == Iter(ia+n)); assert(ia[0] == 2); assert(ia[1] == 2); assert(ia[2] == 2); Index: test/std/algorithms/alg.nonmodifying/alg.search/search_n.pass.cpp =================================================================== --- test/std/algorithms/alg.nonmodifying/alg.search/search_n.pass.cpp +++ test/std/algorithms/alg.nonmodifying/alg.search/search_n.pass.cpp @@ -18,6 +18,7 @@ #include #include "test_iterators.h" +#include "user_defined_integral.hpp" template void @@ -63,6 +64,9 @@ assert(std::search_n(Iter(ic), Iter(ic+sc), 2, 0) == Iter(ic)); assert(std::search_n(Iter(ic), Iter(ic+sc), 3, 0) == Iter(ic)); assert(std::search_n(Iter(ic), Iter(ic+sc), 4, 0) == Iter(ic+sc)); + + // Check that we properly convert the size argument to an integral. + std::search_n(Iter(ic), Iter(ic+sc), UserDefinedIntegral(0), 0); } int main() Index: test/std/algorithms/alg.nonmodifying/alg.search/search_n_pred.pass.cpp =================================================================== --- test/std/algorithms/alg.nonmodifying/alg.search/search_n_pred.pass.cpp +++ test/std/algorithms/alg.nonmodifying/alg.search/search_n_pred.pass.cpp @@ -18,6 +18,7 @@ #include #include "test_iterators.h" +#include "user_defined_integral.hpp" struct count_equal { @@ -29,6 +30,7 @@ unsigned count_equal::count = 0; + template void test() @@ -138,6 +140,10 @@ assert(std::search_n(Iter(ic), Iter(ic+sc), 4, 0, count_equal()) == Iter(ic+sc)); assert(count_equal::count <= sc); count_equal::count = 0; + + // Check that we properly convert the size argument to an integral. + std::search_n(Iter(ic), Iter(ic+sc), UserDefinedIntegral(4), 0, count_equal()); + count_equal::count = 0; } int main() Index: test/support/user_defined_integral.hpp =================================================================== --- /dev/null +++ test/support/user_defined_integral.hpp @@ -0,0 +1,44 @@ +#ifndef SUPPORT_USER_DEFINED_INTEGRAL_HPP +#define SUPPORT_USER_DEFINED_INTEGRAL_HPP + +template +struct UserDefinedIntegral +{ + UserDefinedIntegral() : value(0) {} + UserDefinedIntegral(T v) : value(v) {} + operator T() const { return value; } + T value; +}; + +// Poison the arithmetic and comparison operations +template +void operator+(UserDefinedIntegral, UserDefinedIntegral); + +template +void operator-(UserDefinedIntegral, UserDefinedIntegral); + +template +void operator*(UserDefinedIntegral, UserDefinedIntegral); + +template +void operator/(UserDefinedIntegral, UserDefinedIntegral); + +template +void operator==(UserDefinedIntegral, UserDefinedIntegral); + +template +void operator!=(UserDefinedIntegral, UserDefinedIntegral); + +template +void operator<(UserDefinedIntegral, UserDefinedIntegral); + +template +void operator>(UserDefinedIntegral, UserDefinedIntegral); + +template +void operator<=(UserDefinedIntegral, UserDefinedIntegral); + +template +void operator>=(UserDefinedIntegral, UserDefinedIntegral); + +#endif // SUPPORT_USER_DEFINED_INTEGRAL_HPP