From d053ab66a2b609dde6da805bec82653c63873490 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Wed, 10 Apr 2024 21:29:04 +0200 Subject: [PATCH 1/8] ``: Add separate tests for `generator`'s iterator type --- tests/std/include/test_generator_support.hpp | 64 +++++++ tests/std/test.lst | 1 + tests/std/tests/P2502R2_generator/test.cpp | 1 - .../tests/P2502R2_generator_iterator/env.lst | 4 + .../tests/P2502R2_generator_iterator/test.cpp | 163 ++++++++++++++++++ .../tests/P2502R2_generator_promise/test.cpp | 51 +----- 6 files changed, 233 insertions(+), 51 deletions(-) create mode 100644 tests/std/include/test_generator_support.hpp create mode 100644 tests/std/tests/P2502R2_generator_iterator/env.lst create mode 100644 tests/std/tests/P2502R2_generator_iterator/test.cpp diff --git a/tests/std/include/test_generator_support.hpp b/tests/std/include/test_generator_support.hpp new file mode 100644 index 00000000000..f752bf50565 --- /dev/null +++ b/tests/std/include/test_generator_support.hpp @@ -0,0 +1,64 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#pragma once + +#include +#include +#include +#include +#include +#include + +template +class TestAllocator : public std::allocator { +public: + using value_type = T; + using is_always_equal = AlwaysEqual; + using difference_type = DifferenceType; + using size_type = std::make_unsigned_t; + + TestAllocator() = default; + + template + TestAllocator(const TestAllocator&) {} + + T* allocate(const size_type s) { + return static_cast(::operator new(static_cast(s * sizeof(T)), std::align_val_t{alignof(T)})); + } + + void deallocate(T* const p, size_type s) { + ::operator delete(p, s * sizeof(T), std::align_val_t{alignof(T)}); + } + + operator std::pmr::polymorphic_allocator() const { + return {}; + } + + bool operator==(const TestAllocator&) const = default; +}; + +struct MoveOnly { + MoveOnly() = default; + MoveOnly(const MoveOnly&) = delete; + MoveOnly& operator=(const MoveOnly&) = delete; + MoveOnly(MoveOnly&&) = default; + MoveOnly& operator=(MoveOnly&&) = default; +}; + +static_assert(std::movable); +static_assert(!std::copyable); + +struct Immovable { + Immovable() = default; + Immovable(Immovable&&) = delete; + Immovable& operator=(Immovable&&) = delete; +}; + +static_assert(!std::movable); + +template +struct Proxy { + Proxy() {} + Proxy(const T&) {} +}; diff --git a/tests/std/test.lst b/tests/std/test.lst index 2d7e7cee3a3..b368ae753c9 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -650,6 +650,7 @@ tests\P2474R2_views_repeat_death tests\P2494R2_move_only_range_adaptors tests\P2502R2_generator tests\P2502R2_generator_death +tests\P2502R2_generator_iterator tests\P2502R2_generator_promise tests\P2505R5_monadic_functions_for_std_expected tests\P2510R3_text_formatting_pointers diff --git a/tests/std/tests/P2502R2_generator/test.cpp b/tests/std/tests/P2502R2_generator/test.cpp index ddc3af912ed..2232e29981b 100644 --- a/tests/std/tests/P2502R2_generator/test.cpp +++ b/tests/std/tests/P2502R2_generator/test.cpp @@ -33,7 +33,6 @@ constexpr bool static_checks() { // Non-portable size checks static_assert(sizeof(G) == sizeof(void*)); static_assert(sizeof(typename G::promise_type) == 3 * sizeof(void*)); - static_assert(sizeof(ranges::iterator_t) == sizeof(void*)); return true; } diff --git a/tests/std/tests/P2502R2_generator_iterator/env.lst b/tests/std/tests/P2502R2_generator_iterator/env.lst new file mode 100644 index 00000000000..642f530ffad --- /dev/null +++ b/tests/std/tests/P2502R2_generator_iterator/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_latest_matrix.lst diff --git a/tests/std/tests/P2502R2_generator_iterator/test.cpp b/tests/std/tests/P2502R2_generator_iterator/test.cpp new file mode 100644 index 00000000000..940c6f801ff --- /dev/null +++ b/tests/std/tests/P2502R2_generator_iterator/test.cpp @@ -0,0 +1,163 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include + +#include "test_generator_support.hpp" + +using namespace std; + +template +constexpr bool always_false = false; + +template +generator generate_zero() { + co_return; +} + +template + requires (is_reference_v && default_initializable<_Gen_value_t>) || default_initializable +generator generate_one() { + if constexpr (!is_reference_v) { + co_yield Ref{}; + } else if constexpr (is_lvalue_reference_v) { + _Gen_value_t val{}; + remove_reference_t ref{move(val)}; + co_yield ref; + } else if constexpr (is_rvalue_reference_v) { + _Gen_value_t val{}; + co_yield move(val); + } +} + +template +generator generate_one_recursively() { + co_yield ranges::elements_of{generate_zero()}; + co_yield ranges::elements_of{generate_one()}; + co_yield ranges::elements_of{generate_zero()}; +} + +template +void test_one() { + using Gen = generator; + using Iter = ranges::iterator_t; + static_assert(input_iterator); + + // Test member types + static_assert(same_as, remove_cvref_t, V>>); + static_assert(same_as); + + // Test copying functions + static_assert(!is_copy_constructible_v); + static_assert(!is_copy_assignable_v); + + { // Test move constructor + Gen g = generate_zero(); + Iter i = g.begin(); + Iter j = move(i); + assert(j == default_sentinel); + + static_assert(is_nothrow_move_constructible_v); + } + + { // Test move assignment operator + Gen g1 = generate_one(); + Iter i = g1.begin(); + Gen g2 = generate_zero(); + Iter j = g2.begin(); + + same_as decltype(auto) k = (i = move(j)); + assert(&k == &i); + assert(k == default_sentinel); + + static_assert(is_nothrow_move_assignable_v); + } + + { // Test indirection + auto g = generate_one(); + auto i = g.begin(); + + [[maybe_unused]] same_as<_Gen_reference_t> decltype(auto) r = *i; + + using NoRef = remove_reference_t; + if constexpr (default_initializable && equality_comparable) { + assert(r == NoRef{}); + } + } + + { // Test pre-incrementation + auto g = generate_one_recursively(); + auto i = g.begin(); + + same_as decltype(auto) i_ref = ++i; + assert(&i_ref == &i); + assert(i_ref == default_sentinel); + } + + { // Test post-incrementation + auto g = generate_one_recursively(); + auto i = g.begin(); + i++; + assert(i == default_sentinel); + + static_assert(is_void_v); + } + + { // Test equal operator + auto g1 = generate_one(); + auto i = g1.begin(); + auto g2 = generate_zero(); + auto j = g2.begin(); + + same_as decltype(auto) b1 = i == default_sentinel; + assert(!b1); + + same_as decltype(auto) b2 = default_sentinel == j; + assert(b2); + + same_as decltype(auto) b3 = i != default_sentinel; + assert(b3); + + same_as decltype(auto) b4 = default_sentinel != j; + assert(!b4); + } + + // Test sizeof + static_assert(sizeof(Iter) == sizeof(void*)); // NB: implementation defined +} + +template +void test_with_allocator() { + test_one(); + test_one>(); + test_one>(); + test_one>(); +} + +template +void test_with_type() { + test_with_allocator(); + test_with_allocator(); + test_with_allocator(); + test_with_allocator(); + test_with_allocator(); + + test_with_allocator, T>(); + test_with_allocator&, T>(); + test_with_allocator&, T>(); + test_with_allocator&&, T>(); + test_with_allocator&&, T>(); +} + +int main() { + test_with_type(); + test_with_type(); + test_with_type(); + test_with_type(); +} diff --git a/tests/std/tests/P2502R2_generator_promise/test.cpp b/tests/std/tests/P2502R2_generator_promise/test.cpp index 38cccc9ca40..43958421fd7 100644 --- a/tests/std/tests/P2502R2_generator_promise/test.cpp +++ b/tests/std/tests/P2502R2_generator_promise/test.cpp @@ -18,37 +18,10 @@ #include #include "range_algorithm_support.hpp" +#include "test_generator_support.hpp" using namespace std; -template -class TestAllocator : public allocator { -public: - using value_type = T; - using is_always_equal = AlwaysEqual; - using difference_type = DifferenceType; - using size_type = make_unsigned_t; - - TestAllocator() = default; - - template - TestAllocator(const TestAllocator&) {} - - T* allocate(const size_type s) { - return static_cast(::operator new(static_cast(s * sizeof(T)), align_val_t{alignof(T)})); - } - - void deallocate(T* const p, size_type s) { - ::operator delete(p, s * sizeof(T), align_val_t{alignof(T)}); - } - - operator pmr::polymorphic_allocator() const { - return {}; - } - - bool operator==(const TestAllocator&) const = default; -}; - template concept HasOperatorNew = requires(Args&&... args) { { Promise::operator new(forward(args)...) } -> same_as; @@ -62,28 +35,6 @@ struct generator_allocator> { using type = Alloc; }; -struct MoveOnly { - MoveOnly(const MoveOnly&) = delete; - MoveOnly& operator=(const MoveOnly&) = delete; - MoveOnly(MoveOnly&&) = default; - MoveOnly& operator=(MoveOnly&&) = default; -}; - -static_assert(movable); -static_assert(!copyable); - -struct Immovable { - Immovable(Immovable&&) = delete; - Immovable& operator=(Immovable&&) = delete; -}; - -static_assert(!movable); - -template -struct Proxy { - Proxy(const T&); // not defined -}; - template requires convertible_to, typename Gen::yielded> void test_yield_elements_of_range(typename Gen::promise_type& p) { From 48ea83c16544bca804845f4f3e7a51478c8e93f5 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Wed, 10 Apr 2024 21:48:35 +0200 Subject: [PATCH 2/8] Formatting --- tests/std/tests/P2502R2_generator_iterator/test.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/std/tests/P2502R2_generator_iterator/test.cpp b/tests/std/tests/P2502R2_generator_iterator/test.cpp index 940c6f801ff..21d823ab7ac 100644 --- a/tests/std/tests/P2502R2_generator_iterator/test.cpp +++ b/tests/std/tests/P2502R2_generator_iterator/test.cpp @@ -48,6 +48,7 @@ void test_one() { using Gen = generator; using Iter = ranges::iterator_t; static_assert(input_iterator); + static_assert(sizeof(Iter) == sizeof(void*)); // NB: implementation defined // Test member types static_assert(same_as, remove_cvref_t, V>>); @@ -75,7 +76,6 @@ void test_one() { same_as decltype(auto) k = (i = move(j)); assert(&k == &i); assert(k == default_sentinel); - static_assert(is_nothrow_move_assignable_v); } @@ -127,9 +127,6 @@ void test_one() { same_as decltype(auto) b4 = default_sentinel != j; assert(!b4); } - - // Test sizeof - static_assert(sizeof(Iter) == sizeof(void*)); // NB: implementation defined } template From 9af3520c8dffe30bd9b58913a4cccc91d8ed93cf Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Thu, 11 Apr 2024 11:58:19 +0200 Subject: [PATCH 3/8] Fix problems with LLVM-56507 --- tests/std/tests/P2502R2_generator_iterator/test.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/std/tests/P2502R2_generator_iterator/test.cpp b/tests/std/tests/P2502R2_generator_iterator/test.cpp index 21d823ab7ac..c1bf97c1ae3 100644 --- a/tests/std/tests/P2502R2_generator_iterator/test.cpp +++ b/tests/std/tests/P2502R2_generator_iterator/test.cpp @@ -36,12 +36,14 @@ generator generate_one() { } } +#if !(defined(__clang__) && defined(_M_IX86)) // TRANSITION, LLVM-56507 template generator generate_one_recursively() { co_yield ranges::elements_of{generate_zero()}; co_yield ranges::elements_of{generate_one()}; co_yield ranges::elements_of{generate_zero()}; } +#endif // ^^^ no workaround ^^^ template void test_one() { @@ -91,6 +93,7 @@ void test_one() { } } +#if !(defined(__clang__) && defined(_M_IX86)) // TRANSITION, LLVM-56507 { // Test pre-incrementation auto g = generate_one_recursively(); auto i = g.begin(); @@ -108,6 +111,7 @@ void test_one() { static_assert(is_void_v); } +#endif // ^^^ no workaround ^^^ { // Test equal operator auto g1 = generate_one(); From 595b300d260b56bb8d104bbfa371bc59985ec046 Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Tue, 16 Apr 2024 13:16:11 -0700 Subject: [PATCH 4/8] remove unused `always_false` variable template --- tests/std/tests/P2502R2_generator_iterator/test.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/std/tests/P2502R2_generator_iterator/test.cpp b/tests/std/tests/P2502R2_generator_iterator/test.cpp index c1bf97c1ae3..0472ecd4bec 100644 --- a/tests/std/tests/P2502R2_generator_iterator/test.cpp +++ b/tests/std/tests/P2502R2_generator_iterator/test.cpp @@ -13,9 +13,6 @@ using namespace std; -template -constexpr bool always_false = false; - template generator generate_zero() { co_return; From 95bb7a496877d2197938c613ee7cc391425cd0d8 Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Tue, 16 Apr 2024 13:19:36 -0700 Subject: [PATCH 5/8] Avoid internal `_Gen_meow_t` alias templates --- .../tests/P2502R2_generator_iterator/test.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/tests/std/tests/P2502R2_generator_iterator/test.cpp b/tests/std/tests/P2502R2_generator_iterator/test.cpp index 0472ecd4bec..0ec8d13426b 100644 --- a/tests/std/tests/P2502R2_generator_iterator/test.cpp +++ b/tests/std/tests/P2502R2_generator_iterator/test.cpp @@ -18,17 +18,23 @@ generator generate_zero() { co_return; } -template - requires (is_reference_v && default_initializable<_Gen_value_t>) || default_initializable +template +using gen_value_t = conditional_t, remove_cvref_t, V>; + +template +using gen_reference_t = conditional_t, Ref&&, Ref>; + +template > + requires (is_reference_v && default_initializable) || default_initializable generator generate_one() { if constexpr (!is_reference_v) { co_yield Ref{}; } else if constexpr (is_lvalue_reference_v) { - _Gen_value_t val{}; + ValueType val{}; remove_reference_t ref{move(val)}; co_yield ref; } else if constexpr (is_rvalue_reference_v) { - _Gen_value_t val{}; + ValueType val{}; co_yield move(val); } } @@ -50,7 +56,7 @@ void test_one() { static_assert(sizeof(Iter) == sizeof(void*)); // NB: implementation defined // Test member types - static_assert(same_as, remove_cvref_t, V>>); + static_assert(same_as>); static_assert(same_as); // Test copying functions @@ -82,7 +88,7 @@ void test_one() { auto g = generate_one(); auto i = g.begin(); - [[maybe_unused]] same_as<_Gen_reference_t> decltype(auto) r = *i; + [[maybe_unused]] same_as> decltype(auto) r = *i; using NoRef = remove_reference_t; if constexpr (default_initializable && equality_comparable) { From 6821911ff7f82c85cd646257353854e88beb9bb5 Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Tue, 16 Apr 2024 13:20:45 -0700 Subject: [PATCH 6/8] Separate out proxy-and-non-proxy reference cases in generate_one --- .../tests/P2502R2_generator_iterator/test.cpp | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/tests/std/tests/P2502R2_generator_iterator/test.cpp b/tests/std/tests/P2502R2_generator_iterator/test.cpp index 0ec8d13426b..28e21538769 100644 --- a/tests/std/tests/P2502R2_generator_iterator/test.cpp +++ b/tests/std/tests/P2502R2_generator_iterator/test.cpp @@ -25,17 +25,27 @@ template using gen_reference_t = conditional_t, Ref&&, Ref>; template > - requires (is_reference_v && default_initializable) || default_initializable + requires default_initializable + && (same_as, ValueType> || constructible_from, ValueType&>) generator generate_one() { - if constexpr (!is_reference_v) { - co_yield Ref{}; - } else if constexpr (is_lvalue_reference_v) { - ValueType val{}; - remove_reference_t ref{move(val)}; - co_yield ref; - } else if constexpr (is_rvalue_reference_v) { + if constexpr (same_as, ValueType>) { + // non-proxy reference case + if constexpr (is_reference_v) { + remove_reference_t val{}; + co_yield static_cast(val); + } else { + co_yield ValueType{}; + } + } else { ValueType val{}; - co_yield move(val); + // proxy reference case + if constexpr (is_reference_v) { + // yielding a non-prvalue proxy reference is super weird, but not forbidden + remove_reference_t ref{val}; + co_yield static_cast(ref); + } else { + co_yield Ref{val}; + } } } From d4ba1361a93e9593e6c413d94d39749092c13e4b Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Tue, 16 Apr 2024 13:21:56 -0700 Subject: [PATCH 7/8] Proxy need not be default constructible --- tests/std/include/test_generator_support.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/std/include/test_generator_support.hpp b/tests/std/include/test_generator_support.hpp index f752bf50565..6a9ab7db145 100644 --- a/tests/std/include/test_generator_support.hpp +++ b/tests/std/include/test_generator_support.hpp @@ -59,6 +59,5 @@ static_assert(!std::movable); template struct Proxy { - Proxy() {} Proxy(const T&) {} }; From af29ad105216cf571fc394e358ef80bf1b130ba5 Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Tue, 16 Apr 2024 13:26:49 -0700 Subject: [PATCH 8/8] Teach Proxy to compare with T --- tests/std/include/test_generator_support.hpp | 20 ++++++++++++++++++- .../tests/P2502R2_generator_iterator/test.cpp | 8 ++++---- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/tests/std/include/test_generator_support.hpp b/tests/std/include/test_generator_support.hpp index 6a9ab7db145..3fa0b5dfa88 100644 --- a/tests/std/include/test_generator_support.hpp +++ b/tests/std/include/test_generator_support.hpp @@ -58,6 +58,24 @@ struct Immovable { static_assert(!std::movable); template -struct Proxy { +class Proxy { +public: Proxy(const T&) {} }; + +template +class Proxy { +public: + Proxy(const T& _value_) : value(_value_) {} + + bool operator==(const Proxy& other) const { + return value == other.value; + } + + bool operator==(const T& x) const { + return value == x; + } + +private: + const T& value; +}; diff --git a/tests/std/tests/P2502R2_generator_iterator/test.cpp b/tests/std/tests/P2502R2_generator_iterator/test.cpp index 28e21538769..6e9954ab450 100644 --- a/tests/std/tests/P2502R2_generator_iterator/test.cpp +++ b/tests/std/tests/P2502R2_generator_iterator/test.cpp @@ -98,11 +98,11 @@ void test_one() { auto g = generate_one(); auto i = g.begin(); - [[maybe_unused]] same_as> decltype(auto) r = *i; + same_as> decltype(auto) r = *i; - using NoRef = remove_reference_t; - if constexpr (default_initializable && equality_comparable) { - assert(r == NoRef{}); + using ValueType = gen_value_t; + if constexpr (default_initializable && equality_comparable) { + assert(r == ValueType{}); } }