From 54be1fd1f0381eb8974a34fa6617dbcf884df181 Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Fri, 21 Aug 2020 12:06:34 -0700 Subject: [PATCH 01/22] STL updates for new EDG version (#1216) Small changes to help the new IntelliSense compiler better work with the concepts-using C++20 STL. Drive-by: Avoid `/analyze:only` run timeouts in two Ranges tests that weren't quite exhausting memory. --- stl/inc/xutility | 72 +++++++++---------- tests/std/tests/P0088R3_variant/test.cpp | 2 + .../P0896R4_ranges_alg_find_end/test.cpp | 2 + .../P0896R4_ranges_alg_mismatch/test.cpp | 4 +- 4 files changed, 42 insertions(+), 38 deletions(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index 9c82bb27c55..b67ee654df1 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -815,44 +815,34 @@ concept sized_sentinel_for = sentinel_for<_Se, _It> // clang-format on // ALIAS TEMPLATE _Iter_concept -template >> -struct _Iter_concept_impl {}; - -// clang-format off -template - requires _Has_member_iterator_concept> -struct _Iter_concept_impl<_It, false> { - using type = typename iterator_traits<_It>::iterator_concept; -}; - -template - requires (!_Has_member_iterator_concept> - && _Has_member_iterator_category>) -struct _Iter_concept_impl<_It, false> { - using type = typename iterator_traits<_It>::iterator_category; +template +struct _Iter_concept_impl2 { + template + using _Apply = typename _Traits::iterator_category; }; -// clang-format on - -template -struct _Iter_concept_impl<_It, true> { - using type = random_access_iterator_tag; +template <> +struct _Iter_concept_impl2 { + // clang-format off + template + requires _Is_from_primary> + using _Apply = random_access_iterator_tag; + // clang-format on }; -template <_Has_member_iterator_concept _It> -struct _Iter_concept_impl<_It, true> { - using type = typename _It::iterator_concept; +template +struct _Iter_concept_impl1 { + template + using _Apply = typename _Traits::iterator_concept; }; - -// clang-format off -template - requires(!_Has_member_iterator_concept<_It> && _Has_member_iterator_category<_It>) -struct _Iter_concept_impl<_It, true> { - using type = typename _It::iterator_category; +template <> +struct _Iter_concept_impl1 { + template + using _Apply = typename _Iter_concept_impl2<_Has_member_iterator_category<_Traits>>::template _Apply<_It, _Traits>; }; -// clang-format on -template -using _Iter_concept = typename _Iter_concept_impl<_It>::type; +template >, _It, iterator_traits<_It>>> +using _Iter_concept = + typename _Iter_concept_impl1<_Has_member_iterator_concept<_Traits>>::template _Apply<_It, _Traits>; // clang-format off // CONCEPT input_iterator @@ -4090,14 +4080,24 @@ public: return _Left._Current - _Right._Get_last(); } - _NODISCARD friend constexpr reference iter_move(const move_iterator& _It) noexcept( - noexcept(_RANGES iter_move(_It._Current))) { + _NODISCARD friend constexpr reference iter_move(const move_iterator& _It) +#ifdef __EDG__ // TRANSITION, VSO-1132105 + noexcept(noexcept(_RANGES iter_move(_STD declval()))) +#else // ^^^ workaround / no workaround vvv + noexcept(noexcept(_RANGES iter_move(_It._Current))) +#endif // TRANSITION, VSO-1132105 + { return _RANGES iter_move(_It._Current); } template _Iter2> - friend constexpr void iter_swap(const move_iterator& _Left, const move_iterator<_Iter2>& _Right) noexcept( - noexcept(_RANGES iter_swap(_Left._Current, _Right.base()))) { + friend constexpr void iter_swap(const move_iterator& _Left, const move_iterator<_Iter2>& _Right) +#ifdef __EDG__ // TRANSITION, VSO-1132105 + noexcept(noexcept(_RANGES iter_swap(_STD declval(), _STD declval()))) +#else // ^^^ workaround / no workaround vvv + noexcept(noexcept(_RANGES iter_swap(_Left._Current, _Right.base()))) +#endif // TRANSITION, VSO-1132105 + { _RANGES iter_swap(_Left._Current, _Right.base()); } #endif // __cpp_lib_concepts diff --git a/tests/std/tests/P0088R3_variant/test.cpp b/tests/std/tests/P0088R3_variant/test.cpp index 2cf2dd5210d..20c045972e5 100644 --- a/tests/std/tests/P0088R3_variant/test.cpp +++ b/tests/std/tests/P0088R3_variant/test.cpp @@ -6481,6 +6481,7 @@ namespace msvc { namespace derived_variant { void run_test() { +#ifndef __EDG__ // TRANSITION, VSO-1178211 // Extension: std::visit accepts types derived from a specialization of variant. { struct my_variant : std::variant { @@ -6533,6 +6534,7 @@ namespace msvc { } catch (std::bad_variant_access&) { } } +#endif // TRANSITION, VSO-1178211 } } // namespace derived_variant diff --git a/tests/std/tests/P0896R4_ranges_alg_find_end/test.cpp b/tests/std/tests/P0896R4_ranges_alg_find_end/test.cpp index 06dae11031f..81880bacca8 100644 --- a/tests/std/tests/P0896R4_ranges_alg_find_end/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_find_end/test.cpp @@ -76,6 +76,7 @@ int main() { smoke_test(); } +#ifndef _PREFAST_ // TRANSITION, GH-1030 struct instantiator { template static void call(Fwd1&& fwd1 = {}, Fwd2&& fwd2 = {}) { @@ -107,3 +108,4 @@ struct instantiator { }; template void test_fwd_fwd(); +#endif // TRANSITION, GH-1030 diff --git a/tests/std/tests/P0896R4_ranges_alg_mismatch/test.cpp b/tests/std/tests/P0896R4_ranges_alg_mismatch/test.cpp index 51a0b864436..2ee68e9a70b 100644 --- a/tests/std/tests/P0896R4_ranges_alg_mismatch/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_mismatch/test.cpp @@ -71,12 +71,11 @@ constexpr void smoke_test() { } int main() { -#ifndef _PREFAST_ // TRANSITION, GH-1030 STATIC_ASSERT((smoke_test(), true)); -#endif // TRANSITION, GH-1030 smoke_test(); } +#ifndef _PREFAST_ // TRANSITION, GH-1030 struct instantiator { template static void call(In1&& in1 = {}, In2&& in2 = {}) { @@ -105,3 +104,4 @@ struct instantiator { }; template void test_in_in(); +#endif // TRANSITION, GH-1030 From a293fad25634f3660485109be96a08528452488b Mon Sep 17 00:00:00 2001 From: Amit Rastogi Date: Sat, 22 Aug 2020 07:27:03 +0530 Subject: [PATCH 02/22] Updated README.md - Use the vcpkg submodule instead of separately cloning (#873) Fixes #761. Co-authored-by: Curtis J Bezault Co-authored-by: Casey Carter Co-authored-by: Stephan T. Lavavej --- README.md | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 5b361a006e4..36d179f9d04 100644 --- a/README.md +++ b/README.md @@ -141,18 +141,17 @@ The STL uses boost-math headers to provide P0226R1 Mathematical Special Function acquire this dependency. 1. Install Visual Studio 2019 16.8 Preview 1 or later. -2. Invoke `git clone https://github.com/microsoft/vcpkg` -3. Invoke `cd vcpkg` -4. Invoke `.\bootstrap-vcpkg.bat` -5. Assuming you are targeting x86 and x64, invoke `.\vcpkg.exe install boost-math:x86-windows boost-math:x64-windows` - to install the boost-math dependency. Add `boost-math:arm-windows boost-math:arm64-windows` to this to target ARM - and ARM64. -6. Run `.\vcpkg.exe integrate install` which tells Visual Studio which vcpkg instance you wish to use. If you have never - done this before, you may be prompted to elevate. -7. Open Visual Studio, and choose the "Clone or check out code" option. Enter the URL to this - repository, typically `https://github.com/microsoft/STL` -8. Choose the architecture you wish to build in the IDE, and build as you would any other project. All necessary CMake - settings are set by `CMakeSettings.json` and `vcpkg integrate` + * We recommend selecting "C++ CMake tools for Windows" in the VS Installer. + This will ensure that you're using supported versions of CMake and Ninja. + * Otherwise, install [CMake][] 3.17 or later, and [Ninja][] 1.8.2 or later. +2. Open Visual Studio, and choose the "Clone or check out code" option. Enter the URL of this repository, + `https://github.com/microsoft/STL`. +3. Open a terminal in the IDE with `` Ctrl + ` `` (by default) or press on "View" in the top bar, and then "Terminal". +4. Invoke `git submodule update --init vcpkg` in the terminal. +5. Invoke `.\vcpkg\bootstrap-vcpkg.bat` in the terminal. +6. Invoke `.\vcpkg\vcpkg.exe install boost-math:x86-windows boost-math:x64-windows` to install the boost-math dependency. +7. Choose the architecture you wish to build in the IDE, and build as you would any other project. All necessary CMake + settings are set by `CMakeSettings.json`. # How To Build With A Native Tools Command Prompt From aafee761bc4fc46ba5285122038a392e1485fef7 Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Sat, 22 Aug 2020 04:04:33 +0200 Subject: [PATCH 03/22] Implement ranges::ref_view (#1132) Co-authored-by: Casey Carter --- stl/inc/ranges | 59 ++++++++ tests/std/include/range_algorithm_support.hpp | 55 +++++++ tests/std/test.lst | 1 + .../std/tests/P0896R4_ranges_ref_view/env.lst | 4 + .../tests/P0896R4_ranges_ref_view/test.cpp | 141 ++++++++++++++++++ 5 files changed, 260 insertions(+) create mode 100644 tests/std/tests/P0896R4_ranges_ref_view/env.lst create mode 100644 tests/std/tests/P0896R4_ranges_ref_view/test.cpp diff --git a/stl/inc/ranges b/stl/inc/ranges index 3024333376c..fe0e967e46f 100644 --- a/stl/inc/ranges +++ b/stl/inc/ranges @@ -29,6 +29,65 @@ namespace ranges { template concept viewable_range = range<_Rng> && (borrowed_range<_Rng> || view>); + + // CLASS TEMPLATE ranges::ref_view + // clang-format off + template + requires is_object_v<_Rng> + class ref_view : public view_interface> { + // clang-format on + private: + _Rng* _Range = nullptr; + + static void _Rvalue_poison(_Rng&); + static void _Rvalue_poison(_Rng&&) = delete; + + public: + constexpr ref_view() noexcept = default; + + // clang-format off + template <_Not_same_as _OtherRng> + constexpr ref_view(_OtherRng&& _Other) noexcept( + noexcept(static_cast<_Rng&>(_STD forward<_OtherRng>(_Other)))) // strengthened + requires convertible_to<_OtherRng, _Rng&> && requires { + _Rvalue_poison(static_cast<_OtherRng&&>(_Other)); + } : _Range{_STD addressof(static_cast<_Rng&>(_STD forward<_OtherRng>(_Other)))} {} + // clang-format on + + _NODISCARD constexpr _Rng& base() const noexcept /* strengthened */ { + return *_Range; + } + + _NODISCARD constexpr iterator_t<_Rng> begin() const + noexcept(noexcept(_RANGES begin(*_Range))) /* strengthened */ { + return _RANGES begin(*_Range); + } + + _NODISCARD constexpr sentinel_t<_Rng> end() const noexcept(noexcept(_RANGES end(*_Range))) /* strengthened */ { + return _RANGES end(*_Range); + } + + _NODISCARD constexpr bool empty() const noexcept(noexcept(_RANGES empty(*_Range))) /* strengthened */ + requires _Can_empty<_Rng> { + return _RANGES empty(*_Range); + } + + _NODISCARD constexpr auto size() const noexcept(noexcept(_RANGES size(*_Range))) /* strengthened */ + requires sized_range<_Rng> { + return _RANGES size(*_Range); + } + + _NODISCARD constexpr auto data() const noexcept(noexcept(_RANGES data(*_Range))) /* strengthened */ + requires contiguous_range<_Rng> { + return _RANGES data(*_Range); + } + }; + + template + ref_view(_Rng&) -> ref_view<_Rng>; + + template + inline constexpr bool enable_borrowed_range> = true; } // namespace ranges _STD_END diff --git a/tests/std/include/range_algorithm_support.hpp b/tests/std/include/range_algorithm_support.hpp index 7b71a423a0e..60fa690bc52 100644 --- a/tests/std/include/range_algorithm_support.hpp +++ b/tests/std/include/range_algorithm_support.hpp @@ -968,6 +968,56 @@ struct with_output_ranges { } }; +template +struct with_input_or_output_ranges { + template + static constexpr void call() { + using namespace test; + using test::range; + + // For all ranges, IsCommon implies Eq. + // For single-pass ranges, Eq is uninteresting without IsCommon (there's only one valid iterator + // value at a time, and no reason to compare it with itself for equality). + Continuation::template call>(); + Continuation::template call>(); + Continuation::template call>(); + Continuation::template call>(); + + Continuation::template call>(); + Continuation::template call>(); + Continuation::template call>(); + Continuation::template call>(); + + Continuation::template call>(); + Continuation::template call>(); + Continuation::template call>(); + Continuation::template call>(); + + Continuation::template call>(); + Continuation::template call>(); + Continuation::template call>(); + Continuation::template call>(); + + with_output_ranges::template call(); + } +}; + template struct with_input_iterators { template @@ -1018,6 +1068,11 @@ constexpr void test_in() { with_input_ranges::call(); } +template +constexpr void test_inout() { + with_input_or_output_ranges::call(); +} + template constexpr void test_fwd() { with_forward_ranges::call(); diff --git a/tests/std/test.lst b/tests/std/test.lst index 0e60c21053b..1b9e682b97b 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -312,6 +312,7 @@ tests\P0896R4_ranges_alg_unique_copy tests\P0896R4_ranges_algorithm_machinery tests\P0896R4_ranges_iterator_machinery tests\P0896R4_ranges_range_machinery +tests\P0896R4_ranges_ref_view tests\P0896R4_ranges_subrange tests\P0896R4_ranges_test_machinery tests\P0896R4_ranges_to_address diff --git a/tests/std/tests/P0896R4_ranges_ref_view/env.lst b/tests/std/tests/P0896R4_ranges_ref_view/env.lst new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_ref_view/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_matrix.lst diff --git a/tests/std/tests/P0896R4_ranges_ref_view/test.cpp b/tests/std/tests/P0896R4_ranges_ref_view/test.cpp new file mode 100644 index 00000000000..0a69e1e5561 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_ref_view/test.cpp @@ -0,0 +1,141 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include + +#include +using namespace std; + +// clang-format off +template +concept can_empty = requires(Range& r) { ranges::empty(r); }; +template +concept can_data = requires(Range& r) { ranges::data(r); }; +template +concept can_size = requires(Range& r) { ranges::size(r); }; +// clang-format on + +struct instantiator { + template + static constexpr void call() { + using ranges::ref_view, ranges::begin, ranges::end, ranges::forward_range; + int input[3] = {0, 1, 2}; + + { // traits + STATIC_ASSERT(ranges::input_range || ranges::output_range); + STATIC_ASSERT(ranges::enable_borrowed_range>); + } + + { // constructors and assignment operators + STATIC_ASSERT(!constructible_from, R>); + + ref_view default_constructed{}; + STATIC_ASSERT(is_nothrow_default_constructible_v>); + + R wrapped_input{input}; + ref_view same_range{wrapped_input}; + STATIC_ASSERT(is_nothrow_constructible_v, R&>); + + auto copy_constructed = same_range; + if constexpr (forward_range) { + assert(copy_constructed.begin().peek() == begin(input)); + } + assert(copy_constructed.end().peek() == end(input)); + + default_constructed = copy_constructed; + if constexpr (forward_range) { + assert(default_constructed.begin().peek() == begin(input)); + } + assert(default_constructed.end().peek() == end(input)); + + [[maybe_unused]] auto move_constructed = std::move(default_constructed); + if constexpr (forward_range) { + assert(move_constructed.begin().peek() == begin(input)); + } + assert(move_constructed.end().peek() == end(input)); + + same_range = std::move(copy_constructed); + if constexpr (forward_range) { + assert(same_range.begin().peek() == begin(input)); + } + assert(same_range.end().peek() == end(input)); + } + + { // access + R wrapped_input{input}; + ref_view test_view{wrapped_input}; + same_as auto& base_range = as_const(test_view).base(); + assert(addressof(base_range) == addressof(wrapped_input)); + + STATIC_ASSERT(noexcept(as_const(test_view).base())); + } + + { // iterators + R wrapped_input{input}; + ref_view test_view{wrapped_input}; + const same_as> auto first = as_const(test_view).begin(); + assert(first.peek() == input); + STATIC_ASSERT(noexcept(as_const(test_view).begin()) == noexcept(wrapped_input.begin())); + + const same_as> auto last = as_const(test_view).end(); + assert(last.peek() == end(input)); + STATIC_ASSERT(noexcept(as_const(test_view).end()) == noexcept(wrapped_input.end())); + } + + { // state + STATIC_ASSERT(can_size> == ranges::sized_range); + if constexpr (ranges::sized_range) { + R wrapped_input{input}; + ref_view test_view{wrapped_input}; + + const same_as> auto ref_size = as_const(test_view).size(); + assert(ref_size == size(wrapped_input)); + + STATIC_ASSERT(noexcept(as_const(test_view).size()) == noexcept(wrapped_input.size())); + } + + STATIC_ASSERT(can_data> == ranges::contiguous_range); + if constexpr (ranges::contiguous_range) { + R wrapped_input{input}; + ref_view test_view{wrapped_input}; + + const same_as auto ref_data = as_const(test_view).data(); + assert(ref_data == input); + + STATIC_ASSERT(noexcept(as_const(test_view).data()) == noexcept(wrapped_input.data())); + } + + STATIC_ASSERT(can_empty> == can_empty); + if constexpr (can_empty) { + R wrapped_input{input}; + ref_view test_view{wrapped_input}; + + const same_as auto ref_empty = as_const(test_view).empty(); + assert(!ref_empty); + + STATIC_ASSERT(noexcept(as_const(test_view).empty()) == noexcept(ranges::empty(wrapped_input))); + + R empty_range{}; + ref_view empty_view{empty_range}; + assert(empty_view.empty()); + } + } + + { // CTAD + span spanInput{input}; + ref_view span_view{spanInput}; + STATIC_ASSERT(same_as>>); + } + } +}; + +int main() { + STATIC_ASSERT((test_inout(), true)); + test_inout(); +} From 465d0a5e13bc03decffdbdee63389bf6194dd4df Mon Sep 17 00:00:00 2001 From: MattStephanson <68978048+MattStephanson@users.noreply.github.com> Date: Fri, 21 Aug 2020 19:12:27 -0700 Subject: [PATCH 04/22] Fix errors in hyperbolic function crossover (#1156) Fix integer truncation and off-by-one errors in calculating limit where exp(-x) can be ignored in hyperbolic functions. --- stl/src/xfvalues.cpp | 2 +- stl/src/xlvalues.cpp | 2 +- stl/src/xvalues.cpp | 2 +- tests/std/test.lst | 1 + .../GH_001059_hyperbolic_truncation/env.lst | 4 ++ .../GH_001059_hyperbolic_truncation/test.cpp | 63 +++++++++++++++++++ 6 files changed, 71 insertions(+), 3 deletions(-) create mode 100644 tests/std/tests/GH_001059_hyperbolic_truncation/env.lst create mode 100644 tests/std/tests/GH_001059_hyperbolic_truncation/test.cpp diff --git a/stl/src/xfvalues.cpp b/stl/src/xfvalues.cpp index 5822c050fae..d0329ee4860 100644 --- a/stl/src/xfvalues.cpp +++ b/stl/src/xfvalues.cpp @@ -28,6 +28,6 @@ extern /* const */ _Dconst _FNan = {INIT((_FMAX << _FOFF) | (1 << (_FOFF - 1) extern /* const */ _Dconst _FSnan = {INIT2(_FMAX << _FOFF, 1)}; extern const _Dconst _FRteps = {INIT((_FBIAS - NBITS / 2) << _FOFF)}; -extern const float _FXbig = (NBITS + 1) * 347L / 1000; +extern const float _FXbig = (NBITS + 2) * 0.347f; _END_EXTERN_C_UNLESS_PURE diff --git a/stl/src/xlvalues.cpp b/stl/src/xlvalues.cpp index c2720fe8d16..7ec133738c2 100644 --- a/stl/src/xlvalues.cpp +++ b/stl/src/xlvalues.cpp @@ -26,4 +26,4 @@ extern /* const */ _Dconst _LNan = {INIT((_DMAX << _DOFF) | (1 << (_DOFF - 1) extern /* const */ _Dconst _LSnan = {INIT2(_DMAX << _DOFF, 1)}; extern const _Dconst _LRteps = {INIT((_DBIAS - NBITS / 2) << _DOFF)}; -extern const long double _LXbig = (NBITS + 1) * 347L / 1000; +extern const long double _LXbig = (NBITS + 2) * 0.347L; diff --git a/stl/src/xvalues.cpp b/stl/src/xvalues.cpp index e48d493d42c..1d9a1fb1e30 100644 --- a/stl/src/xvalues.cpp +++ b/stl/src/xvalues.cpp @@ -28,4 +28,4 @@ extern /* const */ _Dconst _Nan = {INIT((_DMAX << _DOFF) | (1 << (_DOFF - 1) extern /* const */ _Dconst _Snan = {INIT2(_DMAX << _DOFF, 1)}; extern const _Dconst _Rteps = {INIT((_DBIAS - NBITS / 2) << _DOFF)}; -extern const double _Xbig = (NBITS + 1) * 347L / 1000; +extern const double _Xbig = (NBITS + 2) * 0.347; diff --git a/tests/std/test.lst b/tests/std/test.lst index 1b9e682b97b..36d3eddf0c5 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -164,6 +164,7 @@ tests\GH_000890_pow_template tests\GH_000940_missing_valarray_copy tests\GH_001010_filesystem_error_encoding tests\GH_001017_discrete_distribution_out_of_range +tests\GH_001059_hyperbolic_truncation tests\GH_001086_partial_sort_copy tests\GH_001103_countl_zero_correctness tests\LWG2597_complex_branch_cut diff --git a/tests/std/tests/GH_001059_hyperbolic_truncation/env.lst b/tests/std/tests/GH_001059_hyperbolic_truncation/env.lst new file mode 100644 index 00000000000..19f025bd0e6 --- /dev/null +++ b/tests/std/tests/GH_001059_hyperbolic_truncation/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_matrix.lst diff --git a/tests/std/tests/GH_001059_hyperbolic_truncation/test.cpp b/tests/std/tests/GH_001059_hyperbolic_truncation/test.cpp new file mode 100644 index 00000000000..67d69e1bb9a --- /dev/null +++ b/tests/std/tests/GH_001059_hyperbolic_truncation/test.cpp @@ -0,0 +1,63 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +// GH-1059: "Incorrect const float values in xvalues.cpp files" +// The _Xbig constants, used to determine when the exp(-x) terms in +// cosh and sinh can be ignored, have off-by-one and integer +// truncation errors. + +#include +#include +#include +#include +#include +#include + +using namespace std; + +template +void Test(T x) { + const complex z{x}; + const T exp_over_2 = T{0.5} * real(exp(z)); + + const T cosh_expected = exp_over_2 + T{0.25} / exp_over_2; + const T cosh_calc = real(cosh(z)); + if (cosh_expected != cosh_calc) { + cout.precision(numeric_limits::digits10 + 2); + cout << "x = " << x << '\n' + << "cosh (expected) = " << cosh_expected << '\n' + << "cosh (calculated) = " << cosh_calc << endl; + assert(cosh_expected == cosh_calc); + } + + const T sinh_expected = exp_over_2 - T{0.25} / exp_over_2; + const T sinh_calc = real(sinh(z)); + if (sinh_expected != sinh_calc) { + cout.precision(numeric_limits::digits10 + 2); + cout << "x = " << x << '\n' + << "sinh (expected) = " << sinh_expected << '\n' + << "sinh (calculated) = " << sinh_calc << endl; + assert(sinh_expected == sinh_calc); + } +} + +template +constexpr array GenerateValues() { + // {old crossover, difference ~ 1 ulp, difference ~ ulp/2} + constexpr int DIG = numeric_limits::digits; + return {DIG * 347L / 1000L, DIG * static_cast(0.347), (DIG + 1) * static_cast(0.347)}; +} + +int main() { + constexpr auto fValues{GenerateValues()}; + for (const auto& x : fValues) { + Test(x); + } + + constexpr auto dValues{GenerateValues()}; + for (const auto& x : dValues) { + Test(x); + } + + return 0; +} From 0b81475cc8087a7b615911d65b52b6a1fad87d7d Mon Sep 17 00:00:00 2001 From: statementreply Date: Sat, 22 Aug 2020 10:20:19 +0800 Subject: [PATCH 05/22] Fix ostream << floating_point not correctly handling precision (#1173) 1. Hexfloat output now ignores precision as required by the standard. (Fixes #1125.) 2. Zero precision is now correctly passed to sprintf. 3. Negative precision no longer crashes. --- stl/inc/xlocnum | 63 +++++++++++++++--- tests/tr1/tests/ostream1/test.cpp | 102 +++++++++++++++++++++++++++++- tests/tr1/tests/ostream2/test.cpp | 102 +++++++++++++++++++++++++++++- 3 files changed, 257 insertions(+), 10 deletions(-) diff --git a/stl/inc/xlocnum b/stl/inc/xlocnum index e2c887b5f1f..0c0bd1db376 100644 --- a/stl/inc/xlocnum +++ b/stl/inc/xlocnum @@ -1146,6 +1146,45 @@ __PURE_APPDOMAIN_GLOBAL locale::id num_get<_Elem, _InIt>::id; #pragma clang diagnostic pop #endif // __clang__ +// STRUCT TEMPLATE _Hex_float_precision +template +struct _Hex_float_precision; + +template <> +struct _Hex_float_precision { + // the number of hexits needed to represent (DBL_MANT_DIG - 1) bits after the radix point exactly + static constexpr int value = ((DBL_MANT_DIG - 1) + 3) / 4; +}; + +template <> +struct _Hex_float_precision { + // the number of hexits needed to represent (LDBL_MANT_DIG - 1) bits after the radix point exactly + static constexpr int value = ((LDBL_MANT_DIG - 1) + 3) / 4; +}; + +// FUNCTION TEMPLATE _Float_put_desired_precision +template +int _Float_put_desired_precision(const streamsize _Precision, const ios_base::fmtflags _Float_flags) { + const bool _Is_hex = _Float_flags == (ios_base::fixed | ios_base::scientific); + if (_Is_hex) { + return _Hex_float_precision<_Ty>::value; + } + + if (_Precision > 0) { + return static_cast(_Precision); + } else if (_Precision == 0) { + const bool _Is_default_float = _Float_flags == 0; + if (_Is_default_float) { + return 1; + } else { + return 0; + } + } else { + constexpr int _Default_precision = 6; + return _Default_precision; + } +} + // CLASS TEMPLATE num_put template >> class num_put : public locale::facet { // facet for converting encoded numbers to text @@ -1292,10 +1331,14 @@ protected: _OutIt _Dest, ios_base& _Iosbase, _Elem _Fill, double _Val) const { // put formatted double to _Dest string _Buf; char _Fmt[8]; - bool _Isfixed = (_Iosbase.flags() & ios_base::floatfield) == ios_base::fixed; - streamsize _Precision = _Iosbase.precision() <= 0 && !_Isfixed ? 6 : _Iosbase.precision(); // desired precision - size_t _Bufsize = static_cast(_Precision); - if (_Isfixed && 1e10 < _CSTD fabs(_Val)) { // f or F format + const auto _Float_flags = _Iosbase.flags() & ios_base::floatfield; + const bool _Is_fixed = _Float_flags == ios_base::fixed; + const bool _Is_hex = _Float_flags == (ios_base::fixed | ios_base::scientific); + const streamsize _Precision = _Is_hex ? -1 : _Iosbase.precision(); // precision setting + const int _Desired_precision = + _Float_put_desired_precision(_Precision, _Float_flags); // desired precision + size_t _Bufsize = static_cast(_Desired_precision); + if (_Is_fixed && 1e10 < _CSTD fabs(_Val)) { // f or F format int _Ptwo; (void) _CSTD frexp(_Val, &_Ptwo); _Bufsize += _CSTD abs(_Ptwo) * 30103L / 100000L; @@ -1312,10 +1355,14 @@ protected: _OutIt _Dest, ios_base& _Iosbase, _Elem _Fill, long double _Val) const { // put formatted long double to _Dest string _Buf; char _Fmt[8]; - bool _Isfixed = (_Iosbase.flags() & ios_base::floatfield) == ios_base::fixed; - streamsize _Precision = _Iosbase.precision() <= 0 && !_Isfixed ? 6 : _Iosbase.precision(); // desired precision - size_t _Bufsize = static_cast(_Precision); - if (_Isfixed && 1e10 < _CSTD fabsl(_Val)) { // f or F format + const auto _Float_flags = _Iosbase.flags() & ios_base::floatfield; + const bool _Is_fixed = _Float_flags == ios_base::fixed; + const bool _Is_hex = _Float_flags == (ios_base::fixed | ios_base::scientific); + const streamsize _Precision = _Is_hex ? -1 : _Iosbase.precision(); // precision setting + const int _Desired_precision = + _Float_put_desired_precision(_Precision, _Float_flags); // desired precision + size_t _Bufsize = static_cast(_Desired_precision); + if (_Is_fixed && 1e10 < _CSTD fabsl(_Val)) { // f or F format int _Ptwo; (void) _CSTD frexpl(_Val, &_Ptwo); _Bufsize += _CSTD abs(_Ptwo) * 30103L / 100000L; diff --git a/tests/tr1/tests/ostream1/test.cpp b/tests/tr1/tests/ostream1/test.cpp index f19c5727112..74bc1791572 100644 --- a/tests/tr1/tests/ostream1/test.cpp +++ b/tests/tr1/tests/ostream1/test.cpp @@ -213,9 +213,109 @@ void test_main() { // test basic workings of ostream definitions outs << STD hexfloat << 2.0; STD string ans = outs.str(); const char* buf = ans.c_str(); - CHECK_STR(buf, "0x1.000p+1"); + CHECK_STR(buf, "0x1.0000000000000p+1"); } + outs.precision(0); + + outs.str(""); + outs << STD defaultfloat << 1.5; + CHECK_STR(outs.str().c_str(), "2"); + + outs.str(""); + outs << STD fixed << 1.0; + CHECK_STR(outs.str().c_str(), "1"); + + outs.str(""); + outs << STD scientific << 2.0; + CHECK_STR(outs.str().c_str(), "2e+00"); + + outs.str(""); + outs << STD hexfloat << 2.0; + CHECK_STR(outs.str().c_str(), "0x1.0000000000000p+1"); + + outs.precision(-1); + + outs.str(""); + outs << STD defaultfloat << 1.5; + CHECK_STR(outs.str().c_str(), "1.5"); + + outs.str(""); + outs << STD fixed << 1.0; + CHECK_STR(outs.str().c_str(), "1.000000"); + + outs.str(""); + outs << STD scientific << 2.0; + CHECK_STR(outs.str().c_str(), "2.000000e+00"); + + outs.str(""); + outs << STD hexfloat << 2.0; + CHECK_STR(outs.str().c_str(), "0x1.0000000000000p+1"); + + outs.precision(-49); + outs.str(""); + outs << STD fixed << 1.0; + CHECK_STR(outs.str().c_str(), "1.000000"); + + outs.precision(3); + + outs.str(""); + outs << STD defaultfloat << 1.5L; + CHECK_STR(outs.str().c_str(), "1.5"); + + outs.str(""); + outs << STD fixed << 1.0L; + CHECK_STR(outs.str().c_str(), "1.000"); + + outs.str(""); + outs << STD scientific << 2.0L; + CHECK_STR(outs.str().c_str(), "2.000e+00"); + + outs.str(""); + outs << STD hexfloat << 2.0L; + CHECK_STR(outs.str().c_str(), "0x1.0000000000000p+1"); + + outs.precision(0); + + outs.str(""); + outs << STD defaultfloat << 1.5L; + CHECK_STR(outs.str().c_str(), "2"); + + outs.str(""); + outs << STD fixed << 1.0L; + CHECK_STR(outs.str().c_str(), "1"); + + outs.str(""); + outs << STD scientific << 2.0L; + CHECK_STR(outs.str().c_str(), "2e+00"); + + outs.str(""); + outs << STD hexfloat << 2.0L; + CHECK_STR(outs.str().c_str(), "0x1.0000000000000p+1"); + + outs.precision(-1); + + outs.str(""); + outs << STD defaultfloat << 1.5L; + CHECK_STR(outs.str().c_str(), "1.5"); + + outs.str(""); + outs << STD fixed << 1.0L; + CHECK_STR(outs.str().c_str(), "1.000000"); + + outs.str(""); + outs << STD scientific << 2.0L; + CHECK_STR(outs.str().c_str(), "2.000000e+00"); + + outs.str(""); + outs << STD hexfloat << 2.0L; + CHECK_STR(outs.str().c_str(), "0x1.0000000000000p+1"); + + outs.precision(-49); + outs.str(""); + outs << STD fixed << 1.0L; + CHECK_STR(outs.str().c_str(), "1.000000"); + // test Boolx inserter const Boolx no(0), yes(1); outs.str(""); diff --git a/tests/tr1/tests/ostream2/test.cpp b/tests/tr1/tests/ostream2/test.cpp index 4fe35d436db..6a2701ecb91 100644 --- a/tests/tr1/tests/ostream2/test.cpp +++ b/tests/tr1/tests/ostream2/test.cpp @@ -208,7 +208,107 @@ void test_main() { // test basic workings of ostream definitions outs << STD hexfloat << 2.0; STD wstring ans = outs.str(); const wchar_t* buf = ans.c_str(); - CHECK_WSTR(buf, L"0x1.000p+1"); + CHECK_WSTR(buf, L"0x1.0000000000000p+1"); + + outs.precision(0); + + outs.str(L""); + outs << STD defaultfloat << 1.5; + CHECK_WSTR(outs.str().c_str(), L"2"); + + outs.str(L""); + outs << STD fixed << 1.0; + CHECK_WSTR(outs.str().c_str(), L"1"); + + outs.str(L""); + outs << STD scientific << 2.0; + CHECK_WSTR(outs.str().c_str(), L"2e+00"); + + outs.str(L""); + outs << STD hexfloat << 2.0; + CHECK_WSTR(outs.str().c_str(), L"0x1.0000000000000p+1"); + + outs.precision(-1); + + outs.str(L""); + outs << STD defaultfloat << 1.5; + CHECK_WSTR(outs.str().c_str(), L"1.5"); + + outs.str(L""); + outs << STD fixed << 1.0; + CHECK_WSTR(outs.str().c_str(), L"1.000000"); + + outs.str(L""); + outs << STD scientific << 2.0; + CHECK_WSTR(outs.str().c_str(), L"2.000000e+00"); + + outs.str(L""); + outs << STD hexfloat << 2.0; + CHECK_WSTR(outs.str().c_str(), L"0x1.0000000000000p+1"); + + outs.precision(-49); + outs.str(L""); + outs << STD fixed << 1.0; + CHECK_WSTR(outs.str().c_str(), L"1.000000"); + + outs.precision(3); + + outs.str(L""); + outs << STD defaultfloat << 1.5L; + CHECK_WSTR(outs.str().c_str(), L"1.5"); + + outs.str(L""); + outs << STD fixed << 1.0L; + CHECK_WSTR(outs.str().c_str(), L"1.000"); + + outs.str(L""); + outs << STD scientific << 2.0L; + CHECK_WSTR(outs.str().c_str(), L"2.000e+00"); + + outs.str(L""); + outs << STD hexfloat << 2.0L; + CHECK_WSTR(outs.str().c_str(), L"0x1.0000000000000p+1"); + + outs.precision(0); + + outs.str(L""); + outs << STD defaultfloat << 1.5L; + CHECK_WSTR(outs.str().c_str(), L"2"); + + outs.str(L""); + outs << STD fixed << 1.0L; + CHECK_WSTR(outs.str().c_str(), L"1"); + + outs.str(L""); + outs << STD scientific << 2.0L; + CHECK_WSTR(outs.str().c_str(), L"2e+00"); + + outs.str(L""); + outs << STD hexfloat << 2.0L; + CHECK_WSTR(outs.str().c_str(), L"0x1.0000000000000p+1"); + + outs.precision(-1); + + outs.str(L""); + outs << STD defaultfloat << 1.5L; + CHECK_WSTR(outs.str().c_str(), L"1.5"); + + outs.str(L""); + outs << STD fixed << 1.0L; + CHECK_WSTR(outs.str().c_str(), L"1.000000"); + + outs.str(L""); + outs << STD scientific << 2.0L; + CHECK_WSTR(outs.str().c_str(), L"2.000000e+00"); + + outs.str(L""); + outs << STD hexfloat << 2.0L; + CHECK_WSTR(outs.str().c_str(), L"0x1.0000000000000p+1"); + + outs.precision(-49); + outs.str(L""); + outs << STD fixed << 1.0L; + CHECK_WSTR(outs.str().c_str(), L"1.000000"); // test Boolx inserter const Boolx no(0), yes(1); From 0926c8282c8587917254d571a890d9080b3ba9b7 Mon Sep 17 00:00:00 2001 From: Hamid Reza Arzaghi Date: Sat, 22 Aug 2020 07:08:00 +0430 Subject: [PATCH 06/22] Add test to cover deque::erase(iter, iter) avoiding self-move-assigns (#1203) Fixes #1176. --- .../test.cpp | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/std/tests/Dev10_881629_vector_erase_return_value/test.cpp b/tests/std/tests/Dev10_881629_vector_erase_return_value/test.cpp index 9b6358318bd..d7aa0dbcfde 100644 --- a/tests/std/tests/Dev10_881629_vector_erase_return_value/test.cpp +++ b/tests/std/tests/Dev10_881629_vector_erase_return_value/test.cpp @@ -44,6 +44,28 @@ void test_case_devcom_776568() { assert(it == c.end()); } +template