diff options
Diffstat (limited to 'libstdc++-v3/testsuite')
21 files changed, 1055 insertions, 37 deletions
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/class_mandate_neg.cc b/libstdc++-v3/testsuite/23_containers/mdspan/class_mandate_neg.cc new file mode 100644 index 0000000..de19b6d --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/mdspan/class_mandate_neg.cc @@ -0,0 +1,41 @@ +// { dg-do compile { target c++23 } } +#include<mdspan> + +#include <cstdint> +#include "layout_like.h" + +struct ExtentsLike +{ + using index_type = int; + using size_type = unsigned int; + using rank_type = size_t; + + static constexpr size_t rank() { return 1; } + static constexpr size_t rank_dynamic() { return 0; } +}; + +constexpr bool +test_custom_extents_type() +{ + std::mdspan<double, ExtentsLike> md1; // { dg-error "required from here" } + return true; +} +static_assert(test_custom_extents_type()); + +constexpr bool +test_element_type_mismatch() +{ + using E = std::extents<int, 1>; + using L = std::layout_right; + using A = std::default_accessor<double>; + + [[maybe_unused]] std::mdspan<float, E, L, A> md2; // { dg-error "required from here" } + return true; +}; +static_assert(test_element_type_mismatch()); + +// { dg-prune-output "Extents must be a specialization of std::extents" } +// { dg-prune-output "no type named '_S_storage'" } +// { dg-prune-output "non-constant condition" } +// { dg-prune-output "static assertion failed" } +// { dg-prune-output "__glibcxx_assert" } diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/extents/class_mandates_neg.cc b/libstdc++-v3/testsuite/23_containers/mdspan/extents/class_mandates_neg.cc index f9c1c01..67d18fe 100644 --- a/libstdc++-v3/testsuite/23_containers/mdspan/extents/class_mandates_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/class_mandates_neg.cc @@ -7,6 +7,8 @@ std::extents<uint8_t, size_t(1) << 9> e1; // { dg-error "from here" } std::extents<char, 1> e2; // { dg-error "from here" } std::extents<bool, 1> e3; // { dg-error "from here" } std::extents<double, 1> e4; // { dg-error "from here" } + // { dg-prune-output "dynamic or representable as IndexType" } // { dg-prune-output "signed or unsigned integer" } // { dg-prune-output "invalid use of incomplete type" } +// { dg-prune-output "non-constant condition for static assertion" } diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/extents/custom_integer.cc b/libstdc++-v3/testsuite/23_containers/mdspan/extents/custom_integer.cc index 2907ad1..404755b 100644 --- a/libstdc++-v3/testsuite/23_containers/mdspan/extents/custom_integer.cc +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/custom_integer.cc @@ -2,38 +2,13 @@ #include <mdspan> #include <testsuite_hooks.h> +#include "int_like.h" // Test construction from a custom integer-like object, that has // no copy/move ctor or copy/move assignment operator. constexpr size_t dyn = std::dynamic_extent; -class IntLike -{ -public: - explicit - IntLike(int i) - : _M_i(i) - { } - - IntLike() = delete; - IntLike(const IntLike&) = delete; - IntLike(IntLike&&) = delete; - - const IntLike& - operator=(const IntLike&) = delete; - - const IntLike& - operator=(IntLike&&) = delete; - - constexpr - operator int() const noexcept - { return _M_i; } - -private: - int _M_i; -}; - static_assert(std::is_convertible_v<IntLike, int>); static_assert(std::is_nothrow_constructible_v<int, IntLike>); diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/extents/extents_mismatch_neg.cc b/libstdc++-v3/testsuite/23_containers/mdspan/extents/extents_mismatch_neg.cc new file mode 100644 index 0000000..b35e531 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/extents_mismatch_neg.cc @@ -0,0 +1,35 @@ +// { dg-do compile { target c++23 } } +#include<mdspan> + +#include <cstdint> + +constexpr size_t dyn = std::dynamic_extent; + +constexpr bool +test_dyn2sta_extents_mismatch_00() +{ + auto e0 = std::extents<int, dyn>{1}; + [[maybe_unused]] auto e1 = std::extents<int, 2>{e0}; // { dg-error "expansion of" } + return true; +} +static_assert(test_dyn2sta_extents_mismatch_00()); // { dg-error "expansion of" } + +constexpr bool +test_dyn2sta_extents_mismatch_01() +{ + [[maybe_unused]] auto e = std::extents<int, 1, dyn>{2, 2}; // { dg-error "expansion of" } + return true; +} +static_assert(test_dyn2sta_extents_mismatch_01()); // { dg-error "expansion of" } + +constexpr bool +test_dyn2sta_extents_mismatch_02() +{ + std::array<int, 2> exts{2, 2}; + [[maybe_unused]] auto e = std::extents<int, 1, dyn>{exts}; // { dg-error "expansion of" } + return true; +} +static_assert(test_dyn2sta_extents_mismatch_02()); // { dg-error "expansion of" } + +// { dg-prune-output "non-constant condition for static assertion" } +// { dg-prune-output "__glibcxx_assert" } diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/extents/int_like.h b/libstdc++-v3/testsuite/23_containers/mdspan/extents/int_like.h new file mode 100644 index 0000000..f39f4cc --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/int_like.h @@ -0,0 +1,30 @@ +#ifndef TEST_MDSPAN_INT_LIKE_H +#define TEST_MDSPAN_INT_LIKE_H + +class IntLike +{ +public: + explicit + IntLike(int i) + : _M_i(i) + { } + + IntLike() = delete; + IntLike(const IntLike&) = delete; + IntLike(IntLike&&) = delete; + + const IntLike& + operator=(const IntLike&) = delete; + + const IntLike& + operator=(IntLike&&) = delete; + + constexpr + operator int() const noexcept + { return _M_i; } + +private: + int _M_i; +}; + +#endif // TEST_MDSPAN_INT_LIKE_H diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/layout_like.h b/libstdc++-v3/testsuite/23_containers/mdspan/layout_like.h new file mode 100644 index 0000000..6a0f8ca --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/mdspan/layout_like.h @@ -0,0 +1,83 @@ +#ifndef TEST_MDSPAN_LAYOUT_LIKE_H +#define TEST_MDSPAN_LAYOUT_LIKE_H 1 + +struct LayoutLike +{ + template<typename Extents> + class mapping + { + public: + using extents_type = Extents; + using index_type = typename extents_type::index_type; + using size_type = typename extents_type::size_type; + using rank_type = typename extents_type::rank_type; + using layout_type = LayoutLike; + + constexpr + mapping() noexcept = default; + + constexpr + mapping(Extents exts) + : m_exts(exts) + { } + + constexpr const extents_type& + extents() const noexcept { return m_exts; } + + constexpr index_type + required_span_size() const noexcept + { + for (size_t i = 0; i < extents_type::rank(); ++i) + if (m_exts.extent(i) == 0) + return 0; + return 1; + } + + template<typename... Indices> + requires (sizeof...(Indices) == extents_type::rank()) + constexpr index_type + operator()(Indices...) const noexcept + { return 0; } + + static constexpr index_type + stride(rank_type) noexcept + { return 0; } + + static constexpr bool + is_always_unique() noexcept + { return false; } + + static constexpr bool + is_always_exhaustive() noexcept + { return true; } + + static constexpr bool + is_always_strided() noexcept + { return true; } + + constexpr bool + is_unique() noexcept + { + if (required_span_size() == 0) + return true; + + for (size_t i = 0; i < extents_type::rank(); ++i) + if (m_exts.extent(i) > 1) + return false; + return true; + } + + static constexpr bool + is_exhaustive() noexcept + { return true; } + + static constexpr bool + is_strided() noexcept + { return true; } + + private: + Extents m_exts; + }; +}; + +#endif diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/debug/out_of_bounds_neg.cc b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/debug/out_of_bounds_neg.cc new file mode 100644 index 0000000..fb8ff01 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/debug/out_of_bounds_neg.cc @@ -0,0 +1,30 @@ +// { dg-do compile { target c++23 } } +// { dg-require-debug-mode "" } +#include<mdspan> + +template<typename Layout> + constexpr bool + test_out_of_bounds_1d() + { + auto m = typename Layout::mapping<std::extents<int, 0>>{}; + (void) m(0); // { dg-error "expansion of" } + return true; + } +static_assert(test_out_of_bounds_1d<std::layout_left>()); // { dg-error "expansion of" } +static_assert(test_out_of_bounds_1d<std::layout_right>()); // { dg-error "expansion of" } +static_assert(test_out_of_bounds_1d<std::layout_stride>()); // { dg-error "expansion of" } + +template<typename Layout> + constexpr bool + test_out_of_bounds_3d() + { + auto m = typename Layout::mapping<std::extents<int, 3, 5, 7>>{}; + (void) m(2, 5, 5); // { dg-error "expansion of" } + return true; + } +static_assert(test_out_of_bounds_3d<std::layout_left>()); // { dg-error "expansion of" } +static_assert(test_out_of_bounds_3d<std::layout_right>()); // { dg-error "expansion of" } +static_assert(test_out_of_bounds_3d<std::layout_stride>()); // { dg-error "expansion of" } + +// { dg-prune-output "non-constant condition for static assertion" } +// { dg-prune-output "__glibcxx_assert" } diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc b/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc new file mode 100644 index 0000000..9252273 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc @@ -0,0 +1,643 @@ +// { dg-do run { target c++23 } } +#include <mdspan> + +#include <testsuite_hooks.h> +#include "extents/int_like.h" +#include "layout_like.h" + +constexpr auto dyn = std::dynamic_extent; + +template<typename MDSpan, typename T, typename E, typename L = std::layout_right, + typename A = std::default_accessor<T>> + constexpr void + assert_typedefs() + { + static_assert(std::same_as<typename MDSpan::extents_type, E>); + static_assert(std::same_as<typename MDSpan::layout_type, L>); + static_assert(std::same_as<typename MDSpan::accessor_type, A>); + static_assert(std::same_as<typename MDSpan::mapping_type, + typename L::mapping<E>>); + static_assert(std::same_as<typename MDSpan::element_type, T>); + static_assert(std::same_as<typename MDSpan::value_type, + std::remove_const_t<T>>); + static_assert(std::same_as<typename MDSpan::index_type, + typename E::index_type>); + static_assert(std::same_as<typename MDSpan::size_type, + typename E::size_type>); + static_assert(std::same_as<typename MDSpan::rank_type, + typename E::rank_type>); + static_assert(std::same_as<typename MDSpan::data_handle_type, + typename A::data_handle_type>); + static_assert(std::same_as<typename MDSpan::reference, + typename A::reference>); + } + +template<typename T, typename E, typename L, template<typename U> typename A> + constexpr void + test_typedefs() + { assert_typedefs<std::mdspan<T, E, L, A<T>>, T, E, L, A<T>>(); } + +constexpr void +test_typedefs_all() +{ + using E = std::extents<int, 1, 2>; + using L = std::layout_left; + + test_typedefs<double, E, L, std::default_accessor>(); + test_typedefs<const double, E, L, std::default_accessor>(); +} + +template<typename MDSpan> + constexpr void + test_rank() + { + using Extents = typename MDSpan::extents_type; + static_assert(MDSpan::rank() == Extents::rank()); + static_assert(MDSpan::rank_dynamic() == Extents::rank_dynamic()); + } + +constexpr bool +test_rank_all() +{ + test_rank<std::mdspan<double, std::extents<int>>>(); + test_rank<std::mdspan<double, std::extents<int, 1>>>(); + test_rank<std::mdspan<double, std::extents<int, dyn>>>(); + return true; +} + +template<typename Extents> + constexpr void + test_extent(Extents exts) + { + double data = 1.0; + auto md = std::mdspan(&data, exts); + using MDSpan = decltype(md); + + for(size_t i = 0; i < MDSpan::rank(); ++i) + { + VERIFY(MDSpan::static_extent(i) == Extents::static_extent(i)); + VERIFY(md.extent(i) == exts.extent(i)); + } + } + +constexpr bool +test_extent_all() +{ + // For rank == 0, check existence of the methods without calling them. + test_extent(std::extents<int>{}); + test_extent(std::extents<int, 0>{}); + test_extent(std::extents<int, dyn>{}); + return true; +} + +template<typename MDSpan> + constexpr void + test_class_properties() + { + static_assert(std::copyable<MDSpan>); + static_assert(std::is_nothrow_move_constructible_v<MDSpan>); + static_assert(std::is_nothrow_move_assignable_v<MDSpan>); + static_assert(std::is_nothrow_swappable_v<MDSpan>); + constexpr bool trivially_copyable = + std::is_trivially_copyable_v<typename MDSpan::accessor_type> + && std::is_trivially_copyable_v<typename MDSpan::mapping_type> + && std::is_trivially_copyable_v<typename MDSpan::data_handle_type>; + static_assert(std::is_trivially_copyable_v<MDSpan> == trivially_copyable); + } + +constexpr bool +test_class_properties_all() +{ + test_class_properties<std::mdspan<double, std::extents<int>>>(); + test_class_properties<std::mdspan<double, std::extents<int, 1>>>(); + test_class_properties<std::mdspan<double, std::extents<int, dyn>>>(); + return true; +} + +constexpr bool +test_default_ctor() +{ + static_assert(!std::is_default_constructible_v<std::mdspan<double, + std::extents<int>>>); + static_assert(!std::is_default_constructible_v<std::mdspan<double, + std::extents<int, 1>>>); + static_assert(std::is_default_constructible_v<std::mdspan<double, + std::extents<int, dyn>>>); + + std::mdspan<double, std::extents<int, dyn>> md; + VERIFY(md.data_handle() == nullptr); + VERIFY(md.empty()); + return true; +} + +constexpr bool +test_from_other() +{ + using Extents = std::extents<int, 3, 5, 7>; + auto exts = Extents{}; + + auto mapping = std::layout_right::mapping(exts); + constexpr size_t n = mapping.required_span_size(); + std::array<double, n> storage{}; + + auto md1 = std::mdspan(storage.data(), exts); + auto md2 = std::mdspan<double, std::dextents<int, 3>>(md1); + + VERIFY(md1.data_handle() == md2.data_handle()); + VERIFY(md1.size() == md2.size()); + + static_assert(!std::is_convertible_v< + std::mdspan<double, std::extents<unsigned int, 2>>, + std::mdspan<double, std::extents<int, 2>>>); + + static_assert(std::is_convertible_v< + std::mdspan<double, std::extents<int, 2>>, + std::mdspan<const double, std::extents<int, 2>>>); + + static_assert(!std::is_constructible_v< + std::mdspan<double, std::extents<int, 2>>, + std::mdspan<const double, std::extents<int, 2>>>); + + return true; +} + +template<typename T, typename E, typename L = std::layout_right, + typename A = std::default_accessor<T>> + constexpr void + assert_deduced_typedefs(auto md) + { assert_typedefs<decltype(md), T, E, L, A>(); } + +constexpr bool +test_from_carray() +{ + constexpr size_t n = 5; + double data[n] = {1.1, 2.2, 3.3, 4.4, 5.5}; + + auto md = std::mdspan(data); + assert_deduced_typedefs<double, std::extents<size_t, n>>(md); + VERIFY(md.rank() == 1); + VERIFY(md.rank_dynamic() == 0); + VERIFY(md[2] == data[2]); + return true; +} + +constexpr bool +test_from_pointer() +{ + double value = 12.3; + auto md = std::mdspan(&value); + assert_deduced_typedefs<double, std::extents<size_t>>(md); + VERIFY(md.rank() == 0); + VERIFY(md.rank_dynamic() == 0); + VERIFY(md[] == value); + return true; +} + +constexpr bool +test_from_pointer_and_shape() +{ + constexpr size_t n = 6; + std::array<double, n> data{1.1, 2.2, 3.3, 4.4, 5.5, 6.6}; + std::array<int, 2> shape{2, 3}; + std::span<const int, 2> shape_view(shape); + + auto verify = [&data](auto md) + { + assert_deduced_typedefs<double, std::dextents<size_t, 2>>(md); + VERIFY(md.rank() == 2); + VERIFY(md.rank_dynamic() == 2); + VERIFY((md[0, 0]) == data[0]); + VERIFY((md[0, 1]) == data[1]); + VERIFY((md[1, 0]) == data[3]); + }; + + verify(std::mdspan(data.data(), shape[0], shape[1])); + verify(std::mdspan(data.data(), shape)); + verify(std::mdspan(data.data(), shape_view)); + + std::mdspan<double, std::dextents<size_t, 2>> md1 = {data.data(), shape}; + verify(md1); + + std::mdspan<double, std::dextents<size_t, 2>> md2 = {data.data(), shape_view}; + verify(md2); + + static_assert(std::is_constructible_v< + std::mdspan<float, std::extents<int, 3, 5>>, float*>); + static_assert(!std::is_constructible_v< + std::mdspan<float, std::extents<int, 3, 5>>, float*, int>); + static_assert(std::is_constructible_v< + std::mdspan<float, std::extents<int, 3, 5>>, float*, int, int>); + static_assert(std::is_constructible_v< + std::mdspan<float, std::extents<int, 3, 5>>, float*, std::span<int, 0>>); + static_assert(std::is_constructible_v< + std::mdspan<float, std::extents<int, 3, 5>>, float*, std::span<int, 2>>); + static_assert(!std::is_convertible_v< + float*, std::mdspan<float, std::extents<int, 3, 5>>>); + + static_assert(std::is_constructible_v< + std::mdspan<float, std::dextents<int, 2>>, float*, std::span<int, 2>>); + static_assert(!std::is_constructible_v< + std::mdspan<float, std::dextents<int, 2>>, float*, std::span<int, 1>>); + static_assert(!std::is_constructible_v< + std::mdspan<float, std::dextents<int, 2>>, float*, std::span<int, 3>>); + static_assert(!std::is_constructible_v< + std::mdspan<float, std::dextents<int, 2>>, float*, std::span<int, dyn>>); + return true; +} + +constexpr bool +test_from_extents() +{ + constexpr size_t n = 3*5*7; + std::array<double, n> storage{}; + using Extents = std::extents<int, 3, 5, 7>; + auto exts = Extents{}; + auto md = std::mdspan(storage.data(), exts); + + assert_deduced_typedefs<double, Extents>(md); + VERIFY(md.data_handle() == storage.data()); + VERIFY(md.extents() == exts); + return true; +} + +constexpr bool +test_from_mapping() +{ + constexpr size_t n = 3*5*7; + std::array<double, n> storage{}; + using Extents = std::extents<int, 3, 5, 7>; + + auto exts = Extents{}; + auto m = std::layout_left::mapping(exts); + auto md = std::mdspan(storage.data(), m); + + assert_deduced_typedefs<double, Extents, std::layout_left>(md); + VERIFY(md.data_handle() == storage.data()); + VERIFY(md.mapping() == m); + return true; +} + +constexpr bool +test_from_accessor() +{ + constexpr size_t n = 3*5*7; + std::array<double, n> storage{}; + using Extents = std::extents<int, 3, 5, 7>; + + auto exts = Extents{}; + auto m = std::layout_left::mapping(exts); + auto a = std::default_accessor<double>{}; + auto md = std::mdspan(storage.data(), m, a); + + assert_deduced_typedefs<double, Extents, std::layout_left>(md); + VERIFY(md.data_handle() == storage.data()); + VERIFY(md.mapping() == m); + return true; +} + +void +test_from_int_like() +{ + constexpr size_t n = 3*5*7; + std::array<double, n> storage{}; + + auto verify = [&](auto md) + { + VERIFY(md.data_handle() == storage.data()); + VERIFY(md.extent(0) == 3); + VERIFY(md.extent(1) == 5); + VERIFY(md.extent(2) == 7); + + VERIFY((md[IntLike(0), 0, IntLike(0)]) == 0.0); + auto zero = std::array{IntLike(0), IntLike(0), IntLike(0)}; + auto zero_view = std::span<IntLike, 3>{zero}; + VERIFY((md[zero]) == 0.0); + VERIFY((md[zero_view]) == 0.0); + }; + + auto shape = std::array{IntLike(3), IntLike(5), IntLike(7)}; + auto shape_view = std::span<IntLike, 3>{shape}; + verify(std::mdspan(storage.data(), IntLike(3), 5, IntLike(7))); + verify(std::mdspan(storage.data(), shape)); + verify(std::mdspan(storage.data(), shape_view)); +} + +template<typename T, bool NothrowConstructible = true, + bool NothrowAssignable = true> + class OpaqueAccessor + { + struct Handle + { + constexpr + Handle(T * other) + : ptr(other) + { } + + constexpr + Handle(const Handle&) noexcept(NothrowConstructible) = default; + + constexpr + Handle(Handle&&) noexcept(NothrowConstructible) = default; + + constexpr Handle& + operator=(const Handle&) noexcept(NothrowAssignable) = default; + + constexpr Handle& + operator=(Handle&&) noexcept(NothrowAssignable) = default; + + T * ptr; + }; + + public: + using element_type = T; + using reference = T&; + using data_handle_type = Handle; + using offset_policy = OpaqueAccessor; + + reference + access(data_handle_type p, size_t i) const + { + ++access_count; + return p.ptr[i]; + } + + typename offset_policy::data_handle_type + offset(data_handle_type p, size_t i) const + { + ++offset_count; + return typename offset_policy::data_handle_type{(void*)(p.ptr + i)}; + } + + mutable size_t access_count = 0; + mutable size_t offset_count = 0; + }; + +void +test_from_opaque_accessor() +{ + constexpr size_t n = 3*5*7; + std::array<double, n> storage{}; + using Extents = std::extents<int, 3, 5, 7>; + + auto exts = Extents{}; + auto m = std::layout_left::mapping(exts); + auto a = OpaqueAccessor<double>{}; + auto handle = OpaqueAccessor<double>::data_handle_type{storage.data()}; + auto md = std::mdspan(handle, m, a); + + using MDSpan = decltype(md); + static_assert(std::same_as<MDSpan::accessor_type, decltype(a)>); + + VERIFY((md[0, 0, 0]) == 0.0); + VERIFY(md.accessor().access_count == 1); + + VERIFY((md[2, 4, 6]) == 0.0); + VERIFY(md.accessor().access_count == 2); +} + +template<typename T, typename Base> + class BaseClassAccessor + { + public: + using element_type = T; + using reference = Base&; + using data_handle_type = T*; + using offset_policy = BaseClassAccessor; + + static_assert(std::common_reference_with<reference&&, element_type&>); + + reference + access(data_handle_type p, size_t i) const + { return p[i]; } + + typename offset_policy::data_handle_type + offset(data_handle_type p, size_t i) const + { return typename offset_policy::data_handle_type{p + i}; } + }; + +struct Base +{ + double value = 1.0; +}; + +struct Derived : Base +{ + double value = 2.0; +}; + +void +test_from_base_class_accessor() +{ + constexpr size_t n = 3*5*7; + std::array<Derived, n> storage{}; + using Extents = std::extents<int, 3, 5, 7>; + + auto exts = Extents{}; + auto m = std::layout_left::mapping(exts); + auto a = BaseClassAccessor<Derived, Base>{}; + auto md = std::mdspan(storage.data(), m, a); + + using MDSpan = decltype(md); + static_assert(std::same_as<MDSpan::accessor_type, decltype(a)>); + static_assert(std::same_as<decltype(md[0, 0, 0]), Base&>); + VERIFY((md[0, 0, 0].value) == 1.0); + VERIFY((md[2, 4, 6].value) == 1.0); +} + +constexpr bool +test_from_mapping_like() +{ + double data = 1.1; + auto m = LayoutLike::mapping<std::extents<int, 1, 2, 3>>{}; + auto md = std::mdspan(&data, m); + VERIFY((md[0, 0, 0]) == data); + VERIFY((md[0, 1, 2]) == data); + return true; +} + +template<typename MDSpan> + constexpr void + test_empty(MDSpan md) + { + VERIFY(md.empty() == (md.size() == 0)); + } + +constexpr bool +test_empty_all() +{ + test_empty(std::mdspan<double, std::extents<int, dyn>>{}); + return true; +} + +constexpr bool +test_access() +{ + using Extents = std::extents<int, 3, 5, 7>; + auto exts = Extents{}; + + auto mapping = std::layout_left::mapping(exts); + constexpr size_t n = mapping.required_span_size(); + std::array<double, n> storage{}; + + auto md = std::mdspan(storage.data(), mapping); + static_assert(std::__mdspan::__mapping_alike<decltype(md)>); + + for(int i = 0; i < exts.extent(0); ++i) + for(int j = 0; j < exts.extent(1); ++j) + for(int k = 0; k < exts.extent(2); ++k) + { + std::array<int, 3> ijk{i, j, k}; + storage[mapping(i, j, k)] = 1.0; + VERIFY((md[i, j, k]) == 1.0); + VERIFY((md[ijk]) == 1.0); + VERIFY((md[std::span(ijk)]) == 1.0); + storage[mapping(i, j, k)] = 0.0; + } + return true; +} + +constexpr bool +test_swap() +{ + using Extents = std::dextents<int, 2>; + auto e1 = Extents{3, 5}; + auto e2 = Extents{7, 11}; + + std::array<double, 3*5> s1{}; + std::array<double, 7*11> s2{}; + + auto md1 = std::mdspan(s1.data(), e1); + auto md2 = std::mdspan(s2.data(), e2); + + std::swap(md1, md2); + + VERIFY(md1.data_handle() == s2.data()); + VERIFY(md2.data_handle() == s1.data()); + + VERIFY(md1.size() == s2.size()); + VERIFY(md2.size() == s1.size()); + return true; +} + +namespace adl +{ + template<typename T> + struct SwappableAccessor + { + using element_type = T; + using reference = T&; + using data_handle_type = T*; + using offset_policy = SwappableAccessor; + + reference + access(data_handle_type p, size_t i) const + { return p[i]; } + + typename offset_policy::data_handle_type + offset(data_handle_type p, size_t i) const + { return p + i; } + + friend void + swap(SwappableAccessor&, SwappableAccessor&) + { ++swap_count; } + + static inline size_t swap_count = 0; + }; +} + +void +test_swap_adl() +{ + using Extents = std::extents<int, dyn>; + using Layout = std::layout_left; + using Accessor = adl::SwappableAccessor<double>; + Accessor::swap_count = 0; + + std::mdspan<double, Extents, Layout, Accessor> m1, m2; + swap(m1, m2); + VERIFY(Accessor::swap_count == 1); +} + +template<bool Constructible, bool Assignable> +constexpr void +test_nothrow_movable() +{ + using Layout = std::layout_left; + using Extents = std::dextents<int, 3>; + using Accessor = OpaqueAccessor<int, Constructible, Assignable>; + using Handle = Accessor::data_handle_type; + static_assert(std::is_nothrow_move_assignable_v<Accessor>); + static_assert(std::is_nothrow_move_constructible_v<Accessor>); + static_assert(std::is_nothrow_move_assignable_v<Handle> == Assignable); + static_assert(std::is_nothrow_move_constructible_v<Handle> == Constructible); + + using MDSpan = std::mdspan<int, Extents, Layout, Accessor>; + static_assert(std::is_nothrow_move_assignable_v<MDSpan> == Assignable); + static_assert(std::is_nothrow_move_constructible_v<MDSpan> == Constructible); +} + +constexpr void +test_nothrow_movable_all() +{ + using MDSpan = std::mdspan<double, std::dextents<int, 3>>; + static_assert(std::is_nothrow_move_assignable_v<MDSpan>); + static_assert(std::is_nothrow_move_constructible_v<MDSpan>); + + test_nothrow_movable<true, true>(); + test_nothrow_movable<true, false>(); + test_nothrow_movable<false, true>(); + test_nothrow_movable<false, false>(); +} + +int +main() +{ + test_typedefs_all(); + + test_rank_all(); + test_extent_all(); + static_assert(test_extent_all()); + + test_class_properties_all(); + static_assert(test_class_properties_all()); + + test_empty_all(); + static_assert(test_empty_all()); + + test_default_ctor(); + static_assert(test_default_ctor()); + + test_from_other(); + static_assert(test_from_other()); + + test_from_carray(); + static_assert(test_from_carray()); + + test_from_pointer_and_shape(); + static_assert(test_from_pointer_and_shape()); + + test_from_extents(); + static_assert(test_from_extents()); + + test_from_mapping(); + static_assert(test_from_mapping()); + + test_from_accessor(); + static_assert(test_from_accessor()); + + test_from_int_like(); + test_from_opaque_accessor(); + test_from_base_class_accessor(); + test_from_mapping_like(); + static_assert(test_from_mapping_like()); + + test_access(); + static_assert(test_access()); + + test_swap(); + static_assert(test_swap()); + test_swap_adl(); + + test_nothrow_movable_all(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/out_of_bounds_neg.cc b/libstdc++-v3/testsuite/23_containers/mdspan/out_of_bounds_neg.cc new file mode 100644 index 0000000..dceae56 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/mdspan/out_of_bounds_neg.cc @@ -0,0 +1,24 @@ +// { dg-do compile { target c++23 } } +#include<mdspan> + +#include "layout_like.h" + +template<typename Layout> +constexpr bool +test_invalid_multi_index() +{ + + double data = 1.1; + auto m = typename Layout::mapping<std::extents<int, 1, 2, 3>>{}; + auto md = std::mdspan(&data, m); + + [[maybe_unused]] double x = md[0, 2, 2]; // { dg-error "expansion of" } + return true; +}; +static_assert(test_invalid_multi_index<LayoutLike>()); // { dg-error "expansion of" } +static_assert(test_invalid_multi_index<std::layout_left>()); // { dg-error "expansion of" } +static_assert(test_invalid_multi_index<std::layout_right>()); // { dg-error "expansion of" } +static_assert(test_invalid_multi_index<std::layout_stride>()); // { dg-error "expansion of" } + +// { dg-prune-output "non-constant condition" } +// { dg-prune-output "__glibcxx_assert" } diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/version.cc b/libstdc++-v3/testsuite/23_containers/mdspan/version.cc new file mode 100644 index 0000000..106ee40 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/mdspan/version.cc @@ -0,0 +1,9 @@ +// { dg-do compile { target c++23 } } +#include <mdspan> + +#ifndef __cpp_lib_mdspan +#error "Feature test macro __cpp_lib_mdspan is missing for <mdspan>" +#if __cpp_lib_mdspan < 202207 +#error "Feature test macro __cpp_lib_mdspan has the wrong value" +#endif +#endif diff --git a/libstdc++-v3/testsuite/23_containers/span/contiguous_range_neg.cc b/libstdc++-v3/testsuite/23_containers/span/contiguous_range_neg.cc index c9e9112..890fdf8 100644 --- a/libstdc++-v3/testsuite/23_containers/span/contiguous_range_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/span/contiguous_range_neg.cc @@ -25,6 +25,7 @@ main() { std::deque<int> d{}; std::span<int, std::dynamic_extent> myspan(d); // { dg-error "no match" } + (void) myspan; } // { dg-prune-output "data" } diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/const_container.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/const_container.cc new file mode 100644 index 0000000..e62f158 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_map/const_container.cc @@ -0,0 +1,19 @@ +// { dg-do compile { target c++11 } } + +#include <unordered_map> + +#include <testsuite_hooks.h> + +// PR c++/116369 +const std::unordered_map<int, int> um + { + { 0, 1 }, + { 2, 3 }, + { 4, 5 } + }; + +int main() +{ + VERIFY( um.size() == 3 ); + VERIFY( um.find(0) != um.end() ); +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/const_container.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/const_container.cc new file mode 100644 index 0000000..3da1e33 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/const_container.cc @@ -0,0 +1,22 @@ +// { dg-do compile { target c++11 } } + +#include <unordered_map> + +#include <testsuite_hooks.h> + +// PR c++/116369 +const std::unordered_multimap<int, int> umm + { + { 0, 1 }, + { 0, 1 }, + { 2, 3 }, + { 2, 3 }, + { 4, 5 }, + { 4, 5 } + }; + +int main() +{ + VERIFY( umm.size() == 6 ); + VERIFY( umm.find(0) != umm.end() ); +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multiset/const_container.cc b/libstdc++-v3/testsuite/23_containers/unordered_multiset/const_container.cc new file mode 100644 index 0000000..841d25a --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_multiset/const_container.cc @@ -0,0 +1,15 @@ +// { dg-do compile { target c++11 } } + +#include <unordered_set> + +#include <testsuite_hooks.h> + +// PR c++/116369 +const std::unordered_multiset<int> ums + { 0, 0, 1, 1, 2, 2 }; + +int main() +{ + VERIFY( ums.size() == 6 ); + VERIFY( ums.find(0) != ums.end() ); +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/const_container.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/const_container.cc new file mode 100644 index 0000000..ffdbbad --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_set/const_container.cc @@ -0,0 +1,14 @@ +// { dg-do compile { target c++11 } } + +#include <unordered_set> + +#include <testsuite_hooks.h> + +// PR c++/116369 +const std::unordered_set<int> us { 0, 1, 2 }; + +int main() +{ + VERIFY( us.size() == 3 ); + VERIFY( us.find(0) != us.end() ); +} diff --git a/libstdc++-v3/testsuite/23_containers/vector/debug/mutex_association.cc b/libstdc++-v3/testsuite/23_containers/vector/debug/mutex_association.cc index ba2ede0..792ed45 100644 --- a/libstdc++-v3/testsuite/23_containers/vector/debug/mutex_association.cc +++ b/libstdc++-v3/testsuite/23_containers/vector/debug/mutex_association.cc @@ -25,7 +25,7 @@ class container : public __gnu_debug::_Safe_sequence<container> { public: __gnu_cxx::__mutex& - get_mutex() + get_mutex() const { return this->_M_get_mutex(); } }; diff --git a/libstdc++-v3/testsuite/ext/verify_neg.cc b/libstdc++-v3/testsuite/ext/verify_neg.cc new file mode 100644 index 0000000..ce03374 --- /dev/null +++ b/libstdc++-v3/testsuite/ext/verify_neg.cc @@ -0,0 +1,28 @@ +// { dg-do compile { target c++11 } } + +#include <testsuite_hooks.h> + +struct X { explicit operator void*() const { return nullptr; } }; + +void +test_VERIFY(int i) +{ + // This should not be parsed as a function type bool(bool(i)): + VERIFY( bool(i) ); + + // This should not produce warnings about lambda in unevaluated context: + VERIFY( []{ return 1; }() ); + + // Only one expression allowed: + VERIFY(1, 2); // { dg-error "in expansion of macro" } + // { dg-error "compound expression in functional cast" "" { target *-*-* } 0 } + + // A scoped enum is not contextually convertible to bool: + enum class E { E0 }; + VERIFY( E::E0 ); // { dg-error "could not convert" } + + // explicit conversion to void* is not contextually convertible to bool: + X x; + VERIFY( x ); // { dg-error "in expansion of macro" } + // { dg-error "invalid cast .* to type 'bool'" "" { target *-*-* } 0 } +} diff --git a/libstdc++-v3/testsuite/std/time/format/format.cc b/libstdc++-v3/testsuite/std/time/format/format.cc index d6e3583..00affb9 100644 --- a/libstdc++-v3/testsuite/std/time/format/format.cc +++ b/libstdc++-v3/testsuite/std/time/format/format.cc @@ -78,6 +78,13 @@ test_bad_format_strings() VERIFY( not is_format_string_for("{:%OOy}", t) ); VERIFY( not is_format_string_for("{:%OEy}", t) ); VERIFY( not is_format_string_for("{:%EOy}", t) ); + + // weekday and month values for which ok() is false + VERIFY( not is_format_string_for("{:%a}", std::chrono::weekday(8)) ); + VERIFY( not is_format_string_for("{:%A}", std::chrono::weekday(8)) ); + VERIFY( not is_format_string_for("{:%b}", std::chrono::month(13)) ); + VERIFY( not is_format_string_for("{:%h}", std::chrono::month(13)) ); + VERIFY( not is_format_string_for("{:%B}", std::chrono::month(13)) ); } template<typename I> diff --git a/libstdc++-v3/testsuite/std/time/format/pr117214_custom_timeput.cc b/libstdc++-v3/testsuite/std/time/format/pr117214_custom_timeput.cc new file mode 100644 index 0000000..03b9496 --- /dev/null +++ b/libstdc++-v3/testsuite/std/time/format/pr117214_custom_timeput.cc @@ -0,0 +1,37 @@ +// { dg-do run { target c++20 } } + +#include <chrono> +#include <format> +#include <locale> +#include <testsuite_hooks.h> + +struct custom_time_put : std::time_put<char> +{ + iter_type + do_put(iter_type out, std::ios_base& io, char_type fill, const tm* t, + char format, char modifier) const override + { + using Base = std::time_put<char>; + + switch (format) { + case 'a': case 'A': case 'b': case 'h': case 'B': case 'p': + *out++ = '['; + *out++ = format; + *out++ = ']'; + } + return Base::do_put(out, io, fill, t, format, modifier); + } +}; + +int main() +{ + using namespace std::chrono; + std::locale loc(std::locale::classic(), new custom_time_put); +#define test(t, fmt, exp) VERIFY( std::format(loc, fmt, t) == exp ) + test(Monday, "{:L%a}", "[a]Mon"); + test(Monday, "{:L%A}", "[A]Monday"); + test(January, "{:L%b}", "[b]Jan"); + test(January, "{:L%h}", "[h]Jan"); + test(January, "{:L%B}", "[B]January"); + test(1h, "{:L%p}", "[p]AM"); +} diff --git a/libstdc++-v3/testsuite/util/testsuite_containers.h b/libstdc++-v3/testsuite/util/testsuite_containers.h index 37491a4..ab0107f 100644 --- a/libstdc++-v3/testsuite/util/testsuite_containers.h +++ b/libstdc++-v3/testsuite/util/testsuite_containers.h @@ -210,6 +210,9 @@ namespace __gnu_test clit = container.cbegin(bn); assert( ++clit == container.cend(bn) ); + clit = container.begin(bn); + assert( ++clit == container.cend(bn) ); + assert( container.begin(bn) != container.cend(bn) ); } }; @@ -304,6 +307,9 @@ namespace __gnu_test assert( container.cbegin() != container.cend() ); assert( container.cbegin() != container.end() ); assert( container.begin() != container.cend() ); + + auto cit = container.begin(); + assert( cit == container.cbegin() ); } }; diff --git a/libstdc++-v3/testsuite/util/testsuite_hooks.h b/libstdc++-v3/testsuite/util/testsuite_hooks.h index faa01ba..bf34fd1 100644 --- a/libstdc++-v3/testsuite/util/testsuite_hooks.h +++ b/libstdc++-v3/testsuite/util/testsuite_hooks.h @@ -58,16 +58,13 @@ # define _VERIFY_PRINT(S, F, L, P, C) __builtin_printf(S, F, L, P, C) #endif -#define VERIFY(fn) \ - do \ - { \ - if (! (fn)) \ - { \ - _VERIFY_PRINT("%s:%d: %s: Assertion '%s' failed.\n", \ - __FILE__, __LINE__, __PRETTY_FUNCTION__, #fn); \ - __builtin_abort(); \ - } \ - } while (false) +#define VERIFY(...) \ + ((void)((__VA_ARGS__) \ + ? (void)(true ? true : bool(__VA_ARGS__)) \ + : (_VERIFY_PRINT("%s:%d: %s: Assertion '%s' failed.\n", \ + __FILE__, __LINE__, __PRETTY_FUNCTION__, \ + #__VA_ARGS__), \ + __builtin_abort()))) #ifdef _GLIBCXX_HAVE_UNISTD_H # include <unistd.h> |