diff options
Diffstat (limited to 'libstdc++-v3/testsuite')
325 files changed, 17085 insertions, 579 deletions
diff --git a/libstdc++-v3/testsuite/17_intro/headers/c++1998/49745.cc b/libstdc++-v3/testsuite/17_intro/headers/c++1998/49745.cc index 7fafe7b..3b9d2eb 100644 --- a/libstdc++-v3/testsuite/17_intro/headers/c++1998/49745.cc +++ b/libstdc++-v3/testsuite/17_intro/headers/c++1998/49745.cc @@ -131,5 +131,3 @@ #endif int truncate = 0; - -// { dg-xfail-if "PR libstdc++/99995" { c++20 } } diff --git a/libstdc++-v3/testsuite/17_intro/names.cc b/libstdc++-v3/testsuite/17_intro/names.cc index 4458325..e94da9d 100644 --- a/libstdc++-v3/testsuite/17_intro/names.cc +++ b/libstdc++-v3/testsuite/17_intro/names.cc @@ -142,6 +142,10 @@ #define try_emplace ( #endif +#if __cplusplus < 202002L +#define ranges ( +#endif + // These clash with newlib so don't use them. # define __lockable cannot be used as an identifier # define __null_sentinel cannot be used as an identifier @@ -244,6 +248,10 @@ #undef r #undef x #undef y +// <stdlib.h> defines drand48_data::a +#undef a +// <sys/localedef.h> defines _LC_weight_t::n +#undef n // <sys/poll.h> defines pollfd_ext::u on AIX 7.3 #undef u // <sys/var.h> defines vario::v @@ -319,6 +327,7 @@ #ifdef __sun__ // <fenv.h> defines these as members of fex_numeric_t +#undef i #undef l #undef f #undef d @@ -328,8 +337,11 @@ #undef ptr // <sys/timespec_util.h> uses this as parameter #undef r -// <stdlib.h> uses this as member of drand48_data +// <stdlib.h> uses these as members of drand48_data +#undef a #undef x +// <string.h> defines this as a parameter of timingsafe_memcmp +#undef n #endif #ifdef __VXWORKS__ @@ -392,4 +404,8 @@ # endif #endif +// PR libstdc++/119496 +// _Temporary_buffer used to have a member with this name +#define requested_size 1 + #include <bits/stdc++.h> diff --git a/libstdc++-v3/testsuite/18_support/comparisons/type_order/1.cc b/libstdc++-v3/testsuite/18_support/comparisons/type_order/1.cc new file mode 100644 index 0000000..b510494 --- /dev/null +++ b/libstdc++-v3/testsuite/18_support/comparisons/type_order/1.cc @@ -0,0 +1,95 @@ +// Copyright (C) 2025 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// { dg-do compile { target c++26 } } + +#include <compare> + +#if __cpp_lib_type_order != 202506L +# error "__cpp_lib_type_order != 202506" +#endif + +static_assert (std::is_same_v <decltype (std::type_order <int, int>::value), + const std::strong_ordering>); +static_assert (std::is_same_v <decltype (std::type_order_v <char, short>), + const std::strong_ordering>); +struct S; +struct T; +template <typename T> +struct U +{ +}; +typedef int int2; +struct V {}; +namespace +{ + struct W {}; +} + +template <typename T, typename U> +struct eq +{ + constexpr eq () + { + static_assert (std::type_order <T, U>::value == std::strong_ordering::equal); + static_assert (std::type_order <U, T>::value == std::strong_ordering::equal); + static_assert (std::type_order_v <T, U> == std::strong_ordering::equal); + static_assert (std::type_order_v <U, T> == std::strong_ordering::equal); + } +}; +template <typename T, typename U> +struct ne +{ + constexpr ne () + { + static_assert (std::type_order <T, U>::value != std::strong_ordering::equal); + static_assert (std::type_order <U, T>::value != std::strong_ordering::equal); + static_assert (std::type_order <T, U>::value == std::strong_ordering::greater + ? std::type_order <U, T>::value == std::strong_ordering::less + : std::type_order <U, T>::value == std::strong_ordering::greater); + static_assert (std::type_order_v <T, U> != std::strong_ordering::equal); + static_assert (std::type_order_v <U, T> != std::strong_ordering::equal); + static_assert (std::type_order_v <T, U> == std::strong_ordering::greater + ? std::type_order_v <U, T> == std::strong_ordering::less + : std::type_order_v <U, T> == std::strong_ordering::greater); + } +}; + +constexpr eq <void, void> a; +constexpr eq <const void, const void> b; +constexpr eq <int, int> c; +constexpr eq <long int, long int> d; +constexpr eq <const volatile unsigned, const volatile unsigned> e; +constexpr eq <S, S> f; +constexpr eq <U <int>, U <int>> g; +constexpr eq <unsigned[2], unsigned[2]> h; +constexpr eq <int, int2> i; +constexpr eq <int (*) (int, long), int (*) (int, long)> j; +constexpr ne <int, long> k; +constexpr ne <const int, int> l; +constexpr ne <S, T> m; +constexpr ne <int &, int &&> n; +constexpr ne <U <S>, U <T>> o; +constexpr ne <U <short>, U <char>> p; +static_assert (std::type_order_v <S, T> != std::strong_ordering::less + || std::type_order_v <T, V> != std::strong_ordering::less + || std::type_order_v <S, V> == std::strong_ordering::less); +constexpr ne <int (*) (int, long), int (*) (int, int)> q; +constexpr eq <W, W> r; +constexpr ne <V, W> s; +constexpr eq <U <W>, U <W>> t; +constexpr ne <U <V>, U <W>> u; diff --git a/libstdc++-v3/testsuite/18_support/exception_ptr/exception_ptr_cast.cc b/libstdc++-v3/testsuite/18_support/exception_ptr/exception_ptr_cast.cc new file mode 100644 index 0000000..6a6fbfe --- /dev/null +++ b/libstdc++-v3/testsuite/18_support/exception_ptr/exception_ptr_cast.cc @@ -0,0 +1,81 @@ +// { dg-do run { target c++26 } } + +// Copyright (C) 2025 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// exception_ptr_cast. + +#include <exception> +#include <testsuite_hooks.h> + +#if __cpp_lib_exception_ptr_cast != 202506L +# error "__cpp_lib_exception_ptr_cast != 202506" +#endif + +struct A { int a; }; +struct B : A {}; +struct C : B {}; +struct D {}; +struct E : virtual C { int e; virtual ~E () {} }; +struct F : virtual E, virtual C { int f; }; +struct G : virtual F, virtual C, virtual E { + G () : g (4) { a = 1; e = 2; f = 3; } int g; +}; + +void test01() +{ + auto a = std::make_exception_ptr(C{ 42 }); + auto b = std::exception_ptr_cast<C>(a); + VERIFY( b != nullptr ); + VERIFY( b->a == 42 ); + auto c = std::exception_ptr_cast<B>(a); + VERIFY( c == static_cast<const B*>(b) ); + auto d = std::exception_ptr_cast<A>(a); + VERIFY( d == static_cast<const A*>(b) ); + auto e = std::exception_ptr_cast<D>(a); + VERIFY( e == nullptr ); + auto f = std::make_exception_ptr(42L); + auto g = std::exception_ptr_cast<long>(f); + VERIFY( g != nullptr ); + VERIFY( *g == 42L ); + try + { + throw G (); + } + catch (...) + { + auto h = std::current_exception(); + auto i = std::exception_ptr_cast<G>(h); + VERIFY( i != nullptr ); + VERIFY( i->a == 1 && i->e == 2 && i->f == 3 && i->g == 4 ); + auto j = std::exception_ptr_cast<A>(h); + VERIFY( j == static_cast<const A*>(i) ); + auto k = std::exception_ptr_cast<C>(h); + VERIFY( k == static_cast<const C*>(i) ); + auto l = std::exception_ptr_cast<E>(h); + VERIFY( l == static_cast<const E*>(i) ); + auto m = std::exception_ptr_cast<F>(h); + VERIFY( m == static_cast<const F*>(i) ); + auto n = std::exception_ptr_cast<G>(a); + VERIFY( n == nullptr ); + } +} + +int main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/18_support/headers/ciso646/macros-2.cc b/libstdc++-v3/testsuite/18_support/headers/ciso646/macros-2.cc new file mode 100644 index 0000000..a492924 --- /dev/null +++ b/libstdc++-v3/testsuite/18_support/headers/ciso646/macros-2.cc @@ -0,0 +1,7 @@ +// { dg-options " -Wdeprecated -fno-operator-names" } +// { dg-do preprocess } + +// Should get a warning for C++20 and up without -D_GLIBCXX_USE_DEPRECATED=0 +// { dg-warning "not a standard header" "" { target c++20 } 0 } + +#include "macros.cc" diff --git a/libstdc++-v3/testsuite/18_support/headers/ciso646/macros.cc b/libstdc++-v3/testsuite/18_support/headers/ciso646/macros.cc index ab3a041..0cb5168 100644 --- a/libstdc++-v3/testsuite/18_support/headers/ciso646/macros.cc +++ b/libstdc++-v3/testsuite/18_support/headers/ciso646/macros.cc @@ -3,7 +3,6 @@ #include <ciso646> -// { dg-warning "deprecated" "" { target c++17_only } 0 } // { dg-error "not a standard header" "" { target c++20 } 0 } #ifdef and diff --git a/libstdc++-v3/testsuite/20_util/aligned_storage/value.cc b/libstdc++-v3/testsuite/20_util/aligned_storage/value.cc index e2c6f7b5..6a2c424 100644 --- a/libstdc++-v3/testsuite/20_util/aligned_storage/value.cc +++ b/libstdc++-v3/testsuite/20_util/aligned_storage/value.cc @@ -21,14 +21,14 @@ #include <type_traits> #include <testsuite_tr1.h> -struct MSAlignType { } __attribute__((__aligned__)); +struct MSAlignType { } __attribute__((__aligned__)); void test01() { using std::aligned_storage; using std::alignment_of; using namespace __gnu_test; - + const std::size_t align_c = alignment_of<char>::value; static_assert(sizeof(aligned_storage<4, align_c>::type) >= 4, ""); static_assert(__alignof__(aligned_storage<4, align_c>::type) == align_c, ""); @@ -55,9 +55,11 @@ void test01() static_assert(__alignof__(aligned_storage<11, align_ct>::type) == align_ct, ""); +#if !_GLIBCXX_INLINE_VERSION const std::size_t align_msa = alignment_of<MSAlignType>::value; static_assert(sizeof(aligned_storage<5>::type) >= 5, ""); static_assert(__alignof__(aligned_storage<5>::type) == align_msa, ""); +#endif } // { dg-warning "deprecated" "" { target c++23 } 0 } diff --git a/libstdc++-v3/testsuite/20_util/bitset/cons/1.cc b/libstdc++-v3/testsuite/20_util/bitset/cons/1.cc index 0a40b6c..6441332 100644 --- a/libstdc++-v3/testsuite/20_util/bitset/cons/1.cc +++ b/libstdc++-v3/testsuite/20_util/bitset/cons/1.cc @@ -47,6 +47,7 @@ void test01(void) const size_t n3 = 128; try { std::bitset<n3> bit03(str01, 5); + VERIFY(false); } catch(std::invalid_argument& fail) { VERIFY( true ); diff --git a/libstdc++-v3/testsuite/20_util/bitset/cons/6282.cc b/libstdc++-v3/testsuite/20_util/bitset/cons/6282.cc index fafa9fc..ee348c3 100644 --- a/libstdc++-v3/testsuite/20_util/bitset/cons/6282.cc +++ b/libstdc++-v3/testsuite/20_util/bitset/cons/6282.cc @@ -39,6 +39,8 @@ void test02(void) std::bitset<0> z3(std::string("10101010101")); VERIFY( z3.any() == false ); + VERIFY( z1.to_ulong() == 0 ); + VERIFY( (z1.to_string<char,char_traits<char>,allocator<char> >().empty() )); try { z1.set(0); VERIFY( false ); @@ -49,9 +51,6 @@ void test02(void) catch(...) { VERIFY( false ); } - - VERIFY( z1.to_ulong() == 0 ); - VERIFY( (z1.to_string<char,char_traits<char>,allocator<char> >().empty() )); } int main() diff --git a/libstdc++-v3/testsuite/20_util/bitset/cons/string_view.cc b/libstdc++-v3/testsuite/20_util/bitset/cons/string_view.cc new file mode 100644 index 0000000..ec3a6c86 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/bitset/cons/string_view.cc @@ -0,0 +1,132 @@ +// C++26 [bitset.cons] + +// { dg-do run { target c++26 } } + +#ifndef C +# define C char +# define L(s) s +#endif + +#include <bitset> +#include <string> +#include <string_view> +#include <algorithm> // std::reverse, std::transform +#include <stdexcept> +#include <testsuite_hooks.h> + +void test01() +{ + // template<_C,_T> + // constexpr explicit + // bitset(const basic_string_view<_C,_T>, + // size_type pos, size_type n, _C zero, _C one) + try { + std::basic_string_view<C> str(L("stuff smith sessions")); + const std::size_t n = 128; + std::bitset<n> bit(str, 5); + VERIFY(false); + } + catch(std::invalid_argument& fail) { + VERIFY( true ); + } + catch(...) { + VERIFY( false ); + } + + try { + std::basic_string_view<C> str(L("010101000011")); + const std::size_t n = 128; + const auto sz = str.size(); + std::bitset<n> bit(str, 0); + std::basic_string<C> str02; + for (std::size_t i = 0; i < sz; ++i) + str02 += (bit.test(i) ? C('1') : C('0')); + std::reverse(str02.begin(), str02.end()); + VERIFY( str02 == str ); + } + catch(std::invalid_argument& fail) { + VERIFY( false ); + } + catch(...) { + VERIFY( false ); + } + + // substring<C> "010101000011" + // "10100001" + try { + std::basic_string_view<C> str(L("010101000011")); + const std::size_t n = 128; + const auto sz = 8; + std::bitset<n> bit(str, 3, sz); + std::basic_string<C> str02; + for (std::size_t i = 0; i < sz; ++i) + str02 += (bit.test(i) ? C('1') : C('0')); + std::reverse(str02.begin(), str02.end()); + VERIFY( str02 == str.substr(3, sz) ); + } + catch(std::invalid_argument& fail) { + VERIFY( false ); + } + catch(...) { + VERIFY( false ); + } + + // "abababaaaabb", zero = 'a', one = 'b' + try { + std::basic_string_view<C> str(L("010101000011")); + const std::size_t n = 128; + const auto sz = str.size(); + std::basic_string<C> str02(str); + std::transform(str02.cbegin(), str02.cend(), str02.begin(), [](auto c) { + return (c - C('0')) + C('a'); + }); + std::basic_string_view<C> str03(str02); + std::bitset<n> bit(str03, 0, 100, C('a'), C('b')); + std::basic_string<C> str04; + for (std::size_t i = 0; i < sz; ++i) + str04 += (bit.test(i) ? C('1') : C('0')); + std::reverse(str04.begin(), str04.end()); + VERIFY( str04 == str ); + } + catch(std::invalid_argument& fail) { + VERIFY( false ); + } + catch(...) { + VERIFY( false ); + } + + // "aba0aba", zero = 'a', one = 'b', '0' appears + try { + const std::size_t n = 128; + std::basic_string_view<C> str05(L("aba0aba")); + std::bitset<n> bit(str05, 0, 100, C('a'), C('b')); + VERIFY( false ); + } + catch(std::invalid_argument& fail) { + VERIFY( true ); + } + catch(...) { + VERIFY( false ); + } + + // pos > str.size() + try { + std::basic_string_view<C> str(L("010101000011")); + const std::size_t n = 128; + const auto sz = str.size(); + std::bitset<n> bit(str, sz + 1, 100); + VERIFY( false ); + } + catch(std::out_of_range& fail) { + VERIFY( true ); + } + catch(...) { + VERIFY( false ); + } +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/20_util/bitset/cons/string_view_wide.cc b/libstdc++-v3/testsuite/20_util/bitset/cons/string_view_wide.cc new file mode 100644 index 0000000..b53fe74 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/bitset/cons/string_view_wide.cc @@ -0,0 +1,8 @@ +// C++26 [bitset.cons] + +// { dg-do run { target c++26 } } + +#define C wchar_t +#define L(s) L ## s + +#include "./string_view.cc" diff --git a/libstdc++-v3/testsuite/20_util/copyable_function/call.cc b/libstdc++-v3/testsuite/20_util/copyable_function/call.cc new file mode 100644 index 0000000..0ac5348 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/copyable_function/call.cc @@ -0,0 +1,225 @@ +// { dg-do run { target c++26 } } +// { dg-require-effective-target hosted } + +#include <functional> +#include <utility> +#include <testsuite_hooks.h> + +using std::copyable_function; + +using std::is_same_v; +using std::is_invocable_v; +using std::is_nothrow_invocable_v; +using std::invoke_result_t; + +// Check return types +static_assert( is_same_v<void, invoke_result_t<copyable_function<void()>>> ); +static_assert( is_same_v<int, invoke_result_t<copyable_function<int()>>> ); +static_assert( is_same_v<int&, invoke_result_t<copyable_function<int&()>>> ); + +// With const qualifier +static_assert( ! is_invocable_v< copyable_function<void()> const > ); +static_assert( ! is_invocable_v< copyable_function<void()> const &> ); +static_assert( is_invocable_v< copyable_function<void() const> > ); +static_assert( is_invocable_v< copyable_function<void() const> &> ); +static_assert( is_invocable_v< copyable_function<void() const> const > ); +static_assert( is_invocable_v< copyable_function<void() const> const &> ); + +// With no ref-qualifier +static_assert( is_invocable_v< copyable_function<void()> > ); +static_assert( is_invocable_v< copyable_function<void()> &> ); +static_assert( is_invocable_v< copyable_function<void() const> > ); +static_assert( is_invocable_v< copyable_function<void() const> &> ); +static_assert( is_invocable_v< copyable_function<void() const> const > ); +static_assert( is_invocable_v< copyable_function<void() const> const &> ); + +// With & ref-qualifier +static_assert( ! is_invocable_v< copyable_function<void()&> > ); +static_assert( is_invocable_v< copyable_function<void()&> &> ); +static_assert( is_invocable_v< copyable_function<void() const&> > ); +static_assert( is_invocable_v< copyable_function<void() const&> &> ); +static_assert( is_invocable_v< copyable_function<void() const&> const > ); +static_assert( is_invocable_v< copyable_function<void() const&> const &> ); + +// With && ref-qualifier +static_assert( is_invocable_v< copyable_function<void()&&> > ); +static_assert( ! is_invocable_v< copyable_function<void()&&> &> ); +static_assert( is_invocable_v< copyable_function<void() const&&> > ); +static_assert( ! is_invocable_v< copyable_function<void() const&&> &> ); +static_assert( is_invocable_v< copyable_function<void() const&&> const > ); +static_assert( ! is_invocable_v< copyable_function<void() const&&> const &> ); + +// With noexcept-specifier +static_assert( ! is_nothrow_invocable_v< copyable_function<void()> > ); +static_assert( ! is_nothrow_invocable_v< copyable_function<void() noexcept(false)> > ); +static_assert( is_nothrow_invocable_v< copyable_function<void() noexcept> > ); +static_assert( is_nothrow_invocable_v< copyable_function<void()& noexcept>& > ); + +void +test01() +{ + struct F + { + int operator()() { return 0; } + int operator()() const { return 1; } + }; + + copyable_function<int()> f0{F{}}; + VERIFY( f0() == 0 ); + VERIFY( std::move(f0)() == 0 ); + + copyable_function<int() const> f1{F{}}; + VERIFY( f1() == 1 ); + VERIFY( std::as_const(f1)() == 1 ); + VERIFY( std::move(f1)() == 1 ); + VERIFY( std::move(std::as_const(f1))() == 1 ); + + copyable_function<int()&> f2{F{}}; + VERIFY( f2() == 0 ); + // Not rvalue-callable: std::move(f2)() + + copyable_function<int() const&> f3{F{}}; + VERIFY( f3() == 1 ); + VERIFY( std::as_const(f3)() == 1 ); + VERIFY( std::move(f3)() == 1 ); + VERIFY( std::move(std::as_const(f3))() == 1 ); + + copyable_function<int()&&> f4{F{}}; + // Not lvalue-callable: f4() + VERIFY( std::move(f4)() == 0 ); + + copyable_function<int() const&&> f5{F{}}; + // Not lvalue-callable: f5() + VERIFY( std::move(f5)() == 1 ); + VERIFY( std::move(std::as_const(f5))() == 1 ); +} + +void +test02() +{ + struct F + { + int operator()() & { return 0; } + int operator()() && { return 1; } + }; + + copyable_function<int()> f0{F{}}; + VERIFY( f0() == 0 ); + VERIFY( std::move(f0)() == 0 ); + + copyable_function<int()&&> f1{F{}}; + // Not lvalue callable: f1() + VERIFY( std::move(f1)() == 1 ); + + copyable_function<int()&> f2{F{}}; + VERIFY( f2() == 0 ); + // Not rvalue-callable: std::move(f2)() +} + +void +test03() +{ + struct F + { + int operator()() const & { return 0; } + int operator()() && { return 1; } + }; + + copyable_function<int()> f0{F{}}; + VERIFY( f0() == 0 ); + VERIFY( std::move(f0)() == 0 ); + + copyable_function<int()&&> f1{F{}}; + // Not lvalue callable: f1() + VERIFY( std::move(f1)() == 1 ); + + copyable_function<int() const> f2{F{}}; + VERIFY( f2() == 0 ); + VERIFY( std::as_const(f2)() == 0 ); + VERIFY( std::move(f2)() == 0 ); + VERIFY( std::move(std::as_const(f2))() == 0 ); + + copyable_function<int() const &&> f3{F{}}; + // Not lvalue callable: f3() + VERIFY( std::move(f3)() == 0 ); + VERIFY( std::move(std::as_const(f3))() == 0 ); + + copyable_function<int() const &> f4{F{}}; + VERIFY( f4() == 0 ); + VERIFY( std::as_const(f4)() == 0 ); + // Not rvalue-callable: std::move(f4)() +} + +void +test04() +{ + struct F + { + int operator()() & { return 0; } + int operator()() && { return 1; } + int operator()() const & { return 2; } + int operator()() const && { return 3; } + }; + + copyable_function<int()> f0{F{}}; + VERIFY( f0() == 0 ); + VERIFY( std::move(f0)() == 0 ); + + copyable_function<int()&> f1{F{}}; + VERIFY( f1() == 0 ); + // Not rvalue-callable: std::move(f1)() + + copyable_function<int()&&> f2{F{}}; + // Not lvalue callable: f2() + VERIFY( std::move(f2)() == 1 ); + + copyable_function<int() const> f3{F{}}; + VERIFY( f3() == 2 ); + VERIFY( std::as_const(f3)() == 2 ); + VERIFY( std::move(f3)() == 2 ); + VERIFY( std::move(std::as_const(f3))() == 2 ); + + copyable_function<int() const &> f4{F{}}; + VERIFY( f4() == 2 ); + VERIFY( std::as_const(f4)() == 2 ); + // Not rvalue-callable: std::move(f4)() + + copyable_function<int() const &&> f5{F{}}; + // Not lvalue callable: f5() + VERIFY( std::move(f5)() == 3 ); + VERIFY( std::move(std::as_const(f5))() == 3 ); +} + +void +test05() +{ + int (*fp)() = [] { return 0; }; + copyable_function<int()> f0{fp}; + VERIFY( f0() == 0 ); + VERIFY( std::move(f0)() == 0 ); + + const copyable_function<int() const> f1{fp}; + VERIFY( f1() == 0 ); + VERIFY( std::move(f1)() == 0 ); +} + +struct Incomplete; +enum CompleteEnum : int; + +void +test_params() +{ + std::copyable_function<void(Incomplete&)> f1; + std::copyable_function<void(Incomplete&&)> f2; + std::copyable_function<void(CompleteEnum)> f4; +} + +int main() +{ + test01(); + test02(); + test03(); + test04(); + test05(); + test_params(); +} diff --git a/libstdc++-v3/testsuite/20_util/copyable_function/cons.cc b/libstdc++-v3/testsuite/20_util/copyable_function/cons.cc new file mode 100644 index 0000000..8d422dc --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/copyable_function/cons.cc @@ -0,0 +1,126 @@ +// { dg-do compile { target c++26 } } +// { dg-require-effective-target hosted } +// { dg-add-options no_pch } + +#include <functional> + +#ifndef __cpp_lib_copyable_function +# error "Feature-test macro for copyable_function missing in <functional>" +#elif __cpp_lib_copyable_function != 202306L +# error "Feature-test macro for copyable_function has wrong value in <functional>" +#endif + +using std::copyable_function; + +using std::is_constructible_v; +using std::is_copy_constructible_v; +using std::is_nothrow_default_constructible_v; +using std::is_nothrow_move_constructible_v; +using std::is_nothrow_constructible_v; +using std::nullptr_t; +using std::in_place_type_t; + +static_assert( is_nothrow_default_constructible_v<copyable_function<void()>> ); +static_assert( is_nothrow_constructible_v<copyable_function<void()>, nullptr_t> ); +static_assert( is_nothrow_move_constructible_v<copyable_function<void()>> ); +static_assert( is_copy_constructible_v<copyable_function<void()>> ); + +static_assert( is_constructible_v<copyable_function<void()>, void()> ); +static_assert( is_constructible_v<copyable_function<void()>, void(&)()> ); +static_assert( is_constructible_v<copyable_function<void()>, void(*)()> ); +static_assert( is_constructible_v<copyable_function<void()>, int()> ); +static_assert( is_constructible_v<copyable_function<void()>, int(&)()> ); +static_assert( is_constructible_v<copyable_function<void()>, int(*)()> ); +static_assert( ! is_constructible_v<copyable_function<void()>, void(int)> ); +static_assert( is_constructible_v<copyable_function<void(int)>, void(int)> ); + +static_assert( is_constructible_v<copyable_function<void(int)>, + in_place_type_t<void(*)(int)>, void(int)> ); + +static_assert( is_constructible_v<copyable_function<void()>, + void() noexcept> ); +static_assert( is_constructible_v<copyable_function<void() noexcept>, + void() noexcept> ); +static_assert( ! is_constructible_v<copyable_function<void() noexcept>, + void() > ); + +struct Q +{ + void operator()() const &; + void operator()() &&; +}; + +static_assert( is_constructible_v<copyable_function<void()>, Q> ); +static_assert( is_constructible_v<copyable_function<void() const>, Q> ); +static_assert( is_constructible_v<copyable_function<void() &>, Q> ); +static_assert( is_constructible_v<copyable_function<void() const &>, Q> ); +static_assert( is_constructible_v<copyable_function<void() &&>, Q> ); +static_assert( is_constructible_v<copyable_function<void() const &&>, Q> ); + +struct R +{ + void operator()() &; + void operator()() &&; +}; + +static_assert( is_constructible_v<copyable_function<void()>, R> ); +static_assert( is_constructible_v<copyable_function<void()&>, R> ); +static_assert( is_constructible_v<copyable_function<void()&&>, R> ); +static_assert( ! is_constructible_v<copyable_function<void() const>, R> ); +static_assert( ! is_constructible_v<copyable_function<void() const&>, R> ); +static_assert( ! is_constructible_v<copyable_function<void() const&&>, R> ); + +// The following nothrow-constructible guarantees are a GCC extension, +// not required by the standard. + +static_assert( is_nothrow_constructible_v<copyable_function<void()>, void()> ); +static_assert( is_nothrow_constructible_v<copyable_function<void(int)>, + in_place_type_t<void(*)(int)>, + void(int)> ); + +// These types are all small and nothrow move constructible +struct F { void operator()(); }; +struct G { void operator()() const; }; +static_assert( is_nothrow_constructible_v<copyable_function<void()>, F> ); +static_assert( is_nothrow_constructible_v<copyable_function<void()>, G> ); +static_assert( is_nothrow_constructible_v<copyable_function<void() const>, G> ); + +struct H { + H(int); + H(int, int) noexcept; + void operator()() noexcept; +}; +static_assert( is_nothrow_constructible_v<copyable_function<void()>, H> ); +static_assert( is_nothrow_constructible_v<copyable_function<void() noexcept>, + H> ); +static_assert( ! is_nothrow_constructible_v<copyable_function<void() noexcept>, + in_place_type_t<H>, int> ); +static_assert( is_nothrow_constructible_v<copyable_function<void() noexcept>, + in_place_type_t<H>, int, int> ); + +struct I { + I(int, const char*); + I(std::initializer_list<char>); + int operator()() const noexcept; +}; + +static_assert( is_constructible_v<copyable_function<void()>, + std::in_place_type_t<I>, + int, const char*> ); +static_assert( is_constructible_v<copyable_function<void()>, + std::in_place_type_t<I>, + std::initializer_list<char>> ); + +void +test_instantiation() +{ + // Instantiate the constructor bodies + copyable_function<void()> f0; + copyable_function<void()> f1(nullptr); + copyable_function<void()> f2( I(1, "two") ); + copyable_function<void()> f3(std::in_place_type<I>, 3, "four"); + copyable_function<void()> f4(std::in_place_type<I>, // PR libstdc++/102825 + { 'P', 'R', '1', '0', '2', '8', '2', '5'}); + auto f5 = std::move(f4); + f4 = std::move(f5); +} diff --git a/libstdc++-v3/testsuite/20_util/copyable_function/conv.cc b/libstdc++-v3/testsuite/20_util/copyable_function/conv.cc new file mode 100644 index 0000000..11c839b --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/copyable_function/conv.cc @@ -0,0 +1,286 @@ +// { dg-do run { target c++26 } } +// { dg-require-effective-target hosted } + +#include <functional> +#include <string_view> +#include <testsuite_hooks.h> + +using std::copyable_function; + +static_assert( !std::is_constructible_v<std::copyable_function<void()>, + std::copyable_function<void()&>> ); +static_assert( !std::is_constructible_v<std::copyable_function<void()>, + std::copyable_function<void()&&>> ); +static_assert( !std::is_constructible_v<std::copyable_function<void()&>, + std::copyable_function<void()&&>> ); +static_assert( !std::is_constructible_v<std::copyable_function<void() const>, + std::copyable_function<void()>> ); + +using FuncType = int(int); + +// Top level const qualifiers are ignored and decay is performed in parameters +// of function_types. +static_assert( std::is_same_v<std::copyable_function<void(int const)>, + std::copyable_function<void(int)>> ); +static_assert( std::is_same_v<std::copyable_function<void(int[2])>, + std::copyable_function<void(int*)>>); +static_assert( std::is_same_v<std::copyable_function<void(int[])>, + std::copyable_function<void(int*)>>); +static_assert( std::is_same_v<std::copyable_function<void(int const[5])>, + std::copyable_function<void(int const*)>>); +static_assert( std::is_same_v<std::copyable_function<void(FuncType)>, + std::copyable_function<void(FuncType*)>>); + +// Non-trivial args, guarantess that type is not passed by copy +struct CountedArg +{ + CountedArg() = default; + CountedArg(const CountedArg& f) noexcept : counter(f.counter) { ++counter; } + CountedArg& operator=(CountedArg&&) = delete; + + int counter = 0; +}; +CountedArg const c; + +// When copyable_function or move_only_function is constructed from other copyable_function, +// the compiler can avoid double indirection per C++26 [func.wrap.general] p2. + +void +test01() +{ + auto f = [](CountedArg const& arg) noexcept { return arg.counter; }; + std::copyable_function<int(CountedArg) const noexcept> c1(f); + using CF = std::copyable_function<int(CountedArg) const noexcept>; + VERIFY( c1(c) == 1 ); + + std::copyable_function<int(CountedArg) const> c2a(c1); + VERIFY( c2a(c) == 1 ); + + std::copyable_function<int(CountedArg) const> c2b(static_cast<CF>(c1)); + VERIFY( c2b(c) == 1 ); + + std::move_only_function<int(CountedArg) const> m2a(c1); + VERIFY( m2a(c) == 1 ); + + std::move_only_function<int(CountedArg) const> m2b(static_cast<CF>(c1)); + VERIFY( m2b(c) == 1 ); + + std::copyable_function<int(CountedArg)> c3a(c1); + VERIFY( c3a(c) == 1 ); + + std::copyable_function<int(CountedArg)> c3b(static_cast<CF>(c1)); + VERIFY( c3b(c) == 1 ); + + std::move_only_function<int(CountedArg)> m3a(c1); + VERIFY( m3a(c) == 1 ); + + std::move_only_function<int(CountedArg)> m3b(static_cast<CF>(c1)); + VERIFY( m3b(c) == 1 ); + + // Invokers internally uses Counted&& for non-trivial types, + // sinature remain compatible. + std::copyable_function<int(CountedArg&&)> c4a(c1); + VERIFY( c4a({}) == 0 ); + + std::copyable_function<int(CountedArg&&)> c4b(static_cast<CF>(c1)); + VERIFY( c4b({}) == 0 ); + + std::move_only_function<int(CountedArg&&)> m4a(c1); + VERIFY( m4a({}) == 0 ); + + std::move_only_function<int(CountedArg&&)> m4b(static_cast<CF>(c1)); + VERIFY( m4b({}) == 0 ); + + std::copyable_function<int(CountedArg&&)&> c5a(c1); + VERIFY( c5a({}) == 0 ); + + std::copyable_function<int(CountedArg&&)&&> c5b(static_cast<CF>(c1)); + VERIFY( std::move(c5b)({}) == 0 ); + + std::move_only_function<int(CountedArg&&)&> m5a(c1); + VERIFY( m5a({}) == 0 ); + + std::move_only_function<int(CountedArg&&)&&> m5b(static_cast<CF>(c1)); + VERIFY( std::move(m5b)({}) == 0 ); + + // Incompatible signatures + std::copyable_function<long(CountedArg) const noexcept> c6a(c1); + VERIFY( c6a(c) == 2 ); + + std::copyable_function<long(CountedArg) const noexcept> c6b(static_cast<CF>(c1)); + VERIFY( c6b(c) == 2 ); + + std::move_only_function<long(CountedArg) const noexcept> m6a(c1); + VERIFY( m6a(c) == 2 ); + + std::move_only_function<long(CountedArg) const noexcept> m6b(static_cast<CF>(c1)); + VERIFY( m6b(c) == 2 ); +} + +void +test02() +{ + auto f = [](CountedArg const& arg) noexcept { return arg.counter; }; + std::copyable_function<int(CountedArg) const noexcept> c1(f); + using CF = std::copyable_function<int(CountedArg) const noexcept>; + VERIFY( c1(c) == 1 ); + + std::copyable_function<int(CountedArg) const> c2; + c2 = c1; + VERIFY( c2(c) == 1 ); + c2 = static_cast<CF>(c1); + VERIFY( c2(c) == 1 ); + + std::move_only_function<int(CountedArg) const> m2; + m2 = c1; + VERIFY( m2(c) == 1 ); + m2 = static_cast<CF>(c1); + VERIFY( m2(c) == 1 ); + + // Incompatible signatures + std::copyable_function<long(CountedArg) const noexcept> c3; + c3 = c1; + VERIFY( c3(c) == 2 ); + c3 = static_cast<CF>(c1); + VERIFY( c3(c) == 2 ); + + std::move_only_function<long(CountedArg) const noexcept> m3; + m3 = c1; + VERIFY( m3(c) == 2 ); + m3 = static_cast<CF>(c1); + VERIFY( m3(c) == 2 ); +} + +void +test03() +{ + std::copyable_function<int(long) const noexcept> c1; + VERIFY( c1 == nullptr ); + + std::copyable_function<int(long) const> c2(c1); + VERIFY( c2 == nullptr ); + c2 = c1; + VERIFY( c2 == nullptr ); + c2 = std::move(c1); + VERIFY( c2 == nullptr ); + + std::copyable_function<bool(int) const> c3(std::move(c1)); + VERIFY( c3 == nullptr ); + c3 = c1; + VERIFY( c3 == nullptr ); + c3 = std::move(c1); + VERIFY( c3 == nullptr ); + + // LWG4255 move_only_function constructor should recognize empty + // copyable_functions + std::move_only_function<int(long) const noexcept> m1(c1); + VERIFY( m1 == nullptr ); + m1 = c1; + VERIFY( m1 == nullptr ); + m1 = std::move(c1); + VERIFY( m1 == nullptr ); + + std::move_only_function<int(long) const> m2(c1); + VERIFY( m2 == nullptr ); + m2 = c1; + VERIFY( m2 == nullptr ); + m2 = std::move(c1); + VERIFY( m2 == nullptr ); + + std::move_only_function<bool(int) const> m3(std::move(c1)); + VERIFY( m3 == nullptr ); + m3 = c1; + VERIFY( m3 == nullptr ); + m3 = std::move(c1); + VERIFY( m3 == nullptr ); +} + +void +test04() +{ + struct F + { + int operator()(CountedArg const& arg) noexcept + { return arg.counter; } + + int operator()(CountedArg const& arg) const noexcept + { return arg.counter + 1000; } + }; + + F f; + std::copyable_function<int(CountedArg) const> c1(f); + VERIFY( c1(c) == 1001 ); + + // Call const overload as std::copyable_function<int(CountedArg) const> + // inside td::copyable_function<int(CountedArg)> would do. + std::copyable_function<int(CountedArg)> c2(c1); + VERIFY( c2(c) == 1001 ); + std::move_only_function<int(CountedArg)> m2(c1); + VERIFY( m2(c) == 1001 ); + + std::copyable_function<int(CountedArg)> m3(f); + VERIFY( m3(c) == 1 ); +} + +void +test05() +{ + auto f = [](CountedArg const& arg) noexcept { return arg.counter; }; + std::copyable_function<int(CountedArg)> w1(f); + // copyable_function stores copyable_function due incompatibile signatures + std::copyable_function<int(CountedArg const&)> w2(std::move(w1)); + // copy is made when passing to int(CountedArg) + VERIFY( w2(c) == 1 ); + // wrapped 3 times + w1 = std::move(w2); + VERIFY( w1(c) == 2 ); + // wrapped 4 times + w2 = std::move(w1); + VERIFY( w2(c) == 2 ); + // wrapped 5 times + w1 = std::move(w2); + VERIFY( w1(c) == 3 ); +} + +void +test06() +{ + // No special interoperability with std::function + auto f = [](CountedArg const& arg) noexcept { return arg.counter; }; + std::function<int(CountedArg)> f1(f); + std::copyable_function<int(CountedArg) const> c1(std::move(f1)); + VERIFY( c1(c) == 2 ); + + std::copyable_function<int(CountedArg) const> c2(f); + std::function<int(CountedArg)> f2(c2); + VERIFY( f2(c) == 2 ); +} + +void +test07() +{ + // Scalar types and small trivially move constructible types are passed + // by value to invoker. So int&& signature is not compatible for such types. + auto fi = [](CountedArg const& arg, int) noexcept { return arg.counter; }; + std::copyable_function<int(CountedArg, int) const noexcept> ci1(fi); + VERIFY( ci1(c, 0) == 1 ); + std::copyable_function<int(CountedArg, int&&) const noexcept> ci2(ci1); + VERIFY( ci2(c, 0) == 2 ); + + auto fs = [](CountedArg const& arg, std::string_view) noexcept { return arg.counter; }; + std::copyable_function<int(CountedArg, std::string_view) const noexcept> cs1(fs); + VERIFY( cs1(c, "") == 1 ); + std::copyable_function<int(CountedArg, std::string_view&&) const noexcept> cs2(cs1); + VERIFY( cs2(c, "") == 2 ); +} + +int main() +{ + test01(); + test02(); + test03(); + test04(); + test05(); + test06(); + test07(); +} diff --git a/libstdc++-v3/testsuite/20_util/copyable_function/copy.cc b/libstdc++-v3/testsuite/20_util/copyable_function/copy.cc new file mode 100644 index 0000000..6445a27 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/copyable_function/copy.cc @@ -0,0 +1,154 @@ +// { dg-do run { target c++26 } } +// { dg-require-effective-target hosted } + +#include <functional> +#include <testsuite_hooks.h> + +using std::copyable_function; + +void +test01() +{ + // Small type with non-throwing move constructor. Not allocated on the heap. + struct F + { + F() = default; + F(const F& f) : counters(f.counters) { ++counters.copy; } + F(F&& f) noexcept : counters(f.counters) { ++counters.move; } + + F& operator=(F&&) = delete; + + struct Counters + { + int copy = 0; + int move = 0; + } counters; + + const Counters& operator()() const { return counters; } + }; + + F f; + std::copyable_function<const F::Counters&() const> m1(f); + VERIFY( m1().copy == 1 ); + VERIFY( m1().move == 0 ); + + // This will copy construct a new target object + auto m2 = m1; + VERIFY( m1 != nullptr && m2 != nullptr ); + VERIFY( m2().copy == 2 ); + VERIFY( m2().move == 0 ); + + m1 = m2; + VERIFY( m1 != nullptr && m2 != nullptr ); + VERIFY( m1().copy == 3 ); + VERIFY( m1().move == 1 ); // Copies object first and then swaps + + m1 = m1; + VERIFY( m1 != nullptr && m2 != nullptr ); + VERIFY( m1().copy == 4 ); + VERIFY( m1().move == 2 ); // Copies object first and then swaps + + m2 = f; + VERIFY( m2().copy == 1 ); + VERIFY( m2().move == 1 ); // Copy construct target object, then swap into m2. +} + +void +test02() +{ + // Move constructor is potentially throwing. Allocated on the heap. + struct F + { + F() = default; + F(const F& f) noexcept : counters(f.counters) { ++counters.copy; } + F(F&& f) noexcept(false) : counters(f.counters) { ++counters.move; } + + F& operator=(F&&) = delete; + + struct Counters + { + int copy = 0; + int move = 0; + } counters; + + Counters operator()() const noexcept { return counters; } + }; + + F f; + std::copyable_function<F::Counters() const> m1(f); + VERIFY( m1().copy == 1 ); + VERIFY( m1().move == 0 ); + + // The target object is on the heap, but we need to allocate new one + auto m2 = m1; + VERIFY( m1 != nullptr && m2 != nullptr ); + VERIFY( m2().copy == 2 ); + VERIFY( m2().move == 0 ); + + m1 = m2; + VERIFY( m1 != nullptr && m2 != nullptr ); + VERIFY( m1().copy == 3 ); + VERIFY( m1().move == 0 ); + + m1 = m1; + VERIFY( m1 != nullptr && m2 != nullptr ); + VERIFY( m1().copy == 4 ); + VERIFY( m1().move == 0 ); + + m2 = f; + VERIFY( m2().copy == 1 ); + VERIFY( m2().move == 0 ); +} + +void +test03() +{ + // Small type with non-throwing, but not non-trivial move constructor. + struct F + { + F(int i) noexcept : id(i) {} + F(const F& f) : id(f.id) + { if (id == 3) throw id; } + F(F&& f) noexcept : id(f.id) { } + + int operator()() const + { return id; } + + int id; + }; + + std::copyable_function<int() const> m1(std::in_place_type<F>, 1); + const std::copyable_function<int() const> m2(std::in_place_type<F>, 2); + const std::copyable_function<int() const> m3(std::in_place_type<F>, 3); + + try + { + auto mc = m3; + VERIFY( false ); + } + catch(int i) + { + VERIFY( i == 3 ); + } + + m1 = m2; + VERIFY( m1() == 2 ); + + try + { + m1 = m3; + VERIFY( false ); + } + catch (int i) + { + VERIFY( i == 3 ); + } + VERIFY( m1() == 2 ); +} + +int main() +{ + test01(); + test02(); + test03(); +} diff --git a/libstdc++-v3/testsuite/20_util/copyable_function/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/copyable_function/incomplete_neg.cc new file mode 100644 index 0000000..21ddde0 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/copyable_function/incomplete_neg.cc @@ -0,0 +1,18 @@ +// { dg-do compile { target c++26 } } + +#include <functional> + +struct IncompleteClass; + +using T1 = std::copyable_function<int(IncompleteClass)>::result_type; // { dg-error "here" } +using T2 = std::copyable_function<int(int, IncompleteClass)>::result_type; // { dg-error "here" } + +enum Enum { + x = [] { + // Enum enumeration is incomplete here + using T3 = std::copyable_function<int(Enum)>::result_type; // { dg-error "here" } + return T3(1); + }() +}; + +// { dg-error "static assertion failed" "" { target *-*-* } 0 } diff --git a/libstdc++-v3/testsuite/20_util/copyable_function/move.cc b/libstdc++-v3/testsuite/20_util/copyable_function/move.cc new file mode 100644 index 0000000..ec9d0d1 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/copyable_function/move.cc @@ -0,0 +1,120 @@ +// { dg-do run { target c++26 } } +// { dg-require-effective-target hosted } + +#include <functional> +#include <testsuite_hooks.h> + +using std::copyable_function; + +void +test01() +{ + // Small type with non-throwing move constructor. Not allocated on the heap. + struct F + { + F() = default; + F(const F& f) : counters(f.counters) { ++counters.copy; } + F(F&& f) noexcept : counters(f.counters) { ++counters.move; } + + F& operator=(F&&) = delete; + + struct Counters + { + int copy = 0; + int move = 0; + } counters; + + const Counters& operator()() const { return counters; } + }; + + F f; + std::copyable_function<const F::Counters&() const> m1(f); + VERIFY( m1().copy == 1 ); + VERIFY( m1().move == 0 ); + + // Standard specifies move assigment as copy and swap + m1 = std::move(m1); + VERIFY( m1 != nullptr ); + VERIFY( m1().copy == 1 ); + VERIFY( m1().move == 0 ); + + // This will move construct a new target object and destroy the old one: + auto m2 = std::move(m1); + VERIFY( m1 == nullptr && m2 != nullptr ); + VERIFY( m2().copy == 1 ); + VERIFY( m2().move == 1 ); + + m1 = std::move(m2); + VERIFY( m1 != nullptr && m2 == nullptr ); + VERIFY( m1().copy == 1 ); + VERIFY( m1().move == 2 ); + + m2 = std::move(f); + VERIFY( m2().copy == 0 ); + VERIFY( m2().move == 2 ); // Move construct target object, then swap into m2. + const int moves = m1().move + m2().move; + // This will do three moves: + swap(m1, m2); + VERIFY( m1().copy == 0 ); + VERIFY( m2().copy == 1 ); + VERIFY( (m1().move + m2().move) == (moves + 3) ); +} + +void +test02() +{ + // Move constructor is potentially throwing. Allocated on the heap. + struct F + { + F() = default; + F(const F& f) noexcept : counters(f.counters) { ++counters.copy; } + F(F&& f) noexcept(false) : counters(f.counters) { ++counters.move; } + + F& operator=(F&&) = delete; + + struct Counters + { + int copy = 0; + int move = 0; + } counters; + + Counters operator()() const noexcept { return counters; } + }; + + F f; + std::copyable_function<F::Counters() const> m1(f); + VERIFY( m1().copy == 1 ); + VERIFY( m1().move == 0 ); + + m1 = std::move(m1); + VERIFY( m1 != nullptr ); + VERIFY( m1().copy == 1 ); + VERIFY( m1().move == 0 ); + + // The target object is on the heap so this just moves a pointer: + auto m2 = std::move(m1); + VERIFY( m1 == nullptr && m2 != nullptr ); + VERIFY( m2().copy == 1 ); + VERIFY( m2().move == 0 ); + + m1 = std::move(m2); + VERIFY( m1 != nullptr && m2 == nullptr ); + VERIFY( m1().copy == 1 ); + VERIFY( m1().move == 0 ); + + m2 = std::move(f); + VERIFY( m2().copy == 0 ); + VERIFY( m2().move == 1 ); + const int moves = m1().move + m2().move; + // This just swaps the pointers, so no moves: + swap(m1, m2); + VERIFY( m1().copy == 0 ); + VERIFY( m2().copy == 1 ); + VERIFY( (m1().move + m2().move) == moves ); +} + +int main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/20_util/expected/119714.cc b/libstdc++-v3/testsuite/20_util/expected/119714.cc new file mode 100644 index 0000000..a8dc6e8 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/expected/119714.cc @@ -0,0 +1,9 @@ +// { dg-do compile { target c++23 } } + +// PR libstdc++/119714 - constraint recursion with std::expected::operator== + +#include <expected> +#include <vector> + +using I = std::vector<std::expected<int,int>>::iterator; +static_assert(std::totally_ordered<I>); diff --git a/libstdc++-v3/testsuite/20_util/expected/equality_constrained.cc b/libstdc++-v3/testsuite/20_util/expected/equality_constrained.cc index 7f6cefa..a079d98 100644 --- a/libstdc++-v3/testsuite/20_util/expected/equality_constrained.cc +++ b/libstdc++-v3/testsuite/20_util/expected/equality_constrained.cc @@ -4,7 +4,7 @@ #ifndef __cpp_lib_constrained_equality # error "Feature-test macro for constrained_equality missing in <expected>" -#elif __cpp_lib_constrained_equality < 202411L // TODO: use final value +#elif __cpp_lib_constrained_equality < 202411L # error "Feature-test macro for constrained_equality has wrong value" #endif diff --git a/libstdc++-v3/testsuite/20_util/function/cons/70692.cc b/libstdc++-v3/testsuite/20_util/function/cons/70692.cc index b15208a..f9e8fe3 100644 --- a/libstdc++-v3/testsuite/20_util/function/cons/70692.cc +++ b/libstdc++-v3/testsuite/20_util/function/cons/70692.cc @@ -11,4 +11,4 @@ int main() std::function<const int&()> ff(f); // { dg-error "no matching function" } std::function<long&&()> f2(f); // { dg-error "no matching function" } } -// { dg-error "std::(__8::)?enable_if" "" { target *-*-* } 0 } +// { dg-error "std::enable_if" "" { target *-*-* } 0 } diff --git a/libstdc++-v3/testsuite/20_util/function_ref/assign.cc b/libstdc++-v3/testsuite/20_util/function_ref/assign.cc new file mode 100644 index 0000000..9b02dc4 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/function_ref/assign.cc @@ -0,0 +1,108 @@ +// { dg-do compile { target c++26 } } + +#include <functional> + +#ifndef __cpp_lib_function_ref +# error "Feature-test macro for function_ref missing in <functional>" +#elif __cpp_lib_function_ref != 202306L +# error "Feature-test macro for function_ref has wrong value in <functional>" +#endif + +using std::nontype; +using std::nontype_t; +using std::function_ref; + +using std::is_nothrow_move_assignable_v; +using std::is_nothrow_copy_assignable_v; +using std::is_nothrow_assignable_v; +using std::is_assignable_v; +using std::is_nothrow_swappable_v; +using std::is_trivially_copyable_v; + +static_assert( is_nothrow_move_assignable_v<function_ref<void()>> ); +static_assert( is_nothrow_copy_assignable_v<function_ref<void()>> ); +static_assert( is_nothrow_swappable_v<function_ref<void()>> ); + +static_assert( ! is_assignable_v<function_ref<void()>, std::nullptr_t> ); + +static_assert( is_nothrow_assignable_v<function_ref<void()>, void()> ); +static_assert( is_nothrow_assignable_v<function_ref<void()>, void(&)()> ); +static_assert( is_nothrow_assignable_v<function_ref<void()>, void(*)()> ); +static_assert( is_nothrow_assignable_v<function_ref<void()>, int()> ); +static_assert( is_nothrow_assignable_v<function_ref<void()>, int(&)()> ); +static_assert( is_nothrow_assignable_v<function_ref<void()>, int(*)()> ); +static_assert( ! is_nothrow_assignable_v<function_ref<void()>, void(int)> ); +static_assert( is_nothrow_assignable_v<function_ref<void(int)>, void(int)> ); + +static_assert( is_nothrow_assignable_v<function_ref<void()>, + void() noexcept> ); +static_assert( is_nothrow_assignable_v<function_ref<void() noexcept>, + void() noexcept> ); +static_assert( ! is_assignable_v<function_ref<void() noexcept>, void() > ); + +struct S +{ + int x; + int f(); +}; +int funS(S); + +static_assert( is_nothrow_assignable_v<function_ref<int(S)>, + decltype(funS)> ); +static_assert( is_nothrow_assignable_v<function_ref<int(S)>, + decltype(&funS)> ); +static_assert( ! is_assignable_v<function_ref<int(S)>, decltype(&S::x)> ); +static_assert( ! is_assignable_v<function_ref<int(S)>, decltype(&S::f)> ); + +static_assert( is_nothrow_assignable_v<function_ref<int(S)>, + nontype_t<funS>> ); +static_assert( is_nothrow_assignable_v<function_ref<int(S)>, + nontype_t<&funS>> ); +static_assert( is_nothrow_assignable_v<function_ref<int(S)>, + nontype_t<&S::x>> ); +static_assert( is_nothrow_assignable_v<function_ref<int(S)>, + nontype_t<&S::f>> ); +struct Q +{ + void operator()() const; +}; + +static_assert( ! is_assignable_v<function_ref<void()>, Q> ); +static_assert( ! is_assignable_v<function_ref<void()>, Q&> ); +static_assert( ! is_assignable_v<function_ref<void()>, const Q&> ); +static_assert( ! is_assignable_v<function_ref<void() const>, Q> ); +static_assert( ! is_assignable_v<function_ref<void() const>, Q&> ); +static_assert( ! is_assignable_v<function_ref<void() const>, const Q&> ); + +static_assert( is_nothrow_assignable_v<function_ref<void()>, + nontype_t<Q{}>> ); +static_assert( is_nothrow_assignable_v<function_ref<void() const>, + nontype_t<Q{}>> ); + +constexpr bool +test_constexpr() +{ + function_ref<void(S)> fp(nontype<funS>); + fp = nontype<funS>; + fp = nontype<&funS>; + fp = nontype<&S::x>; + fp = nontype<&S::f>; + + constexpr Q cq; + function_ref<void() const> fq(cq); + fq = nontype<cq>; + return true; +} +static_assert( test_constexpr() ); + +void func(); + +void +test_instantiation() +{ + function_ref<void(S)> fp(funS); + fp = funS; + fp = &funS; + + test_constexpr(); +} diff --git a/libstdc++-v3/testsuite/20_util/function_ref/call.cc b/libstdc++-v3/testsuite/20_util/function_ref/call.cc new file mode 100644 index 0000000..23253c3 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/function_ref/call.cc @@ -0,0 +1,186 @@ +// { dg-do run { target c++26 } } + +#include <functional> +#include <utility> +#include <testsuite_hooks.h> + +using std::nontype; +using std::function_ref; + +using std::is_same_v; +using std::is_invocable_v; +using std::is_nothrow_invocable_v; +using std::invoke_result_t; + +// Check return types +static_assert( is_same_v<void, invoke_result_t<function_ref<void()>>> ); +static_assert( is_same_v<int, invoke_result_t<function_ref<int()>>> ); +static_assert( is_same_v<int&, invoke_result_t<function_ref<int&()>>> ); + +// Const qualier applies to target object +static_assert( is_invocable_v< function_ref<void()> const > ); +static_assert( is_invocable_v< function_ref<void()> const &> ); +static_assert( is_invocable_v< function_ref<void() const> > ); +static_assert( is_invocable_v< function_ref<void() const> &> ); +static_assert( is_invocable_v< function_ref<void() const> const > ); +static_assert( is_invocable_v< function_ref<void() const> const &> ); + +// With noexcept-specifier +static_assert( ! is_nothrow_invocable_v< function_ref<void()> > ); +static_assert( ! is_nothrow_invocable_v< function_ref<void() noexcept(false)> > ); +static_assert( is_nothrow_invocable_v< function_ref<void() noexcept> > ); + +void +test01() +{ + struct F + { + int operator()() { return 0; } + int operator()() const { return 1; } + }; + + function_ref<int()> f0{F{}}; + VERIFY( f0() == 0 ); + VERIFY( std::move(f0)() == 0 ); + + function_ref<int()> f1{nontype<F{}>}; + VERIFY( f1() == 1 ); + VERIFY( std::move(f1)() == 1 ); + + function_ref<int() const> f2{F{}}; + VERIFY( f2() == 1 ); + VERIFY( std::as_const(f2)() == 1 ); + VERIFY( std::move(f2)() == 1 ); + VERIFY( std::move(std::as_const(f2))() == 1 ); + + function_ref<int() const> f3{nontype<F{}>}; + VERIFY( f3() == 1 ); + VERIFY( std::as_const(f3)() == 1 ); + VERIFY( std::move(f3)() == 1 ); + VERIFY( std::move(std::as_const(f3))() == 1 ); +} + +void +test02() +{ + struct F + { + struct Arg {}; + int operator()(Arg& arg) const { return 0; } + int operator()(const Arg& arg) const { return 1; } + }; + F::Arg arg; + + function_ref<int()> f0{std::nontype<F{}>, arg}; + VERIFY( f0() == 0 ); + VERIFY( std::move(f0)() == 0 ); + + function_ref<int() const> f1{std::nontype<F{}>, arg}; + VERIFY( f1() == 1 ); + VERIFY( std::as_const(f1)() == 1 ); +} + +void +test03() +{ + struct F + { + struct Arg {}; + int operator()(Arg* arg) const { return 0; } + int operator()(const Arg* arg) const { return 1; } + }; + F::Arg arg; + + function_ref<int()> f0{std::nontype<F{}>, &arg}; + VERIFY( f0() == 0 ); + VERIFY( std::move(f0)() == 0 ); + + function_ref<int() const> f1{std::nontype<F{}>, &arg}; + VERIFY( f1() == 1 ); + VERIFY( std::as_const(f1)() == 1 ); +} + +void +test04() +{ + constexpr int (*fp)() = [] { return 0; }; + function_ref<int()> f0{fp}; + VERIFY( f0() == 0 ); + VERIFY( std::move(f0)() == 0 ); + + function_ref<int()> f1{nontype<fp>}; + VERIFY( f1() == 0 ); + VERIFY( std::move(f1)() == 0 ); + + const function_ref<int() const> f2{fp}; + VERIFY( f2() == 0 ); + VERIFY( std::move(f2)() == 0 ); + + const function_ref<int() const> f3{nontype<fp>}; + VERIFY( f2() == 0 ); + VERIFY( std::move(f2)() == 0 ); +} + +using ftype = int(int); +int twice(int x) { return x * 2; } +int cube(int x) { return x * x * x; } +int callback_ptr(ftype* f, int x) { return f(x); } +int callback_ref(ftype& f, int x) { return f(x); } + +void +test05() +{ + + function_ref<int(int)> r1(nontype<&callback_ptr>, &twice); + VERIFY( r1(2) == 4 ); + function_ref<int(int)> r2(nontype<&callback_ptr>, cube); + VERIFY( r2(2) == 8 ); + + function_ref<int(int)> r3(nontype<&callback_ref>, twice); + VERIFY( r3(3) == 6 ); + function_ref<int(int)> r4(nontype<&callback_ref>, cube); + VERIFY( r4(3) == 27 ); + + // Checks if distinction between reference and pointer + // is preserved. + struct F + { + static + int operator()(ftype* f, int x) + { return f(x) + 1000; } + + static + int operator()(ftype& f, int x) + { return f(x) + 2000; } + }; + function_ref<int(int)> r5(nontype<F{}>, &twice); + VERIFY( r5(2) == 1004 ); + function_ref<int(int)> r6(nontype<F{}>, twice); + VERIFY( r6(2) == 2008 ); + function_ref<int(int)> r7(nontype<F{}>, &cube); + VERIFY( r7(3) == 1006 ); + function_ref<int(int)> r8(nontype<F{}>, cube); + VERIFY( r8(3) == 2027 ); +} + +struct Incomplete; +enum CompleteEnum : int; + +void +test_params() +{ + auto f = [](auto&&) {}; + std::function_ref<void(Incomplete&)> f1(f); + // See PR libstdc++/120259, this should be supported. + // std::function_ref<void(Incomplete&&)> f2(f); + std::function_ref<void(CompleteEnum)> f3(f); +} + +int main() +{ + test01(); + test02(); + test03(); + test04(); + test_params(); +} diff --git a/libstdc++-v3/testsuite/20_util/function_ref/cons.cc b/libstdc++-v3/testsuite/20_util/function_ref/cons.cc new file mode 100644 index 0000000..a91f5ba --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/function_ref/cons.cc @@ -0,0 +1,218 @@ +// { dg-do compile { target c++26 } } +// { dg-add-options no_pch } + +#include <functional> + +#ifndef __cpp_lib_function_ref +# error "Feature-test macro for function_ref missing in <functional>" +#elif __cpp_lib_function_ref != 202306L +# error "Feature-test macro for function_ref has wrong value in <functional>" +#endif + +using std::nontype; +using std::nontype_t; +using std::function_ref; + +using std::is_default_constructible_v; +using std::is_nothrow_copy_constructible_v; +using std::is_nothrow_move_constructible_v; +using std::is_nothrow_constructible_v; +using std::is_constructible_v; +using std::is_trivially_copyable_v; + +static_assert( ! is_default_constructible_v<function_ref<void()>> ); +static_assert( is_nothrow_move_constructible_v<function_ref<void()>> ); +static_assert( is_nothrow_copy_constructible_v<function_ref<void()>> ); +static_assert( is_trivially_copyable_v<function_ref<void()>> ); + +static_assert( ! is_constructible_v<function_ref<void()>, std::nullptr_t> ); + +static_assert( is_nothrow_constructible_v<function_ref<void()>, void()> ); +static_assert( is_nothrow_constructible_v<function_ref<void()>, void(&)()> ); +static_assert( is_nothrow_constructible_v<function_ref<void()>, void(*)()> ); +static_assert( is_nothrow_constructible_v<function_ref<void()>, int()> ); +static_assert( is_nothrow_constructible_v<function_ref<void()>, int(&)()> ); +static_assert( is_nothrow_constructible_v<function_ref<void()>, int(*)()> ); +static_assert( ! is_constructible_v<function_ref<void()>, void(int)> ); +static_assert( is_nothrow_constructible_v<function_ref<void(int)>, void(int)> ); + +static_assert( is_nothrow_constructible_v<function_ref<void()>, + void() noexcept> ); +static_assert( is_nothrow_constructible_v<function_ref<void() noexcept>, + void() noexcept> ); +static_assert( ! is_constructible_v<function_ref<void() noexcept>, + void() > ); + +struct S +{ + int x; + int f(); +}; +int funS(S); + +static_assert( is_nothrow_constructible_v<function_ref<int(S)>, + decltype(funS)> ); +static_assert( is_nothrow_constructible_v<function_ref<int(S)>, + decltype(&funS)> ); +static_assert( ! is_constructible_v<function_ref<int(S)>, + decltype(&S::x)> ); +static_assert( ! is_constructible_v<function_ref<int(S)>, + decltype(&S::f)> ); + +static_assert( is_nothrow_constructible_v<function_ref<int(S)>, + nontype_t<funS>> ); +static_assert( is_nothrow_constructible_v<function_ref<int(S)>, + nontype_t<&funS>> ); +static_assert( is_nothrow_constructible_v<function_ref<int(S)>, + nontype_t<&S::x>> ); +static_assert( is_nothrow_constructible_v<function_ref<int(S)>, + nontype_t<&S::f>> ); + +static_assert( is_nothrow_constructible_v<function_ref<int()>, + nontype_t<funS>, S&> ); +static_assert( is_nothrow_constructible_v<function_ref<int()>, + nontype_t<&funS>, S&> ); +static_assert( is_nothrow_constructible_v<function_ref<int()>, + nontype_t<&S::x>, S&> ); +static_assert( is_nothrow_constructible_v<function_ref<int()>, + nontype_t<&S::f>, S&> ); + +static_assert( ! is_constructible_v<function_ref<int()>, + nontype_t<funS>, S*> ); +static_assert( ! is_constructible_v<function_ref<int()>, + nontype_t<&funS>, S*> ); +static_assert( is_nothrow_constructible_v<function_ref<int()>, + nontype_t<&S::x>, S*> ); +static_assert( is_nothrow_constructible_v<function_ref<int()>, + nontype_t<&S::f>, S*> ); + +struct M +{ + void operator()(); +}; + + +static_assert( is_nothrow_constructible_v<function_ref<void()>, M> ); +static_assert( is_nothrow_constructible_v<function_ref<void()>, M&> ); +static_assert( ! is_constructible_v<function_ref<void()>, const M&> ); +static_assert( ! is_constructible_v<function_ref<void() const>, M> ); +static_assert( ! is_constructible_v<function_ref<void() const>, const M&> ); +static_assert( ! is_constructible_v<function_ref<void()>, + nontype_t<M{}>> ); +static_assert( ! is_constructible_v<function_ref<void() const>, + nontype_t<M{}>> ); +struct Q +{ + void operator()(int) const; + void operator()(int*) const; +}; + +static_assert( is_nothrow_constructible_v<function_ref<void(int)>, Q> ); +static_assert( is_nothrow_constructible_v<function_ref<void(int)>, Q&> ); +static_assert( is_nothrow_constructible_v<function_ref<void(int)>, const Q&> ); +static_assert( is_nothrow_constructible_v<function_ref<void(int) const>, Q> ); +static_assert( is_nothrow_constructible_v<function_ref<void(int) const>, Q&> ); +static_assert( is_nothrow_constructible_v<function_ref<void(int) const>, const Q&> ); + +static_assert( is_nothrow_constructible_v<function_ref<void(int)>, + nontype_t<Q{}>> ); +static_assert( is_nothrow_constructible_v<function_ref<void(int) const>, + nontype_t<Q{}>> ); +static_assert( is_nothrow_constructible_v<function_ref<void()>, + nontype_t<Q{}>, int&> ); +static_assert( is_nothrow_constructible_v<function_ref<void() const>, + nontype_t<Q{}>, int&> ); +static_assert( ! is_constructible_v<function_ref<void()>, + nontype_t<Q{}>, int> ); +static_assert( ! is_constructible_v<function_ref<void() const>, + nontype_t<Q{}>, int> ); + +static_assert( is_nothrow_constructible_v<function_ref<void()>, + nontype_t<Q{}>, int*> ); +static_assert( ! is_constructible_v<function_ref<void() const>, + nontype_t<Q{}>, int*> ); + +struct L +{ + void operator()() &; +}; + +static_assert( is_nothrow_constructible_v<function_ref<void()>, L> ); +static_assert( is_nothrow_constructible_v<function_ref<void()>, L&> ); +static_assert( ! is_constructible_v<function_ref<void()>, const L&> ); +static_assert( ! is_constructible_v<function_ref<void() const>, L> ); +static_assert( ! is_constructible_v<function_ref<void() const>, const L&> ); +static_assert( ! is_constructible_v<function_ref<void()>, + nontype_t<L{}>> ); +static_assert( ! is_constructible_v<function_ref<void() const>, + nontype_t<L{}>> ); + +struct R +{ + void operator()(float) const&&; +}; + +static_assert( ! is_constructible_v<function_ref<void(float)>, R> ); +static_assert( ! is_constructible_v<function_ref<void(float)>, R&> ); +static_assert( ! is_constructible_v<function_ref<void(float) const>, R> ); +static_assert( ! is_constructible_v<function_ref<void(float) const>, R&> ); +static_assert( ! is_constructible_v<function_ref<void(float) const>, const R&> ); + +static_assert( ! is_constructible_v<function_ref<void(float)>, + nontype_t<R{}>> ); +static_assert( ! is_constructible_v<function_ref<void(float) const>, + nontype_t<R{}>> ); + +constexpr bool +test_constexpr() +{ + function_ref<void(S)> fp1(nontype<funS>); + function_ref<void(S)> fp3(nontype<&funS>); + function_ref<void(S)> fp4(nontype<&S::x>); + function_ref<void(S)> fp5(nontype<&S::f>); + + S s; + function_ref<void()> fp6(nontype<&funS>, s); + function_ref<void()> fp7(nontype<&S::x>, s); + function_ref<void()> fp8(nontype<&S::x>, &s); + function_ref<void()> fp9(nontype<&S::f>, s); + function_ref<void()> fp10(nontype<&S::f>, &s); + + M m; + function_ref<void()> fm1(m); + function_ref<void()> fm2(std::move(m)); + + Q q; + constexpr Q cq; + function_ref<void(int)> fq1(q); + function_ref<void(int) const> fq2(q); + function_ref<void(int) const> fq3(std::move(q)); + + function_ref<void(int)> fcq1(cq); + function_ref<void(int) const> f(cq); + function_ref<void(int)> fcq3(nontype<cq>); + function_ref<void(int) const> fcq4(nontype<cq>); + + int i = 0; + function_ref<void()> fcq5(nontype<cq>, i); + function_ref<void() const> fcq6(nontype<cq>, i); + function_ref<void()> fcq7(nontype<cq>, &i); + + L l; + function_ref<void()> fl1(l); + function_ref<void()> fl2(std::move(l)); + + return true; +} +static_assert( test_constexpr() ); + +void func(); + +void +test_instantiation() +{ + function_ref<void(S)> fp1(funS); + function_ref<void(S)> fp2(&funS); + + test_constexpr(); +} diff --git a/libstdc++-v3/testsuite/20_util/function_ref/cons_neg.cc b/libstdc++-v3/testsuite/20_util/function_ref/cons_neg.cc new file mode 100644 index 0000000..050090d --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/function_ref/cons_neg.cc @@ -0,0 +1,30 @@ +// { dg-do compile { target c++26 } } + +#include <functional> + +using std::nontype; +using std::function_ref; + +struct S +{ + int x; + void foo(); +}; +S s; + +constexpr int(*fp)(S) = nullptr; +constexpr int S::*mdp = nullptr; +constexpr int (S::*mfp)() = nullptr; + +function_ref<int(S)> fd1(nontype<fp>); // { dg-error "from here" } +function_ref<int(S)> fd2(nontype<mdp>); // { dg-error "from here" } +function_ref<int(S)> fd3(nontype<mfp>); // { dg-error "from here" } + +function_ref<int()> br4(nontype<fp>, s); // { dg-error "from here" } +function_ref<int()> br5(nontype<mdp>, s); // { dg-error "from here" } +function_ref<int()> br6(nontype<mfp>, s); // { dg-error "from here" } + +function_ref<int()> bp7(nontype<mdp>, &s); // { dg-error "from here" } +function_ref<int()> bp8(nontype<mfp>, &s); // { dg-error "from here" } + +// { dg-prune-output "static assertion failed" } diff --git a/libstdc++-v3/testsuite/20_util/function_ref/conv.cc b/libstdc++-v3/testsuite/20_util/function_ref/conv.cc new file mode 100644 index 0000000..7606d26 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/function_ref/conv.cc @@ -0,0 +1,293 @@ +// { dg-do run { target c++26 } } +// { dg-require-effective-target hosted } + +#include <functional> +#include <string_view> +#include <testsuite_hooks.h> + +using std::function_ref; + +static_assert( std::is_constructible_v<std::function_ref<void() const>, + std::function_ref<void()>> ); + +// Non-trivial args, guarantess that type is not passed by copy +struct CountedArg +{ + CountedArg() = default; + CountedArg(const CountedArg& f) noexcept : counter(f.counter) { ++counter; } + CountedArg& operator=(CountedArg&&) = delete; + + int counter = 0; +}; +CountedArg const c; + +using FuncType = int(int); + +// Top level const qualifiers are ignored in function types, and decay +// is performed. +static_assert( std::is_same_v<std::function_ref<void(int const)>, + std::function_ref<void(int)>> ); +static_assert( std::is_same_v<std::function_ref<void(int[2])>, + std::function_ref<void(int*)>>); +static_assert( std::is_same_v<std::function_ref<void(int[])>, + std::function_ref<void(int*)>>); +static_assert( std::is_same_v<std::function_ref<void(int const[5])>, + std::function_ref<void(int const*)>>); +static_assert( std::is_same_v<std::function_ref<void(FuncType)>, + std::function_ref<void(FuncType*)>>); + +// The C++26 [func.wrap.general] p2 does not currently cover funciton_ref, +// so we make extra copies of arguments. + +void +test01() +{ + auto f = [](CountedArg const& arg) noexcept { return arg.counter; }; + std::function_ref<int(CountedArg) const noexcept> r1(f); + std::move_only_function<int(CountedArg) const noexcept> m1(f); + std::copyable_function<int(CountedArg) const noexcept> c1(f); + + // Complatible signatures + std::function_ref<int(CountedArg) const noexcept> r2m(m1); + VERIFY( r2m(c) == 2 ); + std::function_ref<int(CountedArg) const noexcept> r2c(c1); + VERIFY( r2c(c) == 2 ); + + std::function_ref<int(CountedArg) const> r3r(r1); + VERIFY( r3r(c) == 2 ); + std::function_ref<int(CountedArg) const> r3m(m1); + VERIFY( r3m(c) == 2 ); + std::function_ref<int(CountedArg) const> r3c(c1); + VERIFY( r3c(c) == 2 ); + + std::function_ref<int(CountedArg)> r4r(r1); + VERIFY( r4r(c) == 2 ); + std::function_ref<int(CountedArg)> r4m(m1); + VERIFY( r4m(c) == 2 ); + std::function_ref<int(CountedArg)> r4c(c1); + VERIFY( r4c(c) == 2 ); + + // Incompatible signatures + std::function_ref<long(CountedArg) const noexcept> r5r(r1); + VERIFY( r5r(c) == 2 ); + std::function_ref<long(CountedArg) const noexcept> r5m(m1); + VERIFY( r5r(c) == 2 ); + std::function_ref<long(CountedArg) const noexcept> r5c(c1); + VERIFY( r5r(c) == 2 ); +} + +void +test02() +{ + // Constructing move_only_function and copyable_function from function_ref, + // have not chance to restore manager, so we store function_ref inside. + auto f = [](CountedArg const& arg) noexcept { return arg.counter; }; + std::function_ref<int(CountedArg) const noexcept> r1(f); + + std::move_only_function<int(CountedArg) const noexcept> m1(r1); + VERIFY( m1(c) == 2 ); + + std::copyable_function<int(CountedArg) const noexcept> c1(r1); + VERIFY( c1(c) == 2 ); +} + +void +test03() +{ + struct F + { + int operator()(CountedArg const& arg) noexcept + { return arg.counter; } + + int operator()(CountedArg const& arg) const noexcept + { return arg.counter + 1000; } + }; + + F f; + std::function_ref<int(CountedArg) const> r1(f); + VERIFY( r1(c) == 1001 ); + + // Call const overload as std::function_ref<int(CountedArg) const> + // inside std::function_ref<int(CountedArg)> would do. + std::function_ref<int(CountedArg)> r2(r1); + VERIFY( r2(c) == 1002 ); + std::move_only_function<int(CountedArg)> m2(r1); + VERIFY( m2(c) == 1002 ); + + // Call non-const overload as const-qualifed operator() for + // std::function_ref<int(CountedArg)> do. + std::function_ref<int(CountedArg)> r3(f); + VERIFY( r3(c) == 1 ); + std::function_ref<int(CountedArg) const> r4(r3); + VERIFY( r4(c) == 2 ); + std::move_only_function<int(CountedArg) const> m4(r3); + VERIFY( m4(c) == 2 ); +} + +void +test04() +{ + auto f = [](CountedArg const& arg) noexcept { return arg.counter; }; + std::function_ref<int(CountedArg)> w1(f); + // function_ref stores function_ref due incompatibile signatures + std::function_ref<int(CountedArg const&)> w2(std::move(w1)); + // copy is made when passing to int(CountedArg) + VERIFY( w2(c) == 1 ); + // wrapped 3 times + std::function_ref<int(CountedArg)> w3(w2); + VERIFY( w3(c) == 2 ); + // wrapped 4 times + std::function_ref<int(CountedArg const&)> w4(w3); + VERIFY( w4(c) == 2 ); + // wrapped 5 times + std::function_ref<int(CountedArg)> w5(w4); + VERIFY( w5(c) == 3 ); +} + +void +test05() +{ + // No special interoperability with std::function + auto f = [](CountedArg const& arg) noexcept { return arg.counter; }; + std::function<int(CountedArg)> f1(f); + std::function_ref<int(CountedArg) const> c1(std::move(f1)); + VERIFY( c1(c) == 2 ); + + std::function_ref<int(CountedArg) const> c2(f); + std::function<int(CountedArg)> f2(c2); + VERIFY( f2(c) == 2 ); +} + +void +test06() +{ + auto* func = +[]{ static int x; return &x; }; + std::move_only_function<const void*() const> m1(func); + std::function_ref<const void*() const> rm1(m1); + VERIFY( m1() == rm1() ); + std::copyable_function<const void*() const> c1(func); + std::function_ref<const void*() const> rc1(c1); + VERIFY( c1() == rc1() ); + + struct Trivial + { + void const* operator()() const + { return this; } + }; + std::move_only_function<const void*() const> m2(Trivial{}); + std::function_ref<const void*() const> rm2(m2); + VERIFY( m2() == rm2() ); + std::copyable_function<const void*() const> c2(Trivial{}); + std::function_ref<const void*() const> rc2(c2); + VERIFY( c2() == rc2() ); + + struct NonTrivial : Trivial + { + NonTrivial() {} + NonTrivial(NonTrivial&&) noexcept {} + NonTrivial(const NonTrivial&) {} + }; + std::move_only_function<const void*() const> m3(NonTrivial{}); + std::function_ref<const void*() const> rm3(m3); + VERIFY( m3() == rm3() ); + std::copyable_function<const void*() const> c3(NonTrivial{}); + std::function_ref<const void*() const> rc3(c3); + VERIFY( c3() == rc3() ); + + struct Large : Trivial + { + int tab[10]; + }; + std::move_only_function<const void*() const> m4(Large{}); + std::function_ref<const void*() const> rm4(m4); + VERIFY( m4() == rm4() ); + std::copyable_function<const void*() const> c4(Large{}); + std::function_ref<const void*() const> rc4(c4); + VERIFY( c4() == rc4() ); +} + +void +test07() +{ + int (*f1)() = [] { return 1; }; + int (*f2)() = [] { return 2; }; + + std::function_ref<int() const> r1(f1); + std::move_only_function<int() const> m1(f1); + std::copyable_function<int() const> c1(f1); + + std::function_ref<int() const> r2r(r1); + VERIFY( r2r() == 1 ); + r1 = f2; + VERIFY( r2r() == 1 ); // same-siganture, copy constructor is used + + std::function_ref<int() const> r2m(m1); + VERIFY( r2m() == 1 ); + m1 = f2; + VERIFY( r2m() == 2 ); + + std::function_ref<int() const> r2c(c1); + VERIFY( r2c() == 1 ); + c1 = f2; + VERIFY( r2c() == 2 ); + + std::function_ref<int()> r3r(r1); + VERIFY( r3r() == 2 ); + r1 = f1; + VERIFY( r3r() == 1 ); // converting-constructor + + std::function_ref<int()> r3m(m1); + VERIFY( r3m() == 2 ); + m1 = f1; + VERIFY( r3m() == 1 ); + + std::function_ref<int()> r3c(c1); + VERIFY( r3c() == 2 ); + c1 = f1; + VERIFY( r3c() == 1 ); + +} + +constexpr bool +test08() +{ + auto f = [](int x) noexcept { return x; }; + std::function_ref<int(int) const noexcept> rf(f); + + std::function_ref<int(int) const noexcept> rr1(rf); + std::function_ref<int(int)> rr2(rf); + std::function_ref<int(long)> rr3(rf); + return true; +}; + +void +test09() +{ + // Scalar types and small trivially move constructible types are passed + // by value to invoker. So int&& signature is not compatible for such types. + auto fi = [](CountedArg const& arg, int) noexcept { return arg.counter; }; + std::function_ref<int(CountedArg, int) const noexcept> ri1(fi); + VERIFY( ri1(c, 0) == 1 ); + std::function_ref<int(CountedArg, int&&) const noexcept> ri2(ri1); + VERIFY( ri2(c, 0) == 2 ); + + auto fs = [](CountedArg const& arg, std::string_view) noexcept { return arg.counter; }; + std::function_ref<int(CountedArg, std::string_view) const noexcept> rs1(fs); + VERIFY( rs1(c, "") == 1 ); + std::function_ref<int(CountedArg, std::string_view&&) const noexcept> rs2(rs1); + VERIFY( rs2(c, "") == 2 ); +} + +int main() +{ + test01(); + test02(); + test03(); + test04(); + test05(); + test06(); + test07(); + test09(); + + static_assert( test08() ); +} diff --git a/libstdc++-v3/testsuite/20_util/function_ref/deduction.cc b/libstdc++-v3/testsuite/20_util/function_ref/deduction.cc new file mode 100644 index 0000000..2940b87 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/function_ref/deduction.cc @@ -0,0 +1,103 @@ +// { dg-do compile { target c++26 } } + +#include <functional> +#include <type_traits> + +using std::is_same_v; +using std::nontype; +using std::nontype_t; +using std::function_ref; + +int i = 0; + +void f0(); +void f0n() noexcept; + +static_assert( is_same_v<decltype(function_ref(f0)), + function_ref<void()>> ); +static_assert( is_same_v<decltype(function_ref(f0n)), + function_ref<void() noexcept>> ); +static_assert( is_same_v<decltype(function_ref(nontype<f0>)), + function_ref<void()>> ); +static_assert( is_same_v<decltype(function_ref(nontype<f0n>)), + function_ref<void() noexcept>> ); + +void f1(int); +void f1n(int) noexcept; + +static_assert( is_same_v<decltype(function_ref(f1)), + function_ref<void(int)>> ); +static_assert( is_same_v<decltype(function_ref(f1n)), + function_ref<void(int) noexcept>> ); +static_assert( is_same_v<decltype(function_ref(nontype<f1>)), + function_ref<void(int)>> ); +static_assert( is_same_v<decltype(function_ref(nontype<f1n>)), + function_ref<void(int) noexcept>> ); +static_assert( is_same_v<decltype(function_ref(nontype<f1>, i)), + function_ref<void()>> ); +static_assert( is_same_v<decltype(function_ref(nontype<f1n>, i)), + function_ref<void() noexcept>> ); + +void f2(int*, int); +void f2n(int*, int) noexcept; + +static_assert( is_same_v<decltype(function_ref(f2)), + function_ref<void(int*, int)>> ); +static_assert( is_same_v<decltype(function_ref(f2n)), + function_ref<void(int*, int) noexcept>> ); +static_assert( is_same_v<decltype(function_ref(nontype<f2>)), + function_ref<void(int*, int)>> ); +static_assert( is_same_v<decltype(function_ref(nontype<f2n>)), + function_ref<void(int*, int) noexcept>> ); +static_assert( is_same_v<decltype(function_ref(nontype<f2>, &i)), + function_ref<void(int)>> ); +static_assert( is_same_v<decltype(function_ref(nontype<f2n>, &i)), + function_ref<void(int) noexcept>> ); + +struct S +{ + int mem; + int f(); + int fn() noexcept; + + int fc(int) const; + int fcn(int) const noexcept; + + int fl(int) &; + int fln(int) & noexcept; + + int fcl(float) const&; + int fcln(float) const& noexcept; +}; +S s{}; +const S cs{}; + +static_assert( is_same_v<decltype(function_ref(nontype<&S::mem>, s)), + function_ref<int&()>> ); +static_assert( is_same_v<decltype(function_ref(nontype<&S::mem>, cs)), + function_ref<const int&()>> ); +static_assert( is_same_v<decltype(function_ref(nontype<&S::mem>, &s)), + function_ref<int&()>> ); +static_assert( is_same_v<decltype(function_ref(nontype<&S::mem>, &cs)), + function_ref<const int&()>> ); + +static_assert( is_same_v<decltype(function_ref(nontype<&S::f>, s)), + function_ref<int()>> ); +static_assert( is_same_v<decltype(function_ref(nontype<&S::fn>, &s)), + function_ref<int() noexcept>> ); + +static_assert( is_same_v<decltype(function_ref(nontype<&S::fc>, &s)), + function_ref<int(int)>> ); +static_assert( is_same_v<decltype(function_ref(nontype<&S::fcn>, s)), + function_ref<int(int) noexcept>> ); + +static_assert( is_same_v<decltype(function_ref(nontype<&S::fl>, &s)), + function_ref<int(int)>> ); +static_assert( is_same_v<decltype(function_ref(nontype<&S::fln>, s)), + function_ref<int(int) noexcept>> ); + +static_assert( is_same_v<decltype(function_ref(nontype<&S::fcl>, s)), + function_ref<int(float)>> ); +static_assert( is_same_v<decltype(function_ref(nontype<&S::fcln>, &s)), + function_ref<int(float) noexcept>> ); + diff --git a/libstdc++-v3/testsuite/20_util/function_ref/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/function_ref/incomplete_neg.cc new file mode 100644 index 0000000..c8db1ee --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/function_ref/incomplete_neg.cc @@ -0,0 +1,18 @@ +// { dg-do compile { target c++26 } } + +#include <functional> + +struct IncompleteClass; + +int a1 = alignof(std::function_ref<int(IncompleteClass)>); // { dg-error "here" } +int a2 = alignof(std::function_ref<int(int, IncompleteClass)>); // { dg-error "here" } + +enum Enum { + x = [] { + // Enum enumeration is incomplete here + int a3 = alignof(std::function_ref<int(Enum)>); // { dg-error "here" } + return 1; + }() +}; + +// { dg-error "static assertion failed" "" { target *-*-* } 0 } diff --git a/libstdc++-v3/testsuite/20_util/function_ref/mutation.cc b/libstdc++-v3/testsuite/20_util/function_ref/mutation.cc new file mode 100644 index 0000000..32c6931 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/function_ref/mutation.cc @@ -0,0 +1,85 @@ +// { dg-do run { target c++26 } } + +#include <functional> +#include <testsuite_hooks.h> + +using std::nontype; +using std::function_ref; + +void +test01() +{ + struct F { + int v; + int operator()() { return v; } + }; + F f1{2}, f2{5}; + + function_ref<int()> r1(f1); + function_ref<long()> r2(f1); + + VERIFY( r1() == 2 ); + VERIFY( r2() == 2 ); + + f1.v = 10; + + VERIFY( r1() == 10 ); + VERIFY( r2() == 10 ); + + r1 = function_ref<int()>(f2); + r2 = function_ref<long()>(f2); + + VERIFY( r1() == 5 ); + VERIFY( r2() == 5 ); + + f2.v = 13; + + VERIFY( r1() == 13 ); + VERIFY( r2() == 13 ); + + r1 = function_ref<int()>(f1); + r2 = function_ref<long()>(f1); + + f1.v = 20; + VERIFY( r1() == 20 ); + VERIFY( r2() == 20 ); +} + +void +test02() +{ + struct S + { + int x; + int f() { return x; }; + }; + S s{10}; + + function_ref<int()> r1(nontype<&S::x>, s); + function_ref<long()> r2(nontype<&S::x>, &s); + + VERIFY( r1() == 10 ); + VERIFY( r2() == 10 ); + + s.x = 20; + + VERIFY( r1() == 20 ); + VERIFY( r2() == 20 ); + + r1 = function_ref<int()>(nontype<&S::f>, &s); + r2 = function_ref<long()>(nontype<&S::f>, s); + + VERIFY( r1() == 20 ); + VERIFY( r2() == 20 ); + + s.x = 30; + + VERIFY( r1() == 30 ); + VERIFY( r2() == 30 ); +} + +int main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/20_util/headers/memory/version.cc b/libstdc++-v3/testsuite/20_util/headers/memory/version.cc index c82c9a0..946955d 100644 --- a/libstdc++-v3/testsuite/20_util/headers/memory/version.cc +++ b/libstdc++-v3/testsuite/20_util/headers/memory/version.cc @@ -6,3 +6,7 @@ #if __cpp_lib_allocator_traits_is_always_equal != 201411L # error "Feature-test macro __cpp_lib_allocator_traits_is_always_equal has wrong value in <version>" #endif + +#if __cpp_lib_addressof_constexpr != 201603L +# error "Feature-test macro __cpp_lib_addressof_constexpr has wrong value in <version>" +#endif diff --git a/libstdc++-v3/testsuite/20_util/is_complete_or_unbounded/120717.cc b/libstdc++-v3/testsuite/20_util/is_complete_or_unbounded/120717.cc new file mode 100644 index 0000000..4c07683 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/is_complete_or_unbounded/120717.cc @@ -0,0 +1,20 @@ +// PR libstdc++/120717 +// { dg-do compile { target c++11 } } +// { dg-additional-options "-Wsfinae-incomplete" } + +#include <type_traits> + +// Verify __is_complete_or_unbounded doesn't try to instantiate the underlying +// type of a reference or array of unknown bound. +template<class T> struct A { static_assert(false, "do not instantiate"); }; +static_assert(std::__is_complete_or_unbounded(std::__type_identity<A<int>&>{}), ""); +static_assert(std::__is_complete_or_unbounded(std::__type_identity<A<int>&&>{}), ""); +static_assert(std::__is_complete_or_unbounded(std::__type_identity<A<int>[]>{}), ""); + +// Verify __is_complete_or_unbounded doesn't produce unexpected +// -Wsfinae-incomplete warnings. +struct B; +static_assert(std::__is_complete_or_unbounded(std::__type_identity<B&>{}), ""); +static_assert(std::__is_complete_or_unbounded(std::__type_identity<B&&>{}), ""); +static_assert(std::__is_complete_or_unbounded(std::__type_identity<B[]>{}), ""); +struct B { }; // { dg-bogus "-Wsfinae-incomplete" } diff --git a/libstdc++-v3/testsuite/20_util/is_complete_or_unbounded/memoization.cc b/libstdc++-v3/testsuite/20_util/is_complete_or_unbounded/memoization.cc index 256b84d..59af024 100644 --- a/libstdc++-v3/testsuite/20_util/is_complete_or_unbounded/memoization.cc +++ b/libstdc++-v3/testsuite/20_util/is_complete_or_unbounded/memoization.cc @@ -23,7 +23,7 @@ struct X; static_assert( !std::__is_complete_or_unbounded(std::__type_identity<X>{}), "error"); -struct X{}; +struct X{}; // { dg-warning Wsfinae-incomplete } static_assert( std::__is_complete_or_unbounded(std::__type_identity<X>{}), "Result memoized. This leads to worse diagnostics"); diff --git a/libstdc++-v3/testsuite/20_util/is_complete_or_unbounded/memoization_neg.cc b/libstdc++-v3/testsuite/20_util/is_complete_or_unbounded/memoization_neg.cc index 8e207b5..264efa7 100644 --- a/libstdc++-v3/testsuite/20_util/is_complete_or_unbounded/memoization_neg.cc +++ b/libstdc++-v3/testsuite/20_util/is_complete_or_unbounded/memoization_neg.cc @@ -25,5 +25,5 @@ struct X; constexpr bool res_incomplete = std::is_move_constructible<X>::value; // { dg-error "required from here" } -struct X{}; +struct X{}; // { dg-warning Wsfinae-incomplete } constexpr bool res_complete = std::is_default_constructible<X>::value; // { dg-bogus "required from here" } diff --git a/libstdc++-v3/testsuite/20_util/move_only_function/call.cc b/libstdc++-v3/testsuite/20_util/move_only_function/call.cc index bfc609a..72c8118 100644 --- a/libstdc++-v3/testsuite/20_util/move_only_function/call.cc +++ b/libstdc++-v3/testsuite/20_util/move_only_function/call.cc @@ -190,14 +190,28 @@ test04() VERIFY( std::move(std::as_const(f5))() == 3 ); } +void +test05() +{ + int (*fp)() = [] { return 0; }; + move_only_function<int()> f0{fp}; + VERIFY( f0() == 0 ); + VERIFY( std::move(f0)() == 0 ); + + const move_only_function<int() const> f1{fp}; + VERIFY( f1() == 0 ); + VERIFY( std::move(f1)() == 0 ); +} + struct Incomplete; +enum CompleteEnum : int; void test_params() { - std::move_only_function<void(Incomplete)> f1; - std::move_only_function<void(Incomplete&)> f2; - std::move_only_function<void(Incomplete&&)> f3; + std::move_only_function<void(Incomplete&)> f1; + std::move_only_function<void(Incomplete&&)> f2; + std::move_only_function<void(CompleteEnum)> f4; } int main() @@ -206,5 +220,6 @@ int main() test02(); test03(); test04(); + test05(); test_params(); } diff --git a/libstdc++-v3/testsuite/20_util/move_only_function/conv.cc b/libstdc++-v3/testsuite/20_util/move_only_function/conv.cc new file mode 100644 index 0000000..ef8bb37b --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/move_only_function/conv.cc @@ -0,0 +1,223 @@ +// { dg-do run { target c++23 } } +// { dg-require-effective-target hosted } + +#include <functional> +#include <string_view> +#include <testsuite_hooks.h> + +using std::move_only_function; + +static_assert( !std::is_constructible_v<std::move_only_function<void()>, + std::move_only_function<void()&>> ); +static_assert( !std::is_constructible_v<std::move_only_function<void()>, + std::move_only_function<void()&&>> ); +static_assert( !std::is_constructible_v<std::move_only_function<void()&>, + std::move_only_function<void()&&>> ); +static_assert( !std::is_constructible_v<std::move_only_function<void() const>, + std::move_only_function<void()>> ); + +using FuncType = int(int); + +// Top level const qualifiers are ignored in function types, and decay +// is performed. +static_assert( std::is_same_v<std::move_only_function<void(int const)>, + std::move_only_function<void(int)>> ); +static_assert( std::is_same_v<std::move_only_function<void(int[2])>, + std::move_only_function<void(int*)>>); +static_assert( std::is_same_v<std::move_only_function<void(int[])>, + std::move_only_function<void(int*)>>); +static_assert( std::is_same_v<std::move_only_function<void(int const[5])>, + std::move_only_function<void(int const*)>>); +static_assert( std::is_same_v<std::move_only_function<void(FuncType)>, + std::move_only_function<void(FuncType*)>>); + +// Non-trivial args, guarantess that type is not passed by copy +struct CountedArg +{ + CountedArg() = default; + CountedArg(const CountedArg& f) noexcept : counter(f.counter) { ++counter; } + CountedArg& operator=(CountedArg&&) = delete; + + int counter = 0; +}; +CountedArg const c; + +// When move_only_functions is constructed from other move_only_function, +// the compiler can avoid double indirection per C++26 [func.wrap.general] p2. + +void +test01() +{ + auto f = [](CountedArg const& arg) noexcept { return arg.counter; }; + std::move_only_function<int(CountedArg) const noexcept> m1(f); + VERIFY( m1(c) == 1 ); + + std::move_only_function<int(CountedArg) const> m2(std::move(m1)); + VERIFY( m2(c) == 1 ); + + std::move_only_function<int(CountedArg)> m3(std::move(m2)); + VERIFY( m3(c) == 1 ); + + // Invokers internally uses Counted&& for non-trivial types, + // sinature remain compatible. + std::move_only_function<int(CountedArg&&)> m4(std::move(m3)); + VERIFY( m4({}) == 0 ); + + std::move_only_function<int(CountedArg&&)&&> m5(std::move(m4)); + VERIFY( std::move(m5)({}) == 0 ); + + m4 = f; + std::move_only_function<int(CountedArg&&)&> m7(std::move(m4)); + VERIFY( m7({}) == 0 ); + + m4 = f; + std::move_only_function<int(CountedArg&&)&> m8(std::move(m4)); + VERIFY( m8({}) == 0 ); + + // Incompatible signatures + m1 = f; + std::move_only_function<long(CountedArg) const noexcept> m9(std::move(m1)); + VERIFY( m9(c) == 2 ); +} + +void +test02() +{ + auto f = [](CountedArg const& arg) noexcept { return arg.counter; }; + std::move_only_function<int(CountedArg) const noexcept> m1(f); + VERIFY( m1(c) == 1 ); + + std::move_only_function<int(CountedArg) const> m2; + m2 = std::move(m1); + VERIFY( m2(c) == 1 ); + + std::move_only_function<int(CountedArg)> m3; + m3 = std::move(m2); + VERIFY( m3(c) == 1 ); + + // Invokers internally uses Counted&& for non-trivial types, + // sinature remain compatible. + std::move_only_function<int(CountedArg&&)> m4; + m4 = std::move(m3); + VERIFY( m4({}) == 0 ); + + std::move_only_function<int(CountedArg&&)&&> m5; + m5 = std::move(m4); + VERIFY( std::move(m5)({}) == 0 ); + + m4 = f; + std::move_only_function<int(CountedArg&&)&> m7; + m7 = std::move(m4); + VERIFY( m7({}) == 0 ); + + m4 = f; + std::move_only_function<int(CountedArg&&)&> m8; + m8 = std::move(m4); + VERIFY( m8({}) == 0 ); + + m1 = f; + std::move_only_function<long(CountedArg) const noexcept> m9; + m9 = std::move(m1); + VERIFY( m9(c) == 2 ); +} + +void +test03() +{ + std::move_only_function<int(long) const noexcept> e; + VERIFY( e == nullptr ); + + std::move_only_function<int(long) const> e2(std::move(e)); + VERIFY( e2 == nullptr ); + e2 = std::move(e); + VERIFY( e2 == nullptr ); + + std::move_only_function<bool(int) const> e3(std::move(e)); + VERIFY( e3 == nullptr ); + e3 = std::move(e); + VERIFY( e3 == nullptr ); +} + +void +test04() +{ + struct F + { + int operator()(CountedArg const& arg) noexcept + { return arg.counter; } + + int operator()(CountedArg const& arg) const noexcept + { return arg.counter + 1000; } + }; + + F f; + std::move_only_function<int(CountedArg) const> m1(f); + VERIFY( m1(c) == 1001 ); + + // Call const overload as std::move_only_function<int(CountedArg) const> + // inside std::move_only_function<int(CountedArg)> would do. + std::move_only_function<int(CountedArg)> m2(std::move(m1)); + VERIFY( m2(c) == 1001 ); + + std::move_only_function<int(CountedArg)> m3(f); + VERIFY( m3(c) == 1 ); +} + +void +test05() +{ + auto f = [](CountedArg const& arg) noexcept { return arg.counter; }; + std::move_only_function<int(CountedArg)> w1(f); + // move_only_function stores move_only_function due incompatibile signatures + std::move_only_function<int(CountedArg const&)> w2(std::move(w1)); + // copy is made when passing to int(CountedArg) + VERIFY( w2(c) == 1 ); + // wrapped 3 times + w1 = std::move(w2); + VERIFY( w1(c) == 2 ); + // wrapped 4 times + w2 = std::move(w1); + VERIFY( w2(c) == 2 ); + // wrapped 5 times + w1 = std::move(w2); + VERIFY( w1(c) == 3 ); +} + +void +test06() +{ + // No special interoperability with std::function + auto f = [](CountedArg const& arg) noexcept { return arg.counter; }; + std::function<int(CountedArg)> f1(f); + std::move_only_function<int(CountedArg) const> m1(std::move(f1)); + VERIFY( m1(c) == 2 ); +} + +void +test07() +{ + // Scalar types and small trivially move constructible types are passed + // by value to invoker. So int&& signature is not compatible for such types. + auto fi = [](CountedArg const& arg, int) noexcept { return arg.counter; }; + std::move_only_function<int(CountedArg, int) const noexcept> mi1(fi); + VERIFY( mi1(c, 0) == 1 ); + std::move_only_function<int(CountedArg, int&&) const noexcept> mi2(std::move(mi1)); + VERIFY( mi2(c, 0) == 2 ); + + auto fs = [](CountedArg const& arg, std::string_view) noexcept { return arg.counter; }; + std::move_only_function<int(CountedArg, std::string_view) const noexcept> ms1(fs); + VERIFY( ms1(c, "") == 1 ); + std::move_only_function<int(CountedArg, std::string_view&&) const noexcept> ms2(std::move(ms1)); + VERIFY( ms2(c, "") == 2 ); +} + +int main() +{ + test01(); + test02(); + test03(); + test04(); + test05(); + test06(); + test07(); +} diff --git a/libstdc++-v3/testsuite/20_util/move_only_function/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/move_only_function/incomplete_neg.cc new file mode 100644 index 0000000..d025c47 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/move_only_function/incomplete_neg.cc @@ -0,0 +1,18 @@ +// { dg-do compile { target c++23 } } + +#include <functional> + +struct IncompleteClass; + +using T1 = std::move_only_function<int(IncompleteClass)>::result_type; // { dg-error "here" } +using T2 = std::move_only_function<int(int, IncompleteClass)>::result_type; // { dg-error "here" } + +enum Enum { + x = [] { + // Enum enumeration is incomplete here + using T3 = std::move_only_function<int(Enum)>::result_type; // { dg-error "here" } + return T3(1); + }() +}; + +// { dg-error "static assertion failed" "" { target *-*-* } 0 } diff --git a/libstdc++-v3/testsuite/20_util/move_only_function/move.cc b/libstdc++-v3/testsuite/20_util/move_only_function/move.cc index 51e31a6..6da02c9 100644 --- a/libstdc++-v3/testsuite/20_util/move_only_function/move.cc +++ b/libstdc++-v3/testsuite/20_util/move_only_function/move.cc @@ -32,6 +32,12 @@ test01() VERIFY( m1().copy == 1 ); VERIFY( m1().move == 0 ); + // Standard specifies move assigment as copy and swap + m1 = std::move(m1); + VERIFY( m1 != nullptr ); + VERIFY( m1().copy == 1 ); + VERIFY( m1().move == 0 ); + // This will move construct a new target object and destroy the old one: auto m2 = std::move(m1); VERIFY( m1 == nullptr && m2 != nullptr ); @@ -80,6 +86,11 @@ test02() VERIFY( m1().copy == 1 ); VERIFY( m1().move == 0 ); + m1 = std::move(m1); + VERIFY( m1 != nullptr ); + VERIFY( m1().copy == 1 ); + VERIFY( m1().move == 0 ); + // The target object is on the heap so this just moves a pointer: auto m2 = std::move(m1); VERIFY( m1 == nullptr && m2 != nullptr ); diff --git a/libstdc++-v3/testsuite/20_util/optional/range.cc b/libstdc++-v3/testsuite/20_util/optional/range.cc new file mode 100644 index 0000000..e77dc21 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/optional/range.cc @@ -0,0 +1,163 @@ +// { dg-do compile { target c++26 } } + +#include <concepts> +#include <format> +#include <iterator> +#include <optional> +#include <ranges> +#include <string_view> +#include <vector> + +#include <testsuite_hooks.h> + +template<typename O> +constexpr +void +test_range_concepts() +{ + static_assert(std::ranges::contiguous_range<O>); + static_assert(std::ranges::sized_range<O>); + static_assert(std::ranges::common_range<O>); + static_assert(!std::ranges::borrowed_range<O>); + + // an optional<const T> is not assignable, and therefore does not satisfy ranges::view + using T = typename O::value_type; + constexpr bool is_const_opt = std::is_const_v<T>; + static_assert(std::ranges::view<O> == !is_const_opt); + static_assert(std::ranges::viewable_range<O> == !is_const_opt); +} + +template<typename O> +constexpr +void +test_iterator_concepts() +{ + using T = typename O::value_type; + using iterator = typename O::iterator; + static_assert(std::contiguous_iterator<iterator>); + static_assert(std::is_same_v<typename std::iterator_traits<iterator>::value_type, std::remove_cv_t<T>>); + static_assert(std::is_same_v<std::iter_value_t<iterator>, std::remove_cv_t<T>>); + static_assert(std::is_same_v<typename std::iterator_traits<iterator>::reference, T&>); + static_assert(std::is_same_v<std::iter_reference_t<iterator>, T&>); + + using const_iterator = typename O::const_iterator; + static_assert(std::contiguous_iterator<const_iterator>); + static_assert(std::is_same_v<typename std::iterator_traits<const_iterator>::value_type, std::remove_cv_t<T>>); + static_assert(std::is_same_v<std::iter_value_t<const_iterator>, std::remove_cv_t<T>>); + static_assert(std::is_same_v<typename std::iterator_traits<const_iterator>::reference, const T&>); + static_assert(std::is_same_v<std::iter_reference_t<const_iterator>, const T&>); +} + +template<typename O> +constexpr +void +test_empty() +{ + O empty; + VERIFY(!empty); + VERIFY(empty.begin() == empty.end()); + VERIFY(std::as_const(empty).begin() == std::as_const(empty).end()); + VERIFY(std::ranges::empty(empty)); + VERIFY(std::ranges::empty(std::as_const(empty))); + VERIFY(std::ranges::empty(empty | std::views::as_const)); + VERIFY(std::ranges::size(empty) == 0); + VERIFY(std::ranges::size(std::as_const(empty)) == 0); + + size_t count = 0; + for (const auto& x : empty) + ++count; + VERIFY(count == 0); +} + +template<typename O, typename T> +constexpr +void +test_non_empty(const T& value) +{ + O non_empty = std::make_optional(value); + VERIFY(non_empty); + VERIFY(*non_empty == value); + VERIFY(non_empty.begin() != non_empty.end()); + VERIFY(non_empty.begin() < non_empty.end()); + VERIFY(std::as_const(non_empty).begin() != std::as_const(non_empty).end()); + VERIFY(std::as_const(non_empty).begin() < std::as_const(non_empty).end()); + VERIFY(!std::ranges::empty(non_empty)); + VERIFY(!std::ranges::empty(std::as_const(non_empty))); + VERIFY(!std::ranges::empty(non_empty | std::views::as_const)); + VERIFY(std::ranges::size(non_empty) == 1); + VERIFY(std::ranges::size(std::as_const(non_empty)) == 1); + + size_t count = 0; + for (const auto& x : non_empty) + ++count; + VERIFY(count == 1); + + if constexpr (!std::is_const_v<typename O::value_type>) { + for (auto& x : non_empty) + x = T{}; + VERIFY(non_empty); + VERIFY(*non_empty == T{}); + } +} + +template<typename T> +constexpr +void +test(const T& value) +{ + using O = std::optional<T>; + test_range_concepts<O>(); + test_iterator_concepts<O>(); + test_empty<O>(); + test_non_empty<O>(value); + static_assert(!std::formattable<O, char>); + static_assert(!std::formattable<O, wchar_t>); + static_assert(std::format_kind<O> == std::range_format::disabled); +} + +constexpr +void +range_chain_example() // from P3168 +{ + std::vector<int> v{2, 3, 4, 5, 6, 7, 8, 9, 1}; + auto test = [](int i) -> std::optional<int> { + switch(i) { + case 1: + case 3: + case 7: + case 9: + return i * 2; + default: + return {}; + } + }; + + auto result = v + | std::views::transform(test) + | std::views::filter([](auto x) { return bool(x); }) + | std::views::transform([](auto x){ return *x; }) + | std::ranges::to<std::vector>(); + + bool ok = result == std::vector<int>{6, 14, 18, 2}; + VERIFY(ok); +} + +constexpr +bool +all_tests() +{ + test(42); + int i = 42; + test(&i); + test(std::string_view("test")); + test(std::vector<int>{1, 2, 3, 4}); + test(std::optional<int>(42)); + test<const int>(42); + + range_chain_example(); + + return true; +} + +static_assert(all_tests()); + diff --git a/libstdc++-v3/testsuite/20_util/optional/version.cc b/libstdc++-v3/testsuite/20_util/optional/version.cc index 657a399..ba44aa5 100644 --- a/libstdc++-v3/testsuite/20_util/optional/version.cc +++ b/libstdc++-v3/testsuite/20_util/optional/version.cc @@ -21,8 +21,17 @@ #endif #endif +#if __cplusplus > 202302L +# ifndef __cpp_lib_optional_range_support +# error "Feature test macro for optional range support is missing in <version>" +# elif __cpp_lib_optional_range_support != 202406L +# error "Feature test macro for optional range support has wrong value for C++26 in <version>" +# endif +#endif + #undef __cpp_lib_optional #undef __cpp_lib_freestanding_optional +#undef __cpp_lib_optional_range_support #include <optional> #if __cplusplus >= 202302L @@ -32,3 +41,12 @@ # error "Feature test macro for freestanding std::optional has wrong value in <optional>" #endif #endif + +#if __cplusplus > 202302L +# ifndef __cpp_lib_optional_range_support +# error "Feature test macro for optional range support is missing in <optional>" +# endif +# if __cpp_lib_optional_range_support != 202406L +# error "Feature test macro for optional range support has wrong value for C++26 in <optional>" +# endif +#endif diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/requirements/1.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/requirements/1.cc index 8ddb5d2..19090d1 100644 --- a/libstdc++-v3/testsuite/20_util/shared_ptr/requirements/1.cc +++ b/libstdc++-v3/testsuite/20_util/shared_ptr/requirements/1.cc @@ -3,31 +3,122 @@ #include <memory> #include <testsuite_tr1.h> +#include <type_traits> using namespace __gnu_test; +template<template<class> class SmartPtr> void test01() { - std::shared_ptr<ClassType> ptr; - std::shared_ptr<const ClassType> ptr2 = ptr; + SmartPtr<ClassType> ptr; + SmartPtr<const ClassType> ptr2 = ptr; #if __cpp_lib_shared_ptr_arrays >= 201611L - std::shared_ptr<ClassType[10]> ptr_array; - std::shared_ptr<ClassType[]> ptr_array2 = ptr_array; - std::shared_ptr<ClassType const []> ptr_array3 = ptr_array; + SmartPtr<ClassType[10]> ptr_array; + SmartPtr<ClassType[]> ptr_array2 = ptr_array; + SmartPtr<ClassType const []> ptr_array3 = ptr_array; #endif } +template<template<class> class SmartPtr> void test02() { - std::shared_ptr<IncompleteClass> ptr; - std::shared_ptr<const IncompleteClass> ptr2 = ptr; + SmartPtr<IncompleteClass> ptr; + SmartPtr<const IncompleteClass> ptr2 = ptr; #if __cpp_lib_shared_ptr_arrays >= 201611L - std::shared_ptr<IncompleteClass[10]> ptr_array; - std::shared_ptr<IncompleteClass[]> ptr_array2 = ptr_array; - std::shared_ptr<IncompleteClass const []> ptr_array3 = ptr_array; + SmartPtr<IncompleteClass[10]> ptr_array; + SmartPtr<IncompleteClass[]> ptr_array2 = ptr_array; + SmartPtr<IncompleteClass const []> ptr_array3 = ptr_array; #endif } + +template<template<class> class SmartPtr> +void +test03() +{ + static_assert( std::is_convertible<SmartPtr<int>, SmartPtr<const int>>::value); + static_assert(!std::is_convertible<SmartPtr<const int>, SmartPtr<int>>::value); + static_assert( std::is_convertible<SmartPtr<ClassType>, SmartPtr<const ClassType>>::value); + static_assert(!std::is_convertible<SmartPtr<const ClassType>, SmartPtr<ClassType>>::value); + static_assert( std::is_convertible<SmartPtr<IncompleteClass>, SmartPtr<const IncompleteClass>>::value); + static_assert(!std::is_convertible<SmartPtr<const IncompleteClass>, SmartPtr<IncompleteClass>>::value); + static_assert( std::is_convertible<SmartPtr<void>, SmartPtr<const void>>::value); + static_assert(!std::is_convertible<SmartPtr<const void>, SmartPtr<void>>::value); + + static_assert( std::is_convertible<SmartPtr<int>, SmartPtr<void>>::value); + static_assert(!std::is_convertible<SmartPtr<void>, SmartPtr<int>>::value); + static_assert( std::is_convertible<SmartPtr<int>, SmartPtr<const void>>::value); + static_assert( std::is_convertible<SmartPtr<const int>, SmartPtr<const void>>::value); + static_assert(!std::is_convertible<SmartPtr<const int>, SmartPtr<void>>::value); + static_assert(!std::is_convertible<SmartPtr<const void>, SmartPtr<const int>>::value); + static_assert( std::is_convertible<SmartPtr<ClassType>, SmartPtr<void>>::value); + static_assert( std::is_convertible<SmartPtr<ClassType>, SmartPtr<const void>>::value); + + static_assert(!std::is_convertible<SmartPtr<int*>, SmartPtr<const int*>>::value); + static_assert( std::is_convertible<SmartPtr<int*>, SmartPtr<const int* const>>::value); + static_assert(!std::is_convertible<SmartPtr<const int*>, SmartPtr<int*>>::value); + static_assert(!std::is_convertible<SmartPtr<const int* const>, SmartPtr<int*>>::value); + + static_assert(!std::is_convertible<SmartPtr<ClassType*>, SmartPtr<const ClassType*>>::value); + static_assert( std::is_convertible<SmartPtr<ClassType*>, SmartPtr<const ClassType* const>>::value); + static_assert(!std::is_convertible<SmartPtr<const ClassType*>, SmartPtr<ClassType*>>::value); + static_assert(!std::is_convertible<SmartPtr<const ClassType* const>, SmartPtr<ClassType*>>::value); + + static_assert(!std::is_convertible<SmartPtr<void*>, SmartPtr<const void*>>::value); + static_assert( std::is_convertible<SmartPtr<void*>, SmartPtr<const void* const>>::value); + static_assert(!std::is_convertible<SmartPtr<const void*>, SmartPtr<void*>>::value); + static_assert(!std::is_convertible<SmartPtr<const void* const>, SmartPtr<void*>>::value); + +#if __cpp_lib_shared_ptr_arrays >= 201611L + static_assert( std::is_convertible<SmartPtr<int[10]>, SmartPtr<int[]>>::value); + static_assert(!std::is_convertible<SmartPtr<int[]>, SmartPtr<int[10]>>::value); + static_assert( std::is_convertible<SmartPtr<int[10]>, SmartPtr<int const[]>>::value); + static_assert( std::is_convertible<SmartPtr<int[10]>, SmartPtr<int const[10]>>::value); + static_assert( std::is_convertible<SmartPtr<int[]>, SmartPtr<int const[]>>::value); + static_assert(!std::is_convertible<SmartPtr<int const[]>, SmartPtr<int[]>>::value); + static_assert( std::is_convertible<SmartPtr<int const[10]>, SmartPtr<int const[]>>::value); + static_assert(!std::is_convertible<SmartPtr<int const[]>, SmartPtr<int const[10]>>::value); + + static_assert( std::is_convertible<SmartPtr<ClassType[10]>, SmartPtr<ClassType[]>>::value); + static_assert(!std::is_convertible<SmartPtr<ClassType[]>, SmartPtr<ClassType[10]>>::value); + static_assert( std::is_convertible<SmartPtr<ClassType[10]>, SmartPtr<ClassType const[]>>::value); + static_assert( std::is_convertible<SmartPtr<ClassType[10]>, SmartPtr<ClassType const[10]>>::value); + static_assert( std::is_convertible<SmartPtr<ClassType[]>, SmartPtr<ClassType const[]>>::value); + static_assert(!std::is_convertible<SmartPtr<ClassType const[]>, SmartPtr<ClassType[]>>::value); + static_assert( std::is_convertible<SmartPtr<ClassType const[10]>, SmartPtr<ClassType const[]>>::value); + static_assert(!std::is_convertible<SmartPtr<ClassType const[]>, SmartPtr<ClassType const[10]>>::value); + + static_assert( std::is_convertible<SmartPtr<IncompleteClass[10]>, SmartPtr<IncompleteClass[]>>::value); + static_assert(!std::is_convertible<SmartPtr<IncompleteClass[]>, SmartPtr<IncompleteClass[10]>>::value); + static_assert( std::is_convertible<SmartPtr<IncompleteClass[10]>, SmartPtr<IncompleteClass const[]>>::value); + static_assert( std::is_convertible<SmartPtr<IncompleteClass[10]>, SmartPtr<IncompleteClass const[10]>>::value); + static_assert( std::is_convertible<SmartPtr<IncompleteClass[]>, SmartPtr<IncompleteClass const[]>>::value); + static_assert(!std::is_convertible<SmartPtr<IncompleteClass const[]>, SmartPtr<IncompleteClass[]>>::value); + static_assert( std::is_convertible<SmartPtr<IncompleteClass const[10]>, SmartPtr<IncompleteClass const[]>>::value); + static_assert(!std::is_convertible<SmartPtr<IncompleteClass const[]>, SmartPtr<IncompleteClass const[10]>>::value); + + static_assert( std::is_convertible<SmartPtr<int*[10]>, SmartPtr<int*[]>>::value); + static_assert(!std::is_convertible<SmartPtr<int*[]>, SmartPtr<int*[10]>>::value); + static_assert( std::is_convertible<SmartPtr<int*[10]>, SmartPtr<int* const[10]>>::value); + static_assert( std::is_convertible<SmartPtr<int*[10]>, SmartPtr<int* const[]>>::value); + + static_assert(!std::is_convertible<SmartPtr<int*[]>, SmartPtr<void*[]>>::value); + static_assert(!std::is_convertible<SmartPtr<int*[]>, SmartPtr<void const *[]>>::value); +#endif +} + +int +main() +{ + test01<std::shared_ptr>(); + test01<std::weak_ptr>(); + + test02<std::shared_ptr>(); + test02<std::weak_ptr>(); + + test03<std::shared_ptr>(); + test03<std::weak_ptr>(); +} diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/memory_management_tools/destroy_n_neg.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/memory_management_tools/destroy_n_neg.cc new file mode 100644 index 0000000..12c0dc5 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/memory_management_tools/destroy_n_neg.cc @@ -0,0 +1,59 @@ +// Copyright (C) 2017-2025 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// { dg-do compile { target c++17 } } + +#include <memory> + +// This has a trivial destructor, but should not be destructible! +struct DeletedDtor { + ~DeletedDtor() = delete; +}; + +void +test01() +{ + alignas(DeletedDtor) unsigned char buf[sizeof(DeletedDtor)]; + auto p = ::new (buf) DeletedDtor(); + std::destroy_n(p, 1); +} + +class PrivateDtor { + ~PrivateDtor() { } +}; + +void +test02() +{ + alignas(PrivateDtor) unsigned char buf[sizeof(PrivateDtor)]; + auto p = ::new (buf) PrivateDtor(); + std::destroy_n(p, 1); +} + +#if __cpp_constexpr_dynamic_alloc // >= C++20 +consteval bool +test03() +{ + DeletedDtor* p = nullptr; + std::destroy_n(p, 0); + return true; +} +static_assert(test03()); +#endif + +// { dg-error "deleted function .*DeletedDtor" "" { target *-*-* } 0 } +// { dg-error "PrivateDtor.* is private" "" { target *-*-* } 0 } diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/memory_management_tools/destroy_neg.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/memory_management_tools/destroy_neg.cc index 5946a82..096f218 100644 --- a/libstdc++-v3/testsuite/20_util/specialized_algorithms/memory_management_tools/destroy_neg.cc +++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/memory_management_tools/destroy_neg.cc @@ -29,8 +29,7 @@ test01() { alignas(DeletedDtor) unsigned char buf[sizeof(DeletedDtor)]; auto p = ::new (buf) DeletedDtor(); - std::destroy(p, p + 1); // { dg-error "here" } - std::destroy_n(p, 1); // { dg-error "here" } + std::destroy(p, p + 1); } class PrivateDtor { @@ -42,8 +41,19 @@ test02() { alignas(PrivateDtor) unsigned char buf[sizeof(PrivateDtor)]; auto p = ::new (buf) PrivateDtor(); - std::destroy(p, p + 1); // { dg-error "here" } - std::destroy_n(p, 1); // { dg-error "here" } + std::destroy(p, p + 1); } -// { dg-error "value type is destructible" "" { target *-*-* } 0 } +#if __cpp_constexpr_dynamic_alloc // >= C++20 +consteval bool +test03() +{ + DeletedDtor* p = nullptr; + std::destroy(p, p); + return true; +} +static_assert(test03()); +#endif + +// { dg-error "deleted function .*DeletedDtor" "" { target *-*-* } 0 } +// { dg-error "PrivateDtor.* is private" "" { target *-*-* } 0 } diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/constrained.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/constrained.cc index af3b733..5dff0da 100644 --- a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/constrained.cc +++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/constrained.cc @@ -178,12 +178,40 @@ test03() void test_pr101587() { - short in[1]; + short in[1]{}; __gnu_test::test_contiguous_range r(in); // difference_type is integer-like long out[1]; std::span<long> o(out); // difference_type is ptrdiff_t ranges::uninitialized_copy(r, o); ranges::uninitialized_copy_n(ranges::begin(r), 0, o.begin(), o.end()); + + // iterator that has an integer-like class type for difference_type + struct Iter + { + using value_type = long; + using difference_type = std::ranges::__detail::__max_diff_type; + + long& operator*() const { return *p; } + + Iter& operator++() { ++p; return *this; } + Iter operator++(int) { return Iter{p++}; } + + difference_type operator-(Iter i) const { return p - i.p; } + bool operator==(const Iter&) const = default; + + long* p = nullptr; + }; + static_assert(std::sized_sentinel_for<Iter, Iter>); + + std::ranges::subrange<Iter> rmax(Iter{out+0}, Iter{out+1}); + // Check with integer-like class type for output range: + std::ranges::uninitialized_copy(in, rmax); + std::ranges::uninitialized_copy_n(in+0, 1, rmax.begin(), rmax.end()); + + int to[1]; + // And for input range: + std::ranges::uninitialized_copy(rmax, to); + std::ranges::uninitialized_copy_n(rmax.begin(), 1, to+0, to+1); } int diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_default_construct/120397.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_default_construct/120397.cc new file mode 100644 index 0000000..7aa05d7 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_default_construct/120397.cc @@ -0,0 +1,19 @@ +// { dg-do compile { target c++17 } } + +#include <memory> + +// PR libstdc++/120397 +// std::uninitialized_value_construct cannot create arrays of non-trivially +// destructible types + +struct X { X() { } ~X() { } }; + +void def(X (*x)[1]) +{ + std::uninitialized_default_construct(x, x+1); +} + +void def_n(X (*x)[1]) +{ + std::uninitialized_default_construct_n(x, 1); +} diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill/120931.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill/120931.cc new file mode 100644 index 0000000..766fac0 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill/120931.cc @@ -0,0 +1,16 @@ +// { dg-options "-std=gnu++98" } +// { dg-do compile { target c++98_only } } +// std::deque<character types>::resize() method fails with -std=c++98 + +#include <memory> +#include <testsuite_iterators.h> + +void +test_pr120931() +{ + using __gnu_test::test_container; + using __gnu_test::forward_iterator_wrapper; + unsigned char c[1]; + test_container<unsigned char, forward_iterator_wrapper> f(c); + std::uninitialized_fill(f.begin(), f.end(), 0); +} diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_move/constrained.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_move/constrained.cc index fe82d1f1..3e81244 100644 --- a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_move/constrained.cc +++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_move/constrained.cc @@ -188,12 +188,39 @@ test03() void test_pr101587() { - short in[1]; + short in[1]{}; __gnu_test::test_contiguous_range r(in); // difference_type is integer-like long out[1]; std::span<long> o(out); // difference_type is ptrdiff_t ranges::uninitialized_move(r, o); ranges::uninitialized_move_n(ranges::begin(r), 0, o.begin(), o.end()); + + struct Iter + { + using value_type = long; + using difference_type = std::ranges::__detail::__max_diff_type; + + long& operator*() const { return *p; } + + Iter& operator++() { ++p; return *this; } + Iter operator++(int) { return Iter{p++}; } + + difference_type operator-(Iter i) const { return p - i.p; } + bool operator==(const Iter&) const = default; + + long* p = nullptr; + }; + static_assert(std::sized_sentinel_for<Iter, Iter>); + + std::ranges::subrange<Iter> rmax(Iter{out+0}, Iter{out+1}); + // Check with integer-like class type for output range: + std::ranges::uninitialized_move(in, rmax); + std::ranges::uninitialized_move_n(in+0, 1, rmax.begin(), rmax.end()); + + int to[1]; + // And for input range: + std::ranges::uninitialized_copy(rmax, to); + std::ranges::uninitialized_copy_n(rmax.begin(), 1, to+0, to+1); } int diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_value_construct/120397.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_value_construct/120397.cc new file mode 100644 index 0000000..f4d9fce --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_value_construct/120397.cc @@ -0,0 +1,19 @@ +// { dg-do compile { target c++17 } } + +#include <memory> + +// PR libstdc++/120397 +// std::uninitialized_value_construct cannot create arrays of non-trivially +// destructible types + +struct X { X() { } ~X() { } }; + +void val(X (*x)[1]) +{ + std::uninitialized_value_construct(x, x+1); +} + +void val_n(X (*x)[1]) +{ + std::uninitialized_value_construct_n(x, 1); +} diff --git a/libstdc++-v3/testsuite/20_util/system_clock/99832.cc b/libstdc++-v3/testsuite/20_util/system_clock/99832.cc new file mode 100644 index 0000000..693d4d6 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/system_clock/99832.cc @@ -0,0 +1,14 @@ +// { dg-options "-O0 -g0" } +// { dg-do compile { target c++20 } } +// { dg-final { scan-assembler-not "system_clock9to_time_t" } } + +// Bug libstdc++/99832 +// std::chrono::system_clock::to_time_t needs ABI tag for 32-bit time_t + +#include <chrono> + +std::time_t +test_pr99832(std::chrono::system_clock::time_point t) +{ + return std::chrono::system_clock::to_time_t(t); +} diff --git a/libstdc++-v3/testsuite/20_util/tuple/dr3528.cc b/libstdc++-v3/testsuite/20_util/tuple/dr3528.cc new file mode 100644 index 0000000..c20ff95 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/tuple/dr3528.cc @@ -0,0 +1,46 @@ +// { dg-do compile { target c++17 } } + +// LWG 3528. make_from_tuple can perform (the equivalent of) a C-style cast + +#include <tuple> +#include <array> +#include <utility> + +template<typename T, typename Tuple> +using make_t = decltype(std::make_from_tuple<T>(std::declval<Tuple>())); + +template<typename T, typename Tuple, typename = void> +constexpr bool can_make = false; +template<typename T, typename Tuple> +constexpr bool can_make<T, Tuple, std::void_t<make_t<T, Tuple>>> = true; + +static_assert( can_make<int, std::tuple<int>> ); +static_assert( can_make<int, std::tuple<int>&> ); +static_assert( can_make<int, const std::tuple<int>&> ); +static_assert( can_make<int, std::array<short, 1>> ); +static_assert( can_make<int, const std::array<short, 1>&&> ); +static_assert( can_make<std::tuple<int, int>, std::pair<unsigned, long>> ); +static_assert( can_make<std::pair<int, int>, std::array<int, 2>> ); +static_assert( can_make<const int*, std::tuple<int*>> ); +static_assert( can_make<void*, std::tuple<int*>> ); +static_assert( can_make<int, std::tuple<>> ); +static_assert( ! can_make<int, std::tuple<int, int>> ); +static_assert( ! can_make<int, std::pair<short, char>> ); +static_assert( ! can_make<int, std::pair<short, char>&> ); +static_assert( ! can_make<int, std::tuple<const char*>> ); +static_assert( ! can_make<int*, std::tuple<const int*>> ); +static_assert( ! can_make<int*, std::tuple<void*>> ); +static_assert( ! can_make<int, std::array<int, 2>> ); +static_assert( ! can_make<void, std::tuple<>> ); +static_assert( ! can_make<void, std::array<int, 1>> ); + +struct Two +{ + Two(const char*, int); +}; + +static_assert( can_make<Two, std::tuple<char*, unsigned>> ); +static_assert( ! can_make<Two, std::tuple<const char*, int, int>> ); +static_assert( can_make<Two, std::pair<const char*, long>> ); +static_assert( ! can_make<Two, std::pair<int*, long>> ); +static_assert( ! can_make<std::pair<int, int>, std::array<int, 3>> ); diff --git a/libstdc++-v3/testsuite/20_util/tuple/element_access/get_neg.cc b/libstdc++-v3/testsuite/20_util/tuple/element_access/get_neg.cc index 48628a9..18d47d2 100644 --- a/libstdc++-v3/testsuite/20_util/tuple/element_access/get_neg.cc +++ b/libstdc++-v3/testsuite/20_util/tuple/element_access/get_neg.cc @@ -61,4 +61,4 @@ test03() // { dg-error "tuple index must be in range" "" { target *-*-* } 0 } // { dg-prune-output "no type named 'type' in .*_Nth_type" } -// { dg-prune-output "pack index is out of range" } +// { dg-prune-output "pack index '.' is out of range" } diff --git a/libstdc++-v3/testsuite/20_util/weak_ptr/requirements/1.cc b/libstdc++-v3/testsuite/20_util/weak_ptr/requirements/1.cc deleted file mode 100644 index 04ea837..0000000 --- a/libstdc++-v3/testsuite/20_util/weak_ptr/requirements/1.cc +++ /dev/null @@ -1,33 +0,0 @@ -// { dg-do compile { target c++11 } } -// { dg-require-effective-target hosted } - -#include <memory> -#include <testsuite_tr1.h> - -using namespace __gnu_test; - -void -test01() -{ - std::weak_ptr<ClassType> ptr; - std::weak_ptr<const ClassType> ptr2 = ptr; - -#if __cpp_lib_shared_ptr_arrays >= 201611L - std::weak_ptr<ClassType[10]> ptr_array; - std::weak_ptr<ClassType[]> ptr_array2 = ptr_array; - std::weak_ptr<ClassType const []> ptr_array3 = ptr_array; -#endif -} - -void -test02() -{ - std::weak_ptr<IncompleteClass> ptr; - std::weak_ptr<const IncompleteClass> ptr2 = ptr; - -#if __cpp_lib_shared_ptr_arrays >= 201611L - std::weak_ptr<IncompleteClass[10]> ptr_array; - std::weak_ptr<IncompleteClass[]> ptr_array2 = ptr_array; - std::weak_ptr<IncompleteClass const []> ptr_array3 = ptr_array; -#endif -} diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/allocator/char/operator_plus.cc b/libstdc++-v3/testsuite/21_strings/basic_string/allocator/char/operator_plus.cc index 571f853..92e0569 100644 --- a/libstdc++-v3/testsuite/21_strings/basic_string/allocator/char/operator_plus.cc +++ b/libstdc++-v3/testsuite/21_strings/basic_string/allocator/char/operator_plus.cc @@ -17,8 +17,6 @@ // <http://www.gnu.org/licenses/>. // { dg-do run { target c++11 } } -// COW strings don't support C++11 allocator propagation: -// { dg-require-effective-target cxx11_abi } #include <string> #include <testsuite_hooks.h> diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/allocator/wchar_t/operator_plus.cc b/libstdc++-v3/testsuite/21_strings/basic_string/allocator/wchar_t/operator_plus.cc index 0da6843..b75b26a 100644 --- a/libstdc++-v3/testsuite/21_strings/basic_string/allocator/wchar_t/operator_plus.cc +++ b/libstdc++-v3/testsuite/21_strings/basic_string/allocator/wchar_t/operator_plus.cc @@ -17,8 +17,6 @@ // <http://www.gnu.org/licenses/>. // { dg-do run { target c++11 } } -// COW strings don't support C++11 allocator propagation: -// { dg-require-effective-target cxx11_abi } #include <string> #include <testsuite_hooks.h> diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/cons/char/119748.cc b/libstdc++-v3/testsuite/21_strings/basic_string/cons/char/119748.cc new file mode 100644 index 0000000..301ca5d --- /dev/null +++ b/libstdc++-v3/testsuite/21_strings/basic_string/cons/char/119748.cc @@ -0,0 +1,35 @@ +// { dg-do compile } + +// Bug 119748 +// string(InputIterator, InputIterator) rejects volatile charT* as iterator + +#ifndef TEST_CHAR_TYPE +#define TEST_CHAR_TYPE char +#endif + +#include <string> +#include <testsuite_iterators.h> + +typedef TEST_CHAR_TYPE C; + +volatile C vs[42] = {}; +std::basic_string<C> s(vs+0, vs+42); +#ifdef __cpp_lib_containers_ranges +std::basic_string<C> s2(std::from_range, vs); +#endif + +using namespace __gnu_test; + +test_container<volatile C, input_iterator_wrapper> input_cont(vs); +std::basic_string<C> s3(input_cont.begin(), input_cont.end()); + +test_container<volatile C, forward_iterator_wrapper> fwd_cont(vs); +std::basic_string<C> s4(fwd_cont.begin(), fwd_cont.end()); + +#ifdef __cpp_lib_containers_ranges +test_input_range<volatile C> input_range(vs); +std::basic_string<C> s5(std::from_range, input_range); + +test_forward_range<volatile C> fwd_range(vs); +std::basic_string<C> s6(std::from_range, fwd_range); +#endif diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/cons/from_range.cc b/libstdc++-v3/testsuite/21_strings/basic_string/cons/from_range.cc new file mode 100644 index 0000000..6331050 --- /dev/null +++ b/libstdc++-v3/testsuite/21_strings/basic_string/cons/from_range.cc @@ -0,0 +1,129 @@ +// { dg-do run { target c++23 } } + +#include <string> + +#if __cpp_lib_containers_ranges != 202202L +# error "Feature-test macro __cpp_lib_containers_ranges has wrong value in <string>" +#endif + +#include <span> +#include <testsuite_hooks.h> +#include <testsuite_iterators.h> +#include <testsuite_allocator.h> + +void +test_deduction_guide(char* p) +{ + __gnu_test::test_input_range<char> r(nullptr, nullptr); + std::basic_string v(std::from_range, r); + static_assert(std::is_same_v<decltype(v), std::string>); + + using Alloc = __gnu_test::SimpleAllocator<char>; + Alloc alloc; + std::basic_string v2(std::from_range, r, alloc); + static_assert(std::is_same_v<decltype(v2), std::basic_string<char, std::char_traits<char>, Alloc>>); + + __gnu_test::test_input_range<wchar_t> wr(nullptr, nullptr); + std::basic_string w(std::from_range, wr); + static_assert(std::is_same_v<decltype(w), std::wstring>); + + using WAlloc = __gnu_test::SimpleAllocator<wchar_t>; + WAlloc walloc; + std::basic_string w2(std::from_range, wr, walloc); + static_assert(std::is_same_v<decltype(w2), std::basic_string<wchar_t, std::char_traits<wchar_t>, WAlloc>>); +} + +template<typename Range, typename Alloc> +constexpr void +do_test(Alloc alloc) +{ + // The basic_string's value_type. + using V = typename std::allocator_traits<Alloc>::value_type; + using CT = std::char_traits<V>; + + // The range's value_type. + using T = std::ranges::range_value_t<Range>; + T a[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}; + + auto eq = [](const std::basic_string<V, CT, Alloc>& l, std::span<T> r) { + if (l.size() != r.size()) + return false; + for (auto i = 0u; i < l.size(); ++i) + if (l[i] != r[i]) + return false; + return true; + }; + + std::basic_string<V, CT, Alloc> v0(std::from_range, Range(a, a+0)); + VERIFY( v0.empty() ); + VERIFY( v0.get_allocator() == Alloc() ); + + std::basic_string<V, CT, Alloc> v4(std::from_range, Range(a, a+4)); + VERIFY( eq(v4, {a, 4}) ); + VERIFY( v4.get_allocator() == Alloc() ); + + std::basic_string<V, CT, Alloc> v9(std::from_range, Range(a, a+9), alloc); + VERIFY( eq(v9, {a, 9}) ); + VERIFY( v9.get_allocator() == alloc ); + + std::basic_string<V, CT, Alloc> v20(std::from_range, Range(a, a+20), alloc); + VERIFY( eq(v20, {a, 20}) ); + VERIFY( v20.get_allocator() == alloc ); +} + +template<typename Range> +void +do_test_a() +{ + do_test<Range>(std::allocator<char>()); + do_test<Range>(__gnu_test::uneq_allocator<char>(42)); + do_test<Range>(std::allocator<wchar_t>()); + do_test<Range>(__gnu_test::uneq_allocator<wchar_t>(42)); +} + +bool +test_ranges() +{ + using namespace __gnu_test; + + do_test_a<test_forward_range<char>>(); + do_test_a<test_forward_sized_range<char>>(); + do_test_a<test_sized_range_sized_sent<char, forward_iterator_wrapper>>(); + + do_test_a<test_input_range<char>>(); + do_test_a<test_input_sized_range<char>>(); + do_test_a<test_sized_range_sized_sent<char, input_iterator_wrapper>>(); + + do_test_a<test_range<char, input_iterator_wrapper_nocopy>>(); + do_test_a<test_sized_range<char, input_iterator_wrapper_nocopy>>(); + do_test_a<test_sized_range_sized_sent<char, input_iterator_wrapper_nocopy>>(); + + // Not lvalue-convertible to char + struct C { + C(char v) : val(v) { } + operator char() && { return val; } + bool operator==(char b) const { return b == val; } + char val; + }; + using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>; + do_test<rvalue_input_range>(std::allocator<char>()); + + return true; +} + +constexpr bool +test_constexpr() +{ +#if _GLIBCXX_USE_CXX11_ABI + // XXX: this doesn't test the non-forward_range code paths are constexpr. + do_test<std::string_view>(std::allocator<char>()); +#endif // _GLIBCXX_USE_CXX11_ABI + return true; +} + +int main() +{ + test_ranges(); + static_assert( test_constexpr() ); +} diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/cons/wchar_t/119748.cc b/libstdc++-v3/testsuite/21_strings/basic_string/cons/wchar_t/119748.cc new file mode 100644 index 0000000..7d3ba10 --- /dev/null +++ b/libstdc++-v3/testsuite/21_strings/basic_string/cons/wchar_t/119748.cc @@ -0,0 +1,7 @@ +// { dg-do compile } + +// Bug 119748 +// string(InputIterator, InputIterator) rejects volatile charT* as iterator + +#define TEST_CHAR_TYPE wchar_t +#include "../char/119748.cc" diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/append/append_range.cc b/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/append/append_range.cc new file mode 100644 index 0000000..6c0bc0c --- /dev/null +++ b/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/append/append_range.cc @@ -0,0 +1,125 @@ +// { dg-do run { target c++23 } } + +#include <span> +#include <string> +#include <testsuite_allocator.h> +#include <testsuite_hooks.h> +#include <testsuite_iterators.h> + +template<typename Range, typename Alloc> +constexpr void +do_test() +{ + // The vector's value_type. + using V = typename std::allocator_traits<Alloc>::value_type; + using CT = std::char_traits<V>; + + // The range's value_type. + using T = std::ranges::range_value_t<Range>; + T a[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}; + + auto eq = [](const std::basic_string<V, CT, Alloc>& l, std::span<T> r) { + if (l.size() != r.size()) + return false; + for (auto i = 0u; i < l.size(); ++i) + if (l[i] != r[i]) + return false; + return true; + }; + + Range r4(a, a+4); + Range r5(a+4, a+9); + Range r11(a+9, a+20); + + std::basic_string<V, CT, Alloc> v; + v.append_range(r4); + VERIFY( eq(v, {a, 4}) ); + v.append_range(r5); + VERIFY( eq(v, {a, 9}) ); + + std::basic_string<V, CT, Alloc> const s = v; + v.append_range(r11); + VERIFY( eq(v, a) ); + v.append_range(Range(a, a)); + VERIFY( eq(v, a) ); + v.clear(); + v.append_range(Range(a, a)); + VERIFY( v.empty() ); +} + +template<typename Range> +void +do_test_a() +{ + do_test<Range, std::allocator<char>>(); + do_test<Range, __gnu_test::SimpleAllocator<char>>(); + do_test<Range, std::allocator<wchar_t>>(); + do_test<Range, __gnu_test::SimpleAllocator<wchar_t>>(); +} + +bool +test_ranges() +{ + using namespace __gnu_test; + + do_test_a<test_forward_range<char>>(); + do_test_a<test_forward_sized_range<char>>(); + do_test_a<test_sized_range_sized_sent<char, forward_iterator_wrapper>>(); + + do_test_a<test_input_range<char>>(); + do_test_a<test_input_sized_range<char>>(); + do_test_a<test_sized_range_sized_sent<char, input_iterator_wrapper>>(); + + do_test_a<test_range<char, input_iterator_wrapper_nocopy>>(); + do_test_a<test_sized_range<char, input_iterator_wrapper_nocopy>>(); + do_test_a<test_sized_range_sized_sent<char, input_iterator_wrapper_nocopy>>(); + + // Not lvalue-convertible to char + struct C { + C(char v) : val(v) { } + operator char() && { return val; } + bool operator==(char b) const { return b == val; } + char val; + }; + using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>; + do_test<rvalue_input_range, std::allocator<char>>(); + + return true; +} + +void +test_overlapping() +{ + std::string const s = "1234abcd"; + + std::string c = s; + c.append_range(std::string_view(c)); + VERIFY( c == "1234abcd1234abcd" ); + + c = s; + c.append_range(std::string_view(c).substr(4, 4)); + VERIFY( c == "1234abcdabcd" ); + + c = s; + c.reserve(12); + c.append_range(std::string_view(c).substr(0, 4)); + VERIFY( c == "1234abcd1234" ); +} + +constexpr bool +test_constexpr() +{ +#if _GLIBCXX_USE_CXX11_ABI + // XXX: this doesn't test the non-forward_range code paths are constexpr. + do_test<std::string_view, std::allocator<char>>(); +#endif // _GLIBCXX_USE_CXX11_ABI + return true; +} + +int main() +{ + test_ranges(); + test_overlapping(); + static_assert( test_constexpr() ); +} diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/assign/assign_range.cc b/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/assign/assign_range.cc new file mode 100644 index 0000000..310c8bc --- /dev/null +++ b/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/assign/assign_range.cc @@ -0,0 +1,116 @@ +// { dg-do run { target c++23 } } + +#include <vector> +#include <span> +#include <testsuite_hooks.h> +#include <testsuite_iterators.h> +#include <testsuite_allocator.h> + +template<typename Range, typename Alloc> +constexpr void +do_test() +{ + // The vector's value_type. + using V = typename std::allocator_traits<Alloc>::value_type; + using CT = std::char_traits<V>; + + // The range's value_type. + using T = std::ranges::range_value_t<Range>; + T a[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}; + + auto eq = [](const std::basic_string<V, CT, Alloc>& l, std::span<T> r) { + if (l.size() != r.size()) + return false; + for (auto i = 0u; i < l.size(); ++i) + if (l[i] != r[i]) + return false; + return true; + }; + + std::basic_string<V, CT, Alloc> v; + v.assign_range(Range(a, a)); + VERIFY( v.empty() ); + v.assign_range(Range(a, a+4)); + VERIFY( eq(v, {a, 4}) ); + v.assign_range(Range(a, a+9)); + VERIFY( eq(v, {a, 9}) ); + std::basic_string<V, CT, Alloc> const s = v; + v.assign_range(Range(a, a+20)); + VERIFY( eq(v, {a, 20}) ); +} + +template<typename Range> +void +do_test_a() +{ + do_test<Range, std::allocator<char>>(); + do_test<Range, __gnu_test::SimpleAllocator<char>>(); + do_test<Range, std::allocator<wchar_t>>(); + do_test<Range, __gnu_test::SimpleAllocator<wchar_t>>(); +} + +bool +test_ranges() +{ + using namespace __gnu_test; + + do_test_a<test_forward_range<char>>(); + do_test_a<test_forward_sized_range<char>>(); + do_test_a<test_sized_range_sized_sent<char, forward_iterator_wrapper>>(); + + do_test_a<test_input_range<char>>(); + do_test_a<test_input_sized_range<char>>(); + do_test_a<test_sized_range_sized_sent<char, input_iterator_wrapper>>(); + + do_test_a<test_range<char, input_iterator_wrapper_nocopy>>(); + do_test_a<test_sized_range<char, input_iterator_wrapper_nocopy>>(); + do_test_a<test_sized_range_sized_sent<char, input_iterator_wrapper_nocopy>>(); + + // Not lvalue-convertible to char + struct C { + C(char v) : val(v) { } + operator char() && { return val; } + bool operator==(char b) const { return b == val; } + char val; + }; + using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>; + do_test<rvalue_input_range, std::allocator<char>>(); + + return true; +} + +void +test_overlapping() +{ + std::string const s = "1234abcd"; + + std::string c = s; + c.assign_range(std::string_view(c)); + VERIFY( c == "1234abcd" ); + + c = s; + c.assign_range(std::string_view(c).substr(4, 4)); + VERIFY( c == "abcd" ); + + c = s; + c.assign_range(std::string_view(c).substr(0, 4)); + VERIFY( c == "1234" ); +} + +constexpr bool +test_constexpr() +{ +#if _GLIBCXX_USE_CXX11_ABI + // XXX: this doesn't test the non-forward_range code paths are constexpr. + do_test<std::string_view, std::allocator<char>>(); +#endif // _GLIBCXX_USE_CXX11_ABI + return true; +} + +int main() +{ + test_ranges(); + test_overlapping(); + static_assert( test_constexpr() ); +} diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/insert/insert_range.cc b/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/insert/insert_range.cc new file mode 100644 index 0000000..4fead32 --- /dev/null +++ b/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/insert/insert_range.cc @@ -0,0 +1,130 @@ +// { dg-do run { target c++23 } } + +#include <span> +#include <string> +#include <testsuite_allocator.h> +#include <testsuite_hooks.h> +#include <testsuite_iterators.h> + +template<typename Range, typename Alloc> +constexpr void +do_test() +{ + // The vector's value_type. + using V = typename std::allocator_traits<Alloc>::value_type; + using CT = std::char_traits<V>; + + // The range's value_type. + using T = std::ranges::range_value_t<Range>; + T a[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}; + + auto eq = [](const std::basic_string<V, CT, Alloc>& l, std::span<T> r) { + if (l.size() != r.size()) + return false; + for (auto i = 0u; i < l.size(); ++i) + if (l[i] != r[i]) + return false; + return true; + }; + + std::basic_string<V, CT, Alloc> v; + auto it = v.insert_range(v.end(), Range(a, a)); + VERIFY( v.empty() ); + VERIFY( it == v.begin() ); + it = v.insert_range(v.end(), Range(a, a+4)); + VERIFY( eq(v, {a, 4}) ); + VERIFY( it == v.begin() ); + it = v.insert_range(v.end(), Range(a+4, a+9)); + VERIFY( eq(v, {a, 9}) ); + VERIFY( it == v.begin()+4 ); + + std::basic_string<V, CT, Alloc> s = v; + it = v.insert_range(v.end(), Range(a+9, a+20)); + VERIFY( eq(v, {a, 20}) ); + VERIFY( it == v.begin()+9 ); + + v = std::basic_string<V, CT, Alloc>(); + it = v.insert_range(v.begin(), Range(a, a+5)); + VERIFY( it == v.begin() ); + s = v; + it = v.insert_range(v.begin() + 5, Range(a+5, a+20)); + VERIFY( eq(v, {a, 20}) ); + VERIFY( it == v.begin()+5 ); +} + +template<typename Range> +void +do_test_a() +{ + do_test<Range, std::allocator<char>>(); + do_test<Range, __gnu_test::SimpleAllocator<char>>(); + do_test<Range, std::allocator<wchar_t>>(); + do_test<Range, __gnu_test::SimpleAllocator<wchar_t>>(); +} + +bool +test_ranges() +{ + using namespace __gnu_test; + + do_test_a<test_forward_range<char>>(); + do_test_a<test_forward_sized_range<char>>(); + do_test_a<test_sized_range_sized_sent<char, forward_iterator_wrapper>>(); + + do_test_a<test_input_range<char>>(); + do_test_a<test_input_sized_range<char>>(); + do_test_a<test_sized_range_sized_sent<char, input_iterator_wrapper>>(); + + do_test_a<test_range<char, input_iterator_wrapper_nocopy>>(); + do_test_a<test_sized_range<char, input_iterator_wrapper_nocopy>>(); + do_test_a<test_sized_range_sized_sent<char, input_iterator_wrapper_nocopy>>(); + + // Not lvalue-convertible to char + struct C { + C(char v) : val(v) { } + operator char() && { return val; } + bool operator==(char b) const { return b == val; } + char val; + }; + using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>; + do_test<rvalue_input_range, std::allocator<char>>(); + + return true; +} + +void +test_overlapping() +{ + std::string const s = "1234abcd"; + + std::string c = s; + c.insert_range(c.end(), std::string_view(c)); + VERIFY( c == "1234abcd1234abcd" ); + + c = s; + c.insert_range(c.begin()+4, std::string_view(c).substr(4, 4)); + VERIFY( c == "1234abcdabcd" ); + + c = s; + c.reserve(12); + c.insert_range(c.begin()+2, std::string_view(c).substr(0, 4)); + VERIFY( c == "12123434abcd" ); +} + +constexpr bool +test_constexpr() +{ +#if _GLIBCXX_USE_CXX11_ABI + // XXX: this doesn't test the non-forward_range code paths are constexpr. + do_test<std::string_view, std::allocator<char>>(); +#endif // _GLIBCXX_USE_CXX11_ABI + return true; +} + +int main() +{ + test_ranges(); + test_overlapping(); + static_assert( test_constexpr() ); +} diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/replace/replace_with_range.cc b/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/replace/replace_with_range.cc new file mode 100644 index 0000000..9acf11a --- /dev/null +++ b/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/replace/replace_with_range.cc @@ -0,0 +1,133 @@ +// { dg-do run { target c++23 } } + +#include <span> +#include <string> +#include <testsuite_allocator.h> +#include <testsuite_hooks.h> +#include <testsuite_iterators.h> + +template<typename Range, typename Alloc> +constexpr void +do_test() +{ + // The vector's value_type. + using V = typename std::allocator_traits<Alloc>::value_type; + using CT = std::char_traits<V>; + + // The range's value_type. + using T = std::ranges::range_value_t<Range>; + T a[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}; + + auto eq = [](const std::basic_string<V, CT, Alloc>& l, std::span<T> r) { + if (l.size() != r.size()) + return false; + for (auto i = 0u; i < l.size(); ++i) + if (l[i] != r[i]) + return false; + return true; + }; + + std::basic_string<V, CT, Alloc> v; + v.replace_with_range(v.end(), v.end(), Range(a, a)); + VERIFY( v.empty() ); + v.replace_with_range(v.end(), v.end(), Range(a, a+4)); + VERIFY( eq(v, {a, 4}) ); + v.replace_with_range(v.end(), v.end(), Range(a+4, a+9)); + VERIFY( eq(v, {a, 9}) ); + std::basic_string<V, CT, Alloc> s = v; + v.replace_with_range(v.end(), v.end(), Range(a+9, a+20)); + VERIFY( eq(v, {a, 20}) ); + + v.replace_with_range(v.begin()+10, v.begin()+20, Range(a+5, a+10)); + VERIFY( v.size() == 15 ); + v.replace_with_range(v.begin(), v.begin()+10, Range(a, a+5)); + VERIFY( eq(v, {a, 10}) ); + + s = v; + v.replace_with_range(v.begin(), v.begin()+4, Range(a, a+8)); + VERIFY( v.size() == 14 ); + v.replace_with_range(v.begin()+8, v.begin()+12, Range(a+8, a+16)); + VERIFY( v.size() == 18 ); + v.replace_with_range(v.begin()+16, v.begin()+18, Range(a+16, a+20)); + VERIFY( eq(v, {a, 20}) ); +} + +template<typename Range> +void +do_test_a() +{ + do_test<Range, std::allocator<char>>(); + do_test<Range, __gnu_test::SimpleAllocator<char>>(); + do_test<Range, std::allocator<wchar_t>>(); + do_test<Range, __gnu_test::SimpleAllocator<wchar_t>>(); +} + +bool +test_ranges() +{ + using namespace __gnu_test; + + do_test_a<test_forward_range<char>>(); + do_test_a<test_forward_sized_range<char>>(); + do_test_a<test_sized_range_sized_sent<char, forward_iterator_wrapper>>(); + + do_test_a<test_input_range<char>>(); + do_test_a<test_input_sized_range<char>>(); + do_test_a<test_sized_range_sized_sent<char, input_iterator_wrapper>>(); + + do_test_a<test_range<char, input_iterator_wrapper_nocopy>>(); + do_test_a<test_sized_range<char, input_iterator_wrapper_nocopy>>(); + do_test_a<test_sized_range_sized_sent<char, input_iterator_wrapper_nocopy>>(); + + // Not lvalue-convertible to char + struct C { + C(char v) : val(v) { } + operator char() && { return val; } + bool operator==(char b) const { return b == val; } + char val; + }; + using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>; + do_test<rvalue_input_range, std::allocator<char>>(); + + return true; +} + +void +test_overlapping() +{ + std::string const s = "1234abcd"; + + std::string c = s; + c.replace_with_range(c.end(), c.end(), std::string_view(c)); + VERIFY( c == "1234abcd1234abcd" ); + + c = s; + c.replace_with_range(c.begin(), c.begin()+4, std::string_view(c).substr(4, 4)); + VERIFY( c == "abcdabcd" ); + + c = s; + c.replace_with_range(c.begin()+2, c.begin()+4, std::string_view(c).substr(0, 4)); + VERIFY( c == "121234abcd" ); + + c = s; + c.replace_with_range(c.begin()+2, c.begin()+2, std::string_view(c).substr(0, 4)); + VERIFY( c == "12123434abcd" ); +} + +constexpr bool +test_constexpr() +{ +#if _GLIBCXX_USE_CXX11_ABI + // XXX: this doesn't test the non-forward_range code paths are constexpr. + do_test<std::string_view, std::allocator<char>>(); +#endif // _GLIBCXX_USE_CXX11_ABI + return true; +} + +int main() +{ + test_ranges(); + test_overlapping(); + static_assert( test_constexpr() ); +} diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/stold.cc b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/stold.cc index b64ad0c..dd777c4 100644 --- a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/stold.cc +++ b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/stold.cc @@ -31,6 +31,11 @@ void test01() { + /* If these conditions are not met, basic_string.h doesn't define + std::stold(const string&, size_t* = 0), and then the test would + fail to compile. */ +#if (_GLIBCXX_HAVE_STRTOLD && ! _GLIBCXX_HAVE_BROKEN_STRTOLD) \ + || __DBL_MANT_DIG__ == __LDBL_MANT_DIG__ bool test = false; using namespace std; @@ -106,6 +111,7 @@ test01() test = false; } VERIFY( test ); +#endif } int main() diff --git a/libstdc++-v3/testsuite/22_locale/ctype/is/string/89728_neg.cc b/libstdc++-v3/testsuite/22_locale/ctype/is/string/89728_neg.cc index a34b2ae..24aba99 100644 --- a/libstdc++-v3/testsuite/22_locale/ctype/is/string/89728_neg.cc +++ b/libstdc++-v3/testsuite/22_locale/ctype/is/string/89728_neg.cc @@ -18,7 +18,6 @@ // <http://www.gnu.org/licenses/>. // { dg-error "invalid use of incomplete type" "" { target *-*-* } 0 } -// { dg-error "invalid 'static_cast'" "" { target c++98_only } 0 } #include <locale> diff --git a/libstdc++-v3/testsuite/22_locale/num_put/put/char/lwg4084.cc b/libstdc++-v3/testsuite/22_locale/num_put/put/char/lwg4084.cc index b7c7da1..6ce4e8f 100644 --- a/libstdc++-v3/testsuite/22_locale/num_put/put/char/lwg4084.cc +++ b/libstdc++-v3/testsuite/22_locale/num_put/put/char/lwg4084.cc @@ -20,7 +20,11 @@ test_nan() out << ' ' << nan << ' ' << -nan; out << std::showpos; out << ' ' << nan << ' ' << -nan; +#ifdef _AIX // non-conforming + VERIFY( out.str() == " NaNQ -NaNQ NaNQ -NaNQ NaNQ -NaNQ +NaNQ -NaNQ" ); +#else VERIFY( out.str() == " nan -nan NAN -NAN NAN -NAN +NAN -NAN" ); +#endif } void @@ -36,7 +40,11 @@ test_inf() out << ' ' << inf << ' ' << -inf; out << std::showpos; out << ' ' << inf << ' ' << -inf; +#ifdef _AIX // non-conforming + VERIFY( out.str() == " INF -INF INF -INF INF -INF +INF -INF" ); +#else VERIFY( out.str() == " inf -inf INF -INF INF -INF +INF -INF" ); +#endif } int main() diff --git a/libstdc++-v3/testsuite/23_containers/deque/capacity/shrink_to_fit.cc b/libstdc++-v3/testsuite/23_containers/deque/capacity/shrink_to_fit.cc index 7cb6707..6371755 100644 --- a/libstdc++-v3/testsuite/23_containers/deque/capacity/shrink_to_fit.cc +++ b/libstdc++-v3/testsuite/23_containers/deque/capacity/shrink_to_fit.cc @@ -1,4 +1,5 @@ // { dg-do run { target c++11 } } +// { dg-require-effective-target std_allocator_new } // 2010-01-08 Paolo Carlini <paolo.carlini@oracle.com> @@ -19,18 +20,42 @@ // with this library; see the file COPYING3. If not see // <http://www.gnu.org/licenses/>. -#include <vector> +#include <deque> #include <testsuite_hooks.h> +#include <replacement_memory_operators.h> // libstdc++/42573 void test01() { - std::vector<int> d(100); - d.push_back(1); - d.push_back(1); - // VERIFY( d.size() < d.capacity() ); + using namespace std; + __gnu_test::counter::reset(); + + const size_t buf_size = _GLIBCXX_STD_C::__deque_buf_size(sizeof(size_t)); + deque<size_t> d; + for (size_t i = 0; i != buf_size; ++i) + d.push_back(i); + + // No shrink if 1st buffer is full, create some front capacity. + d.pop_front(); + + // 1 node array allocation + 2 node allocation = 3. + VERIFY( __gnu_test::counter::count() == 3 ); + VERIFY( __gnu_test::counter::get()._M_increments == 3 ); + d.shrink_to_fit(); - // VERIFY( d.size() == d.capacity() ); + + // No reallocation if no exception support, shrink_to_fit is then a + // no-op. +#if __cpp_exceptions + // 1 node array allocation + 1 node allocation = 2. + const int expected_count = 2; + const int expected_increments = 2; +#else + const int expected_count = 3; + const int expected_increments = 0; +#endif + VERIFY( __gnu_test::counter::count() == expected_count ); + VERIFY( __gnu_test::counter::get()._M_increments == 3 + expected_increments ); } int main() diff --git a/libstdc++-v3/testsuite/23_containers/deque/cons/from_range.cc b/libstdc++-v3/testsuite/23_containers/deque/cons/from_range.cc index 96e994d..48fd196 100644 --- a/libstdc++-v3/testsuite/23_containers/deque/cons/from_range.cc +++ b/libstdc++-v3/testsuite/23_containers/deque/cons/from_range.cc @@ -1,6 +1,11 @@ // { dg-do run { target c++23 } } #include <deque> + +#if __cpp_lib_containers_ranges != 202202L +# error "Feature-test macro __cpp_lib_containers_ranges has wrong value in <deque>" +#endif + #include <span> #include <testsuite_hooks.h> #include <testsuite_iterators.h> diff --git a/libstdc++-v3/testsuite/23_containers/flat_map/1.cc b/libstdc++-v3/testsuite/23_containers/flat_map/1.cc index d9d88c4..01278d7 100644 --- a/libstdc++-v3/testsuite/23_containers/flat_map/1.cc +++ b/libstdc++-v3/testsuite/23_containers/flat_map/1.cc @@ -1,4 +1,5 @@ // { dg-do run { target c++23 } } +// { dg-timeout-factor 2 } #include <flat_map> @@ -55,16 +56,17 @@ test_deduction_guide() std::vector<long, __gnu_test::SimpleAllocator<long>>, std::vector<float, __gnu_test::SimpleAllocator<float>>>>); - // LWG4223: deduces flat_map<long, float const>, which in turn instantiates - // std::vector<cosnt float> that is ill-formed. - // __gnu_test::test_input_range<std::pair<const long, const float>> r2(0, 0); - // std::flat_map it5(r2.begin(), r2.begin()); - // std::flat_map fr5(std::from_range, r2); + __gnu_test::test_input_range<std::pair<const long, const float>> r2(0, 0); + std::flat_map it5(r2.begin(), r2.begin()); + static_assert(std::is_same_v<decltype(it5), std::flat_map<long, float>>); + std::flat_map fr5(std::from_range, r2); + static_assert(std::is_same_v<decltype(fr5), std::flat_map<long, float>>); - // LWG4223: deduces flat_map<const long&, float&> - //__gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, 0); - // std::flat_map it6(r3.begin(), r3.begin()); - // std::flat_map fr6(std::from_range, r3); + __gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, 0); + std::flat_map it6(r3.begin(), r3.begin()); + static_assert(std::is_same_v<decltype(it6), std::flat_map<long, float>>); + std::flat_map fr6(std::from_range, r3); + static_assert(std::is_same_v<decltype(fr6), std::flat_map<long, float>>); __gnu_test::test_input_range<std::tuple<long, float>> r4(0, 0); std::flat_map it7(r4.begin(), r4.begin()); @@ -241,6 +243,26 @@ test06() VERIFY( std::ranges::equal(m | std::views::values, (int[]){2, 3, 4, 5, 6}) ); } +void +test07() +{ + // PR libstdc++/119427 - std::erase_if(std::flat_foo) does not work + // PR libstdc++/120465 - erase_if for flat_map calls predicate with incorrect type + std::flat_map<int, int> m = {std::pair{1, 2}, {3, 4}, {5, 6}}; + auto n = std::erase_if(m, [](auto x) { return x.first == 1 || x.second == 6; }); + VERIFY( n == 2 ); + VERIFY( std::ranges::equal(m, (std::pair<int,int>[]){{3,4}}) ); +} + +void +test08() +{ + // PR libstdc++/120432 - flat_map operator[] is broken for const lvalue keys + std::flat_map<int, int> m; + const int k = 42; + m[k] = 0; +} + int main() { @@ -253,4 +275,6 @@ main() test04(); test05(); test06(); + test07(); + test08(); } diff --git a/libstdc++-v3/testsuite/23_containers/flat_multimap/1.cc b/libstdc++-v3/testsuite/23_containers/flat_multimap/1.cc index ff180bf..d746614 100644 --- a/libstdc++-v3/testsuite/23_containers/flat_multimap/1.cc +++ b/libstdc++-v3/testsuite/23_containers/flat_multimap/1.cc @@ -1,4 +1,5 @@ // { dg-do run { target c++23 } } +// { dg-timeout-factor 2 } #include <flat_map> #include <deque> @@ -53,16 +54,17 @@ test_deduction_guide() std::vector<long, __gnu_test::SimpleAllocator<long>>, std::vector<float, __gnu_test::SimpleAllocator<float>>>>); - // LWG4223: deduces flat_multimap<long, float const>, which in turn instantiates - // std::vector<cosnt float> that is ill-formed. - // __gnu_test::test_input_range<std::pair<const long, const float>> r2(0, 0); - // std::flat_multimap it5(r2.begin(), r2.begin()); - // std::flat_multimap fr5(std::from_range, r2); + __gnu_test::test_input_range<std::pair<const long, const float>> r2(0, 0); + std::flat_multimap it5(r2.begin(), r2.begin()); + static_assert(std::is_same_v<decltype(it5), std::flat_multimap<long, float>>); + std::flat_multimap fr5(std::from_range, r2); + static_assert(std::is_same_v<decltype(fr5), std::flat_multimap<long, float>>); - // LWG4223: deduces flat_multimap<const long&, float&> - //__gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, 0); - // std::flat_multimap it6(r3.begin(), r3.begin()); - // std::flat_multimap fr6(std::from_range, r3); + __gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, 0); + std::flat_multimap it6(r3.begin(), r3.begin()); + static_assert(std::is_same_v<decltype(it6), std::flat_multimap<long, float>>); + std::flat_multimap fr6(std::from_range, r3); + static_assert(std::is_same_v<decltype(fr6), std::flat_multimap<long, float>>); __gnu_test::test_input_range<std::tuple<long, float>> r4(0, 0); std::flat_multimap it7(r4.begin(), r4.begin()); @@ -219,6 +221,17 @@ test06() VERIFY( std::ranges::equal(m | std::views::values, (int[]){2, 3, 4, 5, 6}) ); } +void +test07() +{ + // PR libstdc++/119427 - std::erase_if(std::flat_foo) does not work + // PR libstdc++/120465 - erase_if for flat_map calls predicate with incorrect type + std::flat_multimap<int, int> m = {std::pair{1, 2}, {3, 4}, {3, 3}, {5, 6}, {6, 6}}; + auto n = std::erase_if(m, [](auto x) { return x.first == 1 || x.second == 6; }); + VERIFY( n == 3 ); + VERIFY( std::ranges::equal(m, (std::pair<int,int>[]){{3,4},{3,3}}) ); +} + int main() { @@ -231,4 +244,5 @@ main() test04(); test05(); test06(); + test07(); } diff --git a/libstdc++-v3/testsuite/23_containers/flat_multiset/1.cc b/libstdc++-v3/testsuite/23_containers/flat_multiset/1.cc index dc3cecd..63855e0 100644 --- a/libstdc++-v3/testsuite/23_containers/flat_multiset/1.cc +++ b/libstdc++-v3/testsuite/23_containers/flat_multiset/1.cc @@ -214,6 +214,37 @@ void test07() #endif } +void +test08() +{ + // PR libstdc++/119620 -- flat_set::emplace always constructs element on the stack + static int copy_counter; + struct A { + A() { } + A(const A&) { ++copy_counter; } + A& operator=(const A&) { ++copy_counter; return *this; } + auto operator<=>(const A&) const = default; + }; + std::vector<A> v; + v.reserve(2); + std::flat_multiset<A> s(std::move(v)); + A a; + s.emplace(a); + VERIFY( copy_counter == 1 ); + s.emplace(a); + VERIFY( copy_counter == 2 ); +} + +void +test09() +{ + // PR libstdc++/119427 - std::erase_if(std::flat_foo) does not work + std::flat_multiset<int> s = {1,1,2,2,3,4,5}; + auto n = std::erase_if(s, [](int x) { return x % 2 != 0; }); + VERIFY( n == 4 ); + VERIFY( std::ranges::equal(s, (int[]){2,2,4}) ); +} + int main() { @@ -225,4 +256,6 @@ main() test05(); test06(); test07(); + test08(); + test09(); } diff --git a/libstdc++-v3/testsuite/23_containers/flat_set/1.cc b/libstdc++-v3/testsuite/23_containers/flat_set/1.cc index 90f5855..b1d9002 100644 --- a/libstdc++-v3/testsuite/23_containers/flat_set/1.cc +++ b/libstdc++-v3/testsuite/23_containers/flat_set/1.cc @@ -229,6 +229,35 @@ void test07() #endif } +void +test08() +{ + // PR libstdc++/119620 -- flat_set::emplace always constructs element on the stack + static int copy_counter; + struct A { + A() { } + A(const A&) { ++copy_counter; } + A& operator=(const A&) { ++copy_counter; return *this; } + auto operator<=>(const A&) const = default; + }; + std::flat_set<A> s; + A a; + s.emplace(a); + VERIFY( copy_counter == 1 ); + s.emplace(a); + VERIFY( copy_counter == 1 ); +} + +void +test09() +{ + // PR libstdc++/119427 - std::erase_if(std::flat_foo) does not work + std::flat_set<int> s = {1,2,3,4,5}; + auto n = std::erase_if(s, [](int x) { return x % 2 != 0; }); + VERIFY( n == 3 ); + VERIFY( std::ranges::equal(s, (int[]){2,4}) ); +} + int main() { @@ -240,4 +269,6 @@ main() test05(); test06(); test07(); + test08(); + test09(); } diff --git a/libstdc++-v3/testsuite/23_containers/forward_list/48101_neg.cc b/libstdc++-v3/testsuite/23_containers/forward_list/48101_neg.cc index 2f2ea2a..d18195e 100644 --- a/libstdc++-v3/testsuite/23_containers/forward_list/48101_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/forward_list/48101_neg.cc @@ -26,6 +26,5 @@ test01() } // { dg-error "non-const, non-volatile value_type" "" { target *-*-* } 0 } -// { dg-prune-output "std::allocator<.* has no member named " } // { dg-prune-output "must have the same value_type as its allocator" } // { dg-prune-output "rebind_alloc" } diff --git a/libstdc++-v3/testsuite/23_containers/forward_list/cons/from_range.cc b/libstdc++-v3/testsuite/23_containers/forward_list/cons/from_range.cc index 65b378e..aa70105 100644 --- a/libstdc++-v3/testsuite/23_containers/forward_list/cons/from_range.cc +++ b/libstdc++-v3/testsuite/23_containers/forward_list/cons/from_range.cc @@ -1,11 +1,15 @@ // { dg-do run { target c++23 } } #include <forward_list> + +#if __cpp_lib_containers_ranges != 202202L +# error "Feature-test macro __cpp_lib_containers_ranges has wrong value in <forward_list>" +#endif + #include <span> #include <testsuite_hooks.h> #include <testsuite_iterators.h> #include <testsuite_allocator.h> - void test_deduction_guide(long* p) { diff --git a/libstdc++-v3/testsuite/23_containers/list/48101_neg.cc b/libstdc++-v3/testsuite/23_containers/list/48101_neg.cc index 8b2e075..cc51705 100644 --- a/libstdc++-v3/testsuite/23_containers/list/48101_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/list/48101_neg.cc @@ -26,5 +26,4 @@ test01() } // { dg-error "non-const, non-volatile value_type" "" { target *-*-* } 0 } -// { dg-prune-output "std::allocator<.* has no member named " } // { dg-prune-output "must have the same value_type as its allocator" } diff --git a/libstdc++-v3/testsuite/23_containers/list/cons/from_range.cc b/libstdc++-v3/testsuite/23_containers/list/cons/from_range.cc index 31448b9..107ad74 100644 --- a/libstdc++-v3/testsuite/23_containers/list/cons/from_range.cc +++ b/libstdc++-v3/testsuite/23_containers/list/cons/from_range.cc @@ -1,6 +1,11 @@ // { dg-do run { target c++23 } } #include <list> + +#if __cpp_lib_containers_ranges != 202202L +# error "Feature-test macro __cpp_lib_containers_ranges has wrong value in <list>" +#endif + #include <span> #include <testsuite_hooks.h> #include <testsuite_iterators.h> diff --git a/libstdc++-v3/testsuite/23_containers/map/48101_neg.cc b/libstdc++-v3/testsuite/23_containers/map/48101_neg.cc index 0661eeb..251beee 100644 --- a/libstdc++-v3/testsuite/23_containers/map/48101_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/map/48101_neg.cc @@ -28,8 +28,8 @@ test01() c2.find(2); // { dg-error "here" } } -// { dg-error "_Compare = std::(__8::)?less<int.>" "" { target *-*-* } 0 } -// { dg-error "_Compare = std::(__8::)?allocator<int>" "" { target *-*-* } 0 } +// { dg-error "_Compare = std::less<int.>" "" { target *-*-* } 0 } +// { dg-error "_Compare = std::allocator<int>" "" { target *-*-* } 0 } // { dg-error "comparison object must be invocable" "" { target *-*-* } 0 } // { dg-prune-output "no match for call" } // { dg-prune-output "invalid conversion" } diff --git a/libstdc++-v3/testsuite/23_containers/map/cons/deduction.cc b/libstdc++-v3/testsuite/23_containers/map/cons/deduction.cc index f8e6e6e..8645988 100644 --- a/libstdc++-v3/testsuite/23_containers/map/cons/deduction.cc +++ b/libstdc++-v3/testsuite/23_containers/map/cons/deduction.cc @@ -258,3 +258,49 @@ test_p1518r2() std::map s2(std::move(m), p); check_type<Map>(s2); } + +struct MyPred +{ + template<typename T, typename U> + bool operator()(T const&, U const&) const; +}; + +template<typename K, typename V> +constexpr bool test_lwg4223() +{ + using KD = std::remove_cv_t<std::remove_reference_t<K>>; + using VD = std::remove_cv_t<std::remove_reference_t<V>>; + using Alloc = __gnu_test::SimpleAllocator<std::pair<const KD, VD>>; + + std::initializer_list<std::pair<K, V>> il = {}; + Alloc a; + MyPred p; + + // The remove_cvref_t is not applied here. + // static_assert(std::is_same_v< + // decltype(std::map(il)), + // std::map<KD, VD>>); + + static_assert(std::is_same_v< + decltype(std::map(il.begin(), il.end())), + std::map<KD, VD>>); + + static_assert(std::is_same_v< + decltype(std::map(il.begin(), il.end(), p)), + std::map<KD, VD, MyPred>>); + + static_assert(std::is_same_v< + decltype(std::map(il.begin(), il.end(), a)), + std::map<KD, VD, std::less<KD>, Alloc>>); + + static_assert(std::is_same_v< + decltype(std::map(il.begin(), il.end(), p, a)), + std::map<KD, VD, MyPred, Alloc>>); + + return true; +} + +static_assert(test_lwg4223<const int, const float>()); +static_assert(test_lwg4223<int&, float&>()); +static_assert(test_lwg4223<int&&, float&&>()); +static_assert(test_lwg4223<const int&, const float&>()); diff --git a/libstdc++-v3/testsuite/23_containers/map/cons/from_range.cc b/libstdc++-v3/testsuite/23_containers/map/cons/from_range.cc index c740471..3a9fede 100644 --- a/libstdc++-v3/testsuite/23_containers/map/cons/from_range.cc +++ b/libstdc++-v3/testsuite/23_containers/map/cons/from_range.cc @@ -1,7 +1,12 @@ // { dg-do run { target c++23 } } -#include <algorithm> #include <map> + +#if __cpp_lib_containers_ranges != 202202L +# error "Feature-test macro __cpp_lib_containers_ranges has wrong value in <map>" +#endif + +#include <algorithm> #include <ranges> #include <span> #include <testsuite_allocator.h> @@ -38,11 +43,11 @@ test_deduction_guide() __gnu_test::test_input_range<std::pair<const long, const float>> r2(0, 0); std::map m5(std::from_range, r2); - static_assert(std::is_same_v<decltype(m5), std::map<long, const float>>); + static_assert(std::is_same_v<decltype(m5), std::map<long, float>>); - // LWG4223: deduces map<const long&, float&> - //__gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, 0); - // std::map m6(std::from_range, r3); + __gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, 0); + std::map m6(std::from_range, r3); + static_assert(std::is_same_v<decltype(m6), std::map<long, float>>); __gnu_test::test_input_range<std::tuple<long, float>> r4(0, 0); std::map m7(std::from_range, r4); diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/accessors/default.cc b/libstdc++-v3/testsuite/23_containers/mdspan/accessors/default.cc new file mode 100644 index 0000000..c036f8a --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/mdspan/accessors/default.cc @@ -0,0 +1,99 @@ +// { dg-do run { target c++23 } } +#include <mdspan> + +#include <testsuite_hooks.h> + +constexpr size_t dyn = std::dynamic_extent; + +template<typename Accessor> + constexpr void + test_accessor_policy() + { + static_assert(std::copyable<Accessor>); + static_assert(std::is_nothrow_move_constructible_v<Accessor>); + static_assert(std::is_nothrow_move_assignable_v<Accessor>); + static_assert(std::is_nothrow_swappable_v<Accessor>); + } + +constexpr bool +test_access() +{ + std::default_accessor<double> accessor; + std::array<double, 5> a{10, 11, 12, 13, 14}; + VERIFY(accessor.access(a.data(), 0) == 10); + VERIFY(accessor.access(a.data(), 4) == 14); + return true; +} + +constexpr bool +test_offset() +{ + std::default_accessor<double> accessor; + std::array<double, 5> a{10, 11, 12, 13, 14}; + VERIFY(accessor.offset(a.data(), 0) == a.data()); + VERIFY(accessor.offset(a.data(), 4) == a.data() + 4); + return true; +} + +class Base +{ }; + +class Derived : public Base +{ }; + +constexpr void +test_ctor() +{ + // T -> T + static_assert(std::is_nothrow_constructible_v<std::default_accessor<double>, + std::default_accessor<double>>); + static_assert(std::is_convertible_v<std::default_accessor<double>, + std::default_accessor<double>>); + + // T -> const T + static_assert(std::is_convertible_v<std::default_accessor<double>, + std::default_accessor<const double>>); + static_assert(std::is_convertible_v<std::default_accessor<Derived>, + std::default_accessor<const Derived>>); + + // const T -> T + static_assert(!std::is_constructible_v<std::default_accessor<double>, + std::default_accessor<const double>>); + static_assert(!std::is_constructible_v<std::default_accessor<Derived>, + std::default_accessor<const Derived>>); + + // T <-> volatile T + static_assert(std::is_convertible_v<std::default_accessor<int>, + std::default_accessor<volatile int>>); + static_assert(!std::is_constructible_v<std::default_accessor<int>, + std::default_accessor<volatile int>>); + + // size difference + static_assert(!std::is_constructible_v<std::default_accessor<char>, + std::default_accessor<int>>); + + // signedness + static_assert(!std::is_constructible_v<std::default_accessor<int>, + std::default_accessor<unsigned int>>); + static_assert(!std::is_constructible_v<std::default_accessor<unsigned int>, + std::default_accessor<int>>); + + // Derived <-> Base + static_assert(!std::is_constructible_v<std::default_accessor<Base>, + std::default_accessor<Derived>>); + static_assert(!std::is_constructible_v<std::default_accessor<Derived>, + std::default_accessor<Base>>); + +} + +int +main() +{ + test_accessor_policy<std::default_accessor<double>>(); + test_access(); + static_assert(test_access()); + test_offset(); + static_assert(test_offset()); + test_ctor(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/accessors/default_neg.cc b/libstdc++-v3/testsuite/23_containers/mdspan/accessors/default_neg.cc new file mode 100644 index 0000000..f8da2b5 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/mdspan/accessors/default_neg.cc @@ -0,0 +1,23 @@ +// { dg-do compile { target c++23 } } +#include<mdspan> + +std::default_accessor<int[3]> a; // { dg-error "required from here" } + +class AbstractBase +{ + virtual void + foo() const = 0; +}; + +class Derived : public AbstractBase +{ + void + foo() const override + { } +}; + +std::default_accessor<Derived> b_ok; +std::default_accessor<AbstractBase> b_err; // { dg-error "required from here"} + +// { dg-prune-output "ElementType must not be an array type" } +// { dg-prune-output "ElementType must not be an abstract" } 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 new file mode 100644 index 0000000..f9c1c01 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/class_mandates_neg.cc @@ -0,0 +1,12 @@ +// { dg-do compile { target c++23 } } +#include<mdspan> + +#include <cstdint> + +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" } diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy.cc b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy.cc new file mode 100644 index 0000000..a7b3a169 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy.cc @@ -0,0 +1,82 @@ +// { dg-do run { target c++23 } } +#include <mdspan> + +#include <testsuite_hooks.h> + +// Test the copy ctor and the ctor from other extents. + +constexpr auto dyn = std::dynamic_extent; + +// Not constructible +static_assert(!std::is_constructible_v<std::extents<int>, + std::extents<int, 1>>); + +static_assert(!std::is_constructible_v<std::extents<int, 1, 1>, + std::extents<int, 1>>); + +static_assert(!std::is_constructible_v<std::extents<int, dyn>, + std::extents<int, dyn, dyn>>); + +static_assert(!std::is_constructible_v<std::extents<int, 2, 2>, + std::extents<int, 1, 2>>); + +// Nothrow constructible +static_assert(std::is_nothrow_constructible_v<std::extents<int, 1>, + std::extents<unsigned int, dyn>>); +static_assert(std::is_nothrow_constructible_v<std::extents<unsigned int, dyn>, + std::extents<int, 1>>); + +// Implicit conversion +static_assert(!std::is_convertible_v<std::extents<unsigned int>, + std::extents<int>>); +static_assert(std::is_convertible_v<std::extents<int>, + std::extents<unsigned int>>); + +static_assert(!std::is_convertible_v<std::extents<unsigned int, 1>, + std::extents<int, 1>>); +static_assert(std::is_convertible_v<std::extents<int, 1>, + std::extents<unsigned int, 1>>); + +static_assert(!std::is_convertible_v<std::extents<int, dyn>, + std::extents<int, 1>>); +static_assert(std::is_convertible_v<std::extents<int, 1>, + std::extents<int, dyn>>); + +static_assert(!std::is_convertible_v<std::extents<unsigned int, 1>, + std::extents<int, dyn>>); +static_assert(std::is_convertible_v<std::extents<int, 1>, + std::extents<unsigned int, dyn>>); + +template<typename T, size_t... Extents, typename Other> + constexpr void + test_ctor(const Other& other) + { + auto e = std::extents<T, Extents...>(other); + VERIFY(e == other); + } + +constexpr int +test_all() +{ + auto e0 = std::extents<int>(); + test_ctor<int>(e0); + + auto e1 = std::extents<int, 1, 2, 3>(); + test_ctor<int, 1, 2, 3>(e1); + test_ctor<int, 1, dyn, 3>(e1); + test_ctor<unsigned int, 1, dyn, 3>(e1); + + auto e2 = std::extents<unsigned int, 1, dyn, 3>{1, 2, 3}; + test_ctor<int, 1, 2, 3>(e2); + test_ctor<int, 1, dyn, 3>(e2); + test_ctor<int, 1, dyn, dyn>(e2); + return true; +} + +int +main() +{ + test_all(); + static_assert(test_all()); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_default.cc b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_default.cc new file mode 100644 index 0000000..f45d3e5 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_default.cc @@ -0,0 +1,41 @@ +// { dg-do run { target c++23 } } +#include <mdspan> + +#include <cstdint> +#include <testsuite_hooks.h> + +constexpr auto dyn = std::dynamic_extent; + +template<typename Extents> + constexpr void + test_default_ctor() + { + Extents exts; + for(size_t i = 0; i < Extents::rank(); ++i) + if(exts.static_extent(i) == std::dynamic_extent) + VERIFY(exts.extent(i) == 0); + else + VERIFY(std::cmp_equal(exts.extent(i), Extents::static_extent(i))); + } + +constexpr bool +test_default_ctor_all() +{ + test_default_ctor<std::extents<int, 1>>(); + test_default_ctor<std::extents<int, dyn>>(); + test_default_ctor<std::extents<int, 1, 2>>(); + test_default_ctor<std::extents<int, dyn, 2>>(); + test_default_ctor<std::extents<int, dyn, dyn>>(); + test_default_ctor<std::extents<int, 1, 2, 3>>(); + test_default_ctor<std::extents<int, dyn, 2, dyn>>(); + test_default_ctor<std::extents<int, dyn, dyn, dyn>>(); + return true; +} + +int +main() +{ + test_default_ctor_all(); + static_assert(test_default_ctor_all()); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints.cc b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints.cc new file mode 100644 index 0000000..3a70efd --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints.cc @@ -0,0 +1,62 @@ +// { dg-do run { target c++23 } } +#include <mdspan> + +#include <testsuite_hooks.h> + +constexpr auto dyn = std::dynamic_extent; + +class A {}; + +// Not constructible if the number of integer-like arguments isn't either +// rank() or rank_dynamic(). +static_assert(!std::is_constructible_v<std::extents<int>, int>); +static_assert(!std::is_constructible_v<std::extents<int, dyn, dyn>, int>); +static_assert(!std::is_constructible_v<std::extents<int, 1, dyn, 3>, int, int>); + +// Not constructible from non integer-like objects. +static_assert(!std::is_constructible_v<std::extents<int, 1>, int, A>); + +// No implicit conversion from integer-like objects. +template<typename Extent, typename... OExtents> + constexpr bool + is_explicit() + { + return std::is_nothrow_constructible_v<Extent, OExtents...> + && !std::is_convertible_v<Extent, OExtents...>; + } + +static_assert(is_explicit<std::extents<int, 1>, int>()); +static_assert(is_explicit<std::extents<int, 1>, unsigned int>()); +static_assert(is_explicit<std::extents<unsigned int, 1>, int>()); + +constexpr bool +test_all() +{ + auto expected = std::extents<int, 1, 2, 3>(1, 2, 3); + + // From all extents. + VERIFY((std::extents<int, 1, 2, 3>(1, 2, 3)) == expected); + VERIFY((std::extents<int, dyn, 2, 3>(1, 2, 3)) == expected); + VERIFY((std::extents<int, dyn, 2, dyn>(1, 2, 3)) == expected); + + VERIFY((std::extents<int, 1, 2, 3>{1, 2, 3}) == expected); + VERIFY((std::extents<int, dyn, 2, 3>{1, 2, 3}) == expected); + VERIFY((std::extents<int, dyn, 2, dyn>{1, 2, 3}) == expected); + + // From only dynamic extents. + VERIFY((std::extents<int, dyn, 2, 3>(1)) == expected); + VERIFY((std::extents<int, dyn, 2, dyn>(1, 3)) == expected); + + VERIFY((std::extents<int, dyn, 2, 3>{1}) == expected); + VERIFY((std::extents<int, dyn, 2, dyn>{1, 3}) == expected); + + return true; +} + +int +main() +{ + test_all(); + static_assert(test_all()); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape.cc b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape.cc new file mode 100644 index 0000000..01624f2 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape.cc @@ -0,0 +1,160 @@ +// { dg-do run { target c++23 } } +#include <mdspan> + +#include <testsuite_hooks.h> + +constexpr auto dyn = std::dynamic_extent; + +template<typename Extent, typename T, size_t N> + constexpr bool + constructible() + { + return std::is_nothrow_constructible_v<Extent, std::array<T, N>> + && std::is_nothrow_constructible_v<Extent, std::span<T, N>>; + } + +template<typename Extent, typename T, size_t N> + constexpr bool + not_constructible() + { + return !std::is_constructible_v<Extent, std::array<T, N>> + && !std::is_constructible_v<Extent, std::span<T, N>>; + } + +template<typename Extent, typename T, size_t N> + constexpr bool + convertible() + { + return std::is_convertible_v<std::array<T, N>, Extent> + && std::is_convertible_v<std::span<T, N>, Extent>; + } + +template<typename Extent, typename T, size_t N> + constexpr bool + not_convertible() + { + return !std::is_convertible_v<std::array<T, N>, Extent> + && !std::is_convertible_v<std::span<T, N>, Extent>; + } + +static_assert(constructible<std::extents<int, 1, 2>, int, 2>()); +static_assert(not_constructible<std::extents<int, 1, 2>, int, 1>()); + +static_assert(constructible<std::extents<int>, int, 0>()); +static_assert(convertible<std::extents<int>, int, 0>()); +static_assert(convertible<std::extents<unsigned int>, int, 0>()); +static_assert(convertible<std::extents<int>, unsigned int, 0>()); + +static_assert(constructible<std::extents<int, 1, dyn>, int, 1>()); +static_assert(convertible<std::extents<int, 1, dyn>, int, 1>()); +static_assert(convertible<std::extents<unsigned int, 1, dyn>, int, 1>()); +static_assert(convertible<std::extents<int, 1, dyn>, unsigned int, 1>()); + +static_assert(constructible<std::extents<int, 1, dyn>, int, 2>()); +static_assert(not_convertible<std::extents<int, 1, dyn>, int, 2>()); +static_assert(not_convertible<std::extents<unsigned int, 1, dyn>, int, 2>()); +static_assert(not_convertible<std::extents<int, 1, dyn>, unsigned int, 2>()); + +// Non-integer, but convertible. +static_assert(constructible<std::extents<int, dyn>, double, 1>()); +static_assert(convertible<std::extents<int, dyn>, double, 1>()); + +namespace all_extents +{ + template<typename Shape> + constexpr void + test_ctor(Shape shape) + { + auto expected = std::extents<int, 1, 2, 3>(); + VERIFY((std::extents<int, 1, dyn, 3>(shape)) == expected); + VERIFY((std::extents<int, dyn, dyn, dyn>(shape)) == expected); + VERIFY((std::extents<int, 1, 2, 3>(shape)) == expected); + } + + constexpr void + test_common_shapes() + { + auto array = std::array<int, 3>{1, 2, 3}; + auto span_const = std::span<const int, 3>(array); + auto span = std::span<int, 3>(array); + + test_ctor(array); + test_ctor(span); + test_ctor(span_const); + } + + constexpr void + test_empty_shapes() + { + auto shape = std::array<int, 0>(); + auto span = std::span<int, 0>(shape); + + auto expected = std::extents<int>(); + VERIFY((std::extents<int>(shape)) == expected); + VERIFY((std::extents<int>(span)) == expected); + } + + constexpr bool + test_all() + { + test_common_shapes(); + test_empty_shapes(); + return true; + } +} + +namespace only_dynamic_extents +{ + template<typename Extents, typename Shape> + constexpr void + test_ctor(const Shape& shape) + { + Extents e = shape; + + VERIFY(e.rank_dynamic() == shape.size()); + + size_t di = 0; + for(size_t i = 0; i < e.rank(); ++i) + if(e.static_extent(i) == dyn) + VERIFY(e.extent(i) == shape[di++]); + } + + template<typename Extents, typename T, size_t N> + constexpr void + test_all_shape_types(std::array<T, N> shape) + { + test_ctor<Extents>(shape); + test_ctor<Extents>(std::span<T, N>(shape)); + test_ctor<Extents>(std::span<const T, N>(shape)); + } + + constexpr void + test_common_shapes() + { + auto s = std::array<int, 0>{}; + auto s2 = std::array<int, 1>{2}; + auto s123 = std::array<int, 3>{1, 2, 3}; + + test_all_shape_types<std::extents<int, 1, dyn, 3>>(s2); + test_all_shape_types<std::extents<int, dyn, dyn, dyn>>(s123); + test_all_shape_types<std::extents<int, 1, 2, 3>>(s); + } + + constexpr bool + test_all() + { + test_common_shapes(); + return true; + } +} + +int +main() +{ + all_extents::test_all(); + static_assert(all_extents::test_all()); + + only_dynamic_extents::test_all(); + static_assert(only_dynamic_extents::test_all()); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/extents/custom_integer.cc b/libstdc++-v3/testsuite/23_containers/mdspan/extents/custom_integer.cc new file mode 100644 index 0000000..2907ad1 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/custom_integer.cc @@ -0,0 +1,87 @@ +// { dg-do run { target c++23 } } +#include <mdspan> + +#include <testsuite_hooks.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>); + +void +test_shape(const auto& s2, const auto& s23) +{ + std::extents<int, 2, 3> expected; + + std::extents<int, 2, 3> e1(s23); + VERIFY(e1 == expected); + + std::extents<int, dyn, 3> e2(s2); + VERIFY(e2 == expected); + + std::extents<int, dyn, 3> e3(s23); + VERIFY(e3 == expected); + + std::extents<int, dyn, dyn> e4(s23); + VERIFY(e4 == expected); +} + +void +test_pack() +{ + std::extents<int, 2, 3> expected; + + std::extents<int, dyn, 3> e1(IntLike(2)); + VERIFY(e1 == expected); + + std::extents<int, dyn, 3> e2(IntLike(2), IntLike(3)); + VERIFY(e2 == expected); + + std::extents<int, dyn, dyn> e3(IntLike(2), IntLike(3)); + VERIFY(e3 == expected); +} + +int +main() +{ + auto a2 = std::array<IntLike, 1>{IntLike(2)}; + auto s2 = std::span<IntLike, 1>(a2); + + auto a23 = std::array<IntLike, 2>{IntLike(2), IntLike(3)}; + auto s23 = std::span<IntLike, 2>(a23); + + test_shape(a2, a23); + test_shape(s2, s23); + test_pack(); + + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/extents/misc.cc b/libstdc++-v3/testsuite/23_containers/mdspan/extents/misc.cc new file mode 100644 index 0000000..e71fdc5 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/misc.cc @@ -0,0 +1,224 @@ +// { dg-do run { target c++23 } } +#include <mdspan> + +#include <cstdint> +#include <testsuite_hooks.h> + +constexpr size_t dyn = std::dynamic_extent; + +// Check class traits. +static_assert(std::regular<std::extents<int>>); +static_assert(std::regular<std::extents<int, 1>>); +static_assert(std::regular<std::extents<int, dyn>>); + +static_assert(std::is_trivially_copyable_v<std::extents<int>>); +static_assert(std::is_trivially_copyable_v<std::extents<int, 1>>); +static_assert(std::is_trivially_copyable_v<std::extents<int, dyn>>); + +// Check member typedefs. +static_assert(std::is_same_v<std::extents<int, 1, 2>::rank_type, size_t>); + +static_assert(std::is_unsigned_v<std::extents<int, 2>::size_type>); +static_assert(std::is_unsigned_v<std::extents<unsigned int, 2>::size_type>); + +static_assert(std::is_same_v<std::extents<int, 2>::index_type, int>); +static_assert(std::is_same_v<std::extents<unsigned int, 2>::index_type, + unsigned int>); + +// Check `rank`. +static_assert(std::extents<int, 1>::rank() == 1); +static_assert(std::extents<int, dyn>::rank() == 1); +static_assert(std::extents<int, 2, dyn>::rank() == 2); + +// Check `rank_dynamic`. +static_assert(std::extents<int, 1>::rank_dynamic() == 0); +static_assert(std::extents<int, dyn>::rank_dynamic() == 1); +static_assert(std::extents<int, 2, dyn>::rank_dynamic() == 1); +static_assert(std::extents<int, dyn, dyn>::rank_dynamic() == 2); + +template<typename T, size_t... Extents> + constexpr bool + check_rank_return_types() + { + auto e = std::extents<T, Extents...>(); + return std::is_same_v<decltype(e.rank()), size_t> + && std::is_same_v<decltype(e.rank_dynamic()), size_t>; + } + +static_assert(check_rank_return_types<int, 1>()); + +// Check that the static extents don't take up space. +static_assert(sizeof(std::extents<int, 1, dyn>) == sizeof(int)); +static_assert(sizeof(std::extents<short, 1, dyn>) == sizeof(short)); + +template<typename Extents> +class Container +{ + int dummy; + [[no_unique_address]] std::extents<size_t> b0; +}; + +static_assert(sizeof(Container<std::extents<short, 1, 2>>) == sizeof(int)); +static_assert(sizeof(Container<std::extents<size_t, 1, 2>>) == sizeof(int)); + +// operator= +static_assert(std::is_nothrow_assignable_v<std::extents<int, dyn, 2>, + std::extents<int, 1, 2>>); + +constexpr bool +test_assign() +{ + auto e1 = std::extents<int, 1, 2>(); + auto e2 = std::extents<int, 1, 2>(); + + e2 = e1; + VERIFY(e2 == e1); + + auto e5 = std::extents<int, 1, dyn>(); + e5 = e1; + VERIFY(e5 == e1); + + auto e3 = std::extents<int, dyn, dyn>(1, 2); + auto e4 = std::extents<int, dyn, dyn>(3, 4); + e3 = e4; + VERIFY(e3 == e4); + return true; +} + +// Deduction guide +template<size_t Rank, typename... Extents> +constexpr void +test_deduction(Extents... exts) +{ + std::array<size_t, sizeof...(exts)> shape{static_cast<size_t>(exts)...}; + std::dextents<size_t, Rank> expected(shape); + std::extents e(exts...); + static_assert(std::is_same_v<decltype(e), std::dextents<size_t, Rank>>); + VERIFY(e == expected); +} + +constexpr bool +test_deduction_all() +{ + test_deduction<0>(); + test_deduction<1>(1); + test_deduction<2>(1.0, 2.0f); + test_deduction<3>(int(1), short(2), size_t(3)); + return true; +} + +class A {}; + +template<typename... Extents> + concept deducible = requires + { + { std::extents(Extents{}...) } + -> std::convertible_to<std::dextents<size_t, sizeof...(Extents)>>; + }; + +static_assert(deducible<int>); +static_assert(!deducible<A, A>); + +// dextents +static_assert(std::is_same_v<std::dextents<int, 0>, std::extents<int>>); +static_assert(std::is_same_v<std::dextents<int, 1>, std::extents<int, dyn>>); +static_assert(std::is_same_v<std::dextents<int, 5>, + std::extents<int, dyn, dyn, dyn, dyn, dyn>>); + +static_assert(std::dextents<int, 5>::rank() == 5); +static_assert(std::dextents<int, 5>::rank_dynamic() == 5); +static_assert(std::is_same_v<typename std::dextents<int, 5>::index_type, int>); + +// static_extent +static_assert(std::extents<int, 1, 2>::static_extent(0) == 1); +static_assert(std::extents<int, 1, 2>::static_extent(1) == 2); + +static_assert(std::extents<int, 1, dyn>::static_extent(0) == 1); +static_assert(std::extents<int, 1, dyn>::static_extent(1) == dyn); + +static_assert(std::extents<int, dyn, dyn>::static_extent(0) == dyn); +static_assert(std::extents<int, dyn, dyn>::static_extent(1) == dyn); + +// extent +template<typename Extent> + constexpr void + test_extent(const Extent& e, + const std::array<typename Extent::index_type, Extent::rank()>& shape) + { + for(size_t i = 0; i < e.rank(); ++i) + VERIFY(e.extent(i) == shape[i]); + } + +constexpr bool +test_extent_all() +{ + test_extent(std::extents<int, 1, 2>{}, {1, 2}); + test_extent(std::extents<int, 1, dyn>{2}, {1, 2}); + test_extent(std::extents<int, dyn, dyn>{1, 2}, {1, 2}); + return true; +} + +// operator== +template<typename Lhs, typename Rhs> + constexpr void + test_ops_eq(const Lhs& lhs, const Rhs& rhs, bool expected) + { + VERIFY((lhs == rhs) == expected); + VERIFY((lhs != rhs) == !expected); + } + +constexpr void +test_op_eq_rank_zero() +{ + auto e1 = std::extents<int>(); + auto e2 = std::extents<int>(); + auto e3 = std::extents<unsigned int>(); + + test_ops_eq(e1, e2, true); + test_ops_eq(e1, e3, true); +} + +constexpr void +test_op_eq_common() +{ + auto e1 = std::extents<int, 1, 2, 3>(); + auto e2 = std::extents<int, 1, 2, 3>(); + auto e3 = std::extents<int, 1, dyn, 3>(2); + auto e4 = std::extents<int, 1, dyn, 3>(3); + + auto e5 = std::extents<int, 1>(); + auto e6 = std::extents<int, 1, 3, 3>(); + + test_ops_eq(e1, e2, true); + test_ops_eq(e1, e3, true); + test_ops_eq(e1, e4, false); + + test_ops_eq(e1, e5, false); + test_ops_eq(e1, e6, false); + test_ops_eq(e3, e6, false); +} + +constexpr bool +test_op_eq_all() +{ + test_op_eq_rank_zero(); + test_op_eq_common(); + return true; +} + +int +main() +{ + test_assign(); + static_assert(test_assign()); + + test_deduction_all(); + static_assert(test_deduction_all()); + + test_extent_all(); + static_assert(test_extent_all()); + + test_op_eq_all(); + static_assert(test_op_eq_all()); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/class_mandate_neg.cc b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/class_mandate_neg.cc new file mode 100644 index 0000000..7091153 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/class_mandate_neg.cc @@ -0,0 +1,48 @@ +// { dg-do compile { target c++23 } } +#include<mdspan> + +#include <cstdint> + +constexpr size_t dyn = std::dynamic_extent; +static constexpr size_t n = std::numeric_limits<uint8_t>::max() / 2; + +template<typename Layout> + struct A + { + typename Layout::mapping<std::extents<uint8_t, n, 2>> m0; + typename Layout::mapping<std::extents<uint8_t, n, 2, dyn>> m1; + typename Layout::mapping<std::extents<uint8_t, n, 2, 0>> m2; + + using extents_type = std::extents<uint8_t, n, 4>; + typename Layout::mapping<extents_type> m3; // { dg-error "required from" } + }; + +template<size_t Count, typename Layout, typename OLayout> + bool + B() + { + using Extents = std::extents<uint8_t, dyn, dyn, Count>; + using OExtents = std::extents<uint16_t, n, 4, Count>; + + using Mapping = typename Layout::mapping<Extents>; + using OMapping = typename OLayout::mapping<OExtents>; + + Mapping m{OMapping{}}; + return true; + }; + +A<std::layout_left> a_left; // { dg-error "required from" } +A<std::layout_right> a_right; // { dg-error "required from" } +A<std::layout_stride> a_stride; // { dg-error "required from" } + +auto b1 = B<1, std::layout_left, std::layout_left>(); // { dg-error "required from" } +auto b2 = B<2, std::layout_left, std::layout_stride>(); // { dg-error "required from" } + +auto b3 = B<3, std::layout_right, std::layout_right>(); // { dg-error "required from" } +auto b4 = B<4, std::layout_right, std::layout_stride>(); // { dg-error "required from" } + +auto b5 = B<5, std::layout_stride, std::layout_right>(); // { dg-error "required from" } +auto b6 = B<6, std::layout_stride, std::layout_left>(); // { dg-error "required from" } +auto b7 = B<7, std::layout_stride, std::layout_stride>(); // { dg-error "required from" } + +// { dg-prune-output "must be representable as index_type" } diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/ctors.cc b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/ctors.cc new file mode 100644 index 0000000..23c0a55 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/ctors.cc @@ -0,0 +1,436 @@ +// { dg-do run { target c++23 } } +#include <mdspan> + +#include <cstdint> +#include <testsuite_hooks.h> + +constexpr size_t dyn = std::dynamic_extent; + +template<typename Mapping, typename IndexType, size_t... Extents> + constexpr void + verify(std::extents<IndexType, Extents...> oexts) + { + auto m = Mapping(oexts); + VERIFY(m.extents() == oexts); + } + +template<typename Mapping, typename OMapping> + requires (requires { typename OMapping::layout_type; }) + constexpr void + verify(OMapping other) + { + constexpr auto rank = Mapping::extents_type::rank(); + auto m = Mapping(other); + VERIFY(m.extents() == other.extents()); + if constexpr (rank > 0) + for(size_t i = 0; i < rank; ++i) + VERIFY(std::cmp_equal(m.stride(i), other.stride(i))); + } + + +template<typename To, typename From> + constexpr void + verify_convertible(From from) + { + static_assert(std::is_convertible_v<From, To>); + verify<To>(from); + } + +template<typename To, typename From> + constexpr void + verify_nothrow_convertible(From from) + { + static_assert(std::is_nothrow_constructible_v<To, From>); + verify_convertible<To>(from); + } + +template<typename To, typename From> + constexpr void + verify_constructible(From from) + { + static_assert(!std::is_convertible_v<From, To>); + static_assert(std::is_constructible_v<To, From>); + verify<To>(from); + } + +template<typename To, typename From> + constexpr void + verify_nothrow_constructible(From from) + { + static_assert(std::is_nothrow_constructible_v<To, From>); + verify_constructible<To>(from); + } + +template<typename Mapping, typename OExtents> + constexpr void + assert_not_constructible() + { + static_assert(!std::is_constructible_v<Mapping, OExtents>); + } + +// ctor: mapping() +namespace default_ctor +{ + template<typename Layout, typename Extents> + constexpr void + test_default_ctor() + { + using Mapping = typename Layout::mapping<Extents>; + + Mapping m; + for(size_t i = 0; i < Extents::rank(); ++i) + if (Extents::static_extent(i) == std::dynamic_extent) + VERIFY(m.extents().extent(i) == 0); + else + VERIFY(m.extents().static_extent(i) == Extents::static_extent(i)); + } + + template<typename Layout> + constexpr bool + test_default_ctor_all() + { + test_default_ctor<Layout, std::extents<int, dyn>>(); + test_default_ctor<Layout, std::extents<int, 1, 2>>(); + test_default_ctor<Layout, std::extents<int, dyn, 2>>(); + test_default_ctor<Layout, std::extents<int, dyn, dyn>>(); + test_default_ctor<Layout, std::extents<int, dyn, 2, dyn>>(); + test_default_ctor<Layout, std::extents<int, dyn, dyn, dyn>>(); + return true; + } + + template<typename Layout> + constexpr void + test_all() + { + test_default_ctor_all<Layout>(); + static_assert(test_default_ctor_all<Layout>()); + } +} + +// ctor: mapping(const extents&) +namespace from_extents +{ + template<typename Layout, typename Extents, typename OExtents> + constexpr void + verify_nothrow_convertible(OExtents oexts) + { + using Mapping = typename Layout::mapping<Extents>; + ::verify_nothrow_convertible<Mapping>(oexts); + } + + template<typename Layout, typename Extents, typename OExtents> + constexpr void + verify_nothrow_constructible(OExtents oexts) + { + using Mapping = typename Layout::mapping<Extents>; + ::verify_nothrow_constructible<Mapping>(oexts); + } + + template<typename Layout, typename Extents, typename OExtents> + constexpr void + assert_not_constructible() + { + using Mapping = typename Layout::mapping<Extents>; + ::assert_not_constructible<Mapping, OExtents>(); + } + + template<typename Layout> + constexpr bool + test_ctor() + { + verify_nothrow_convertible<Layout, std::extents<int>>( + std::extents<int>{}); + + verify_nothrow_convertible<Layout, std::extents<int, 2>>( + std::extents<int, 2>{}); + + verify_nothrow_convertible<Layout, std::extents<int, dyn, 3>>( + std::extents<int, dyn, 3>{2}); + + verify_nothrow_constructible<Layout, std::extents<unsigned int>>( + std::extents<int>{}); + + verify_nothrow_constructible<Layout, std::extents<int, dyn>>( + std::extents<int, 2>{}); + + verify_nothrow_constructible<Layout, std::extents<int, dyn, 3>>( + std::extents<int, 2, 3>{}); + + assert_not_constructible<Layout, std::extents<int>, + std::extents<unsigned int>>(); + assert_not_constructible<Layout, std::extents<int, 2>, + std::extents<int, dyn>>(); + assert_not_constructible<Layout, std::extents<int, 2, 3>, + std::extents<int, dyn, 3>>(); + return true; + } + + template<typename Layout, typename Extents> + constexpr void + assert_deducible(Extents exts) + { + typename Layout::mapping m(exts); + static_assert(std::same_as<decltype(m), + typename Layout::mapping<Extents>>); + } + + template<typename Layout> + constexpr void + test_deducible() + { + assert_deducible<Layout>(std::extents<int>()); + assert_deducible<Layout>(std::extents<int, 1>()); + assert_deducible<Layout>(std::extents<int, 1, 2, dyn>(3)); + } + + template<typename Layout> + constexpr void + test_all() + { + test_ctor<Layout>(); + static_assert(test_ctor<Layout>()); + test_deducible<Layout>(); + } +} + +// ctor: mapping(mapping<OExtents>) +namespace from_same_layout +{ + template<typename Layout, typename Extents, typename OExtents> + constexpr void + verify_nothrow_convertible(OExtents exts) + { + using Mapping = typename Layout::mapping<Extents>; + using OMapping = typename Layout::mapping<OExtents>; + + ::verify_nothrow_convertible<Mapping>(OMapping(exts)); + } + + template<typename Layout, typename Extents, typename OExtents> + constexpr void + verify_nothrow_constructible(OExtents exts) + { + using Mapping = typename Layout::mapping<Extents>; + using OMapping = typename Layout::mapping<OExtents>; + + ::verify_nothrow_constructible<Mapping>(OMapping(exts)); + } + + template<typename Layout> + constexpr bool + test_ctor() + { + verify_nothrow_convertible<Layout, std::extents<unsigned int>>( + std::extents<int>{}); + + verify_nothrow_constructible<Layout, std::extents<int>>( + std::extents<unsigned int>{}); + + assert_not_constructible< + typename Layout::mapping<std::extents<int>>, + typename Layout::mapping<std::extents<int, 1>>>(); + + assert_not_constructible< + typename Layout::mapping<std::extents<int, 1>>, + typename Layout::mapping<std::extents<int>>>(); + + verify_nothrow_constructible<Layout, std::extents<int, 1>>( + std::extents<int, dyn>{1}); + + verify_nothrow_convertible<Layout, std::extents<int, dyn>>( + std::extents<int, 1>{}); + + assert_not_constructible< + typename Layout::mapping<std::extents<int, 1, 2>>, + typename Layout::mapping<std::extents<int, 1>>>(); + + verify_nothrow_constructible<Layout, std::extents<int, 1, 2>>( + std::extents<int, dyn, 2>{1}); + + verify_nothrow_convertible<Layout, std::extents<int, dyn, 2>>( + std::extents<int, 1, 2>{}); + return true; + } + + template<typename Layout> + constexpr void + test_all() + { + test_ctor<Layout>(); + static_assert(test_ctor<Layout>()); + } +} + +// ctor: mapping(layout_{right,left}::mapping<OExtents>) +namespace from_left_or_right +{ + template<typename SLayout, typename OLayout, typename SExtents, + typename OExtents> + constexpr void + verify_ctor(OExtents oexts) + { + using SMapping = typename SLayout::mapping<SExtents>; + using OMapping = typename OLayout::mapping<OExtents>; + + constexpr bool expected = std::is_convertible_v<OExtents, SExtents>; + if constexpr (expected) + verify_nothrow_convertible<SMapping>(OMapping(oexts)); + else + verify_nothrow_constructible<SMapping>(OMapping(oexts)); + } + + template<typename SLayout, typename OLayout> + constexpr bool + test_ctor() + { + assert_not_constructible< + typename SLayout::mapping<std::extents<int>>, + typename OLayout::mapping<std::extents<int, 1>>>(); + + verify_ctor<OLayout, SLayout, std::extents<int>>( + std::extents<unsigned int>{}); + + verify_ctor<OLayout, SLayout, std::extents<unsigned int>>( + std::extents<int>{}); + + assert_not_constructible< + typename SLayout::mapping<std::extents<int, 1>>, + typename OLayout::mapping<std::extents<int>>>(); + + verify_ctor<OLayout, SLayout, std::extents<int, 1>>( + std::extents<int, 1>{}); + + verify_ctor<OLayout, SLayout, std::extents<int, 1>>( + std::extents<unsigned int, 1>{}); + + verify_ctor<OLayout, SLayout, std::extents<unsigned int, 1>>( + std::extents<int, 1>{}); + + assert_not_constructible< + typename SLayout::mapping<std::extents<int, 1, 2>>, + typename OLayout::mapping<std::extents<int, 1, 2>>>(); + return true; + } + + template<typename SLayout, typename OLayout> + constexpr void + test_all() + { + test_ctor<SLayout, OLayout>(); + static_assert(test_ctor<SLayout, OLayout>()); + } +} + +// ctor: mapping(layout_stride::mapping<OExtents>) +namespace from_stride +{ + template<typename Mapping> + constexpr auto + strides(Mapping m) + { + constexpr auto rank = Mapping::extents_type::rank(); + std::array<typename Mapping::index_type, rank> s; + + if constexpr (rank > 0) + for(size_t i = 0; i < rank; ++i) + s[i] = m.stride(i); + return s; + } + + template<typename Layout, typename Extents, typename OExtents> + constexpr void + verify_nothrow_convertible(OExtents oexts) + { + using Mapping = typename Layout::mapping<Extents>; + using OMapping = std::layout_stride::mapping<OExtents>; + + constexpr auto other = OMapping(oexts, strides(Mapping(Extents(oexts)))); + ::verify_nothrow_convertible<Mapping>(other); + } + + template<typename Layout, typename Extents, typename OExtents> + constexpr void + verify_nothrow_constructible(OExtents oexts) + { + using Mapping = typename Layout::mapping<Extents>; + using OMapping = std::layout_stride::mapping<OExtents>; + + constexpr auto other = OMapping(oexts, strides(Mapping(Extents(oexts)))); + ::verify_nothrow_constructible<Mapping>(other); + } + + template<typename Layout> + constexpr bool + test_ctor() + { + assert_not_constructible< + typename Layout::mapping<std::extents<int>>, + std::layout_stride::mapping<std::extents<int, 1>>>(); + + assert_not_constructible< + typename Layout::mapping<std::extents<int, 1>>, + std::layout_stride::mapping<std::extents<int>>>(); + + assert_not_constructible< + typename Layout::mapping<std::extents<int, 2>>, + std::layout_stride::mapping<std::extents<int, 1>>>(); + + verify_nothrow_convertible<Layout, std::extents<int>>( + std::extents<int>{}); + + verify_nothrow_convertible<Layout, std::extents<unsigned int>>( + std::extents<int>{}); + + // Rank == 0 doesn't check IndexType for convertibility. + verify_nothrow_convertible<Layout, std::extents<int>>( + std::extents<unsigned int>{}); + + verify_nothrow_constructible<Layout, std::extents<int, 3>>( + std::extents<int, 3>{}); + + verify_nothrow_constructible<Layout, std::extents<unsigned int, 3>>( + std::extents<int, 3>{}); + + verify_nothrow_constructible<Layout, std::extents<int, 3>>( + std::extents<unsigned int, 3>{}); + + verify_nothrow_constructible<Layout, std::extents<int, 3, 5>>( + std::extents<int, 3, 5>{}); + + verify_nothrow_constructible<Layout, std::extents<unsigned int, 3, 5>>( + std::extents<int, 3, 5>{}); + + verify_nothrow_constructible<Layout, std::extents<int, 3, 5>>( + std::extents<unsigned int, 3, 5>{}); + return true; + } + + template<typename Layout> + constexpr void + test_all() + { + test_ctor<Layout>(); + static_assert(test_ctor<Layout>()); + } +} + +template<typename Layout> + constexpr void + test_all() + { + default_ctor::test_all<Layout>(); + from_extents::test_all<Layout>(); + from_same_layout::test_all<Layout>(); + from_stride::test_all<Layout>(); + } + +int +main() +{ + test_all<std::layout_left>(); + test_all<std::layout_right>(); + + from_left_or_right::test_all<std::layout_left, std::layout_right>(); + from_left_or_right::test_all<std::layout_right, std::layout_left>(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/empty.cc b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/empty.cc new file mode 100644 index 0000000..655b9b6 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/empty.cc @@ -0,0 +1,131 @@ +// { dg-do run { target c++23 } } +#include <mdspan> + +#include <cstdint> +#include <algorithm> +#include <testsuite_hooks.h> + +constexpr size_t dyn = std::dynamic_extent; + +template<typename Mapping> + constexpr void + invoke_stride(Mapping m) + { + // Only checking for UB, e.g. signed overflow. + for(size_t i = 0; i < Mapping::extents_type::rank(); ++i) + m.stride(i); + } + +template<typename Mapping> + constexpr void + verify_required_span_size(Mapping m) + { VERIFY(m.required_span_size() == 0); } + +template<typename Mapping> + constexpr void + verify_all(Mapping m) + { + verify_required_span_size(m); + invoke_stride(m); + } + +template<typename Layout, typename Int> +constexpr void +test_static_overflow() +{ + constexpr Int n1 = std::numeric_limits<Int>::max(); + constexpr size_t n2 = std::dynamic_extent - 1; + constexpr size_t n = std::cmp_less(n1, n2) ? size_t(n1) : n2; + + verify_all(typename Layout::mapping<std::extents<Int, n, n, 0, n, n>>{}); + verify_all(typename Layout::mapping<std::extents<Int, 0, n, n, n>>{}); + verify_all(typename Layout::mapping<std::extents<Int, dyn, n, n, n>>{}); + verify_all(typename Layout::mapping<std::extents<Int, n, n, n, 0>>{}); + verify_all(typename Layout::mapping<std::extents<Int, n, n, n, dyn>>{}); +} + +template<typename Int, size_t N> +constexpr std::array<Int, N> +make_strides() +{ + std::array<Int, N> strides; + std::ranges::fill(strides, Int(1)); + return strides; +} + +template<typename Layout, typename Extents> +constexpr typename Layout::mapping<Extents> +make_mapping(Extents exts) +{ + using IndexType = typename Extents::index_type; + constexpr auto rank = Extents::rank(); + constexpr auto strides = make_strides<IndexType, rank>(); + + if constexpr (std::same_as<Layout, std::layout_stride>) + return typename Layout::mapping(exts, strides); + else + return typename Layout::mapping(exts); +} + +template<typename Layout, typename Int> +constexpr void +test_dynamic_overflow() +{ + constexpr Int n1 = std::numeric_limits<Int>::max(); + constexpr size_t n2 = std::dynamic_extent - 1; + constexpr Int n = std::cmp_less(n1, n2) ? n1 : Int(n2); + + verify_all(make_mapping<Layout>( + std::extents<Int, dyn, dyn, 0, dyn, dyn>{n, n, n, n})); + + verify_all(make_mapping<Layout>( + std::extents<Int, dyn, dyn, dyn, dyn, dyn>{n, n, 0, n, n})); + + verify_all(make_mapping<Layout>( + std::extents<Int, dyn, dyn, dyn, 0>{n, n, n})); + + verify_all(make_mapping<Layout>( + std::extents<Int, dyn, dyn, dyn, dyn>{n, n, n, 0})); + + verify_all(make_mapping<Layout>( + std::extents<Int, 0, dyn, dyn, dyn>{n, n, n})); + + verify_all(make_mapping<Layout>( + std::extents<Int, dyn, dyn, dyn, dyn>{0, n, n, n})); +} + +template<typename Layout, typename Int> +constexpr void +test_overflow() +{ + test_static_overflow<Layout, Int>(); + test_dynamic_overflow<Layout, Int>(); +} + +template<typename Layout> +constexpr bool +test_all() +{ + test_overflow<Layout, signed char>(); + test_overflow<Layout, short int>(); + test_overflow<Layout, int>(); + test_overflow<Layout, long int>(); + test_overflow<Layout, long long int>(); + + test_overflow<Layout, unsigned char>(); + test_overflow<Layout, unsigned short int>(); + test_overflow<Layout, unsigned int>(); + test_overflow<Layout, unsigned long int>(); + test_overflow<Layout, unsigned long long int>(); + test_overflow<Layout, size_t>(); + return true; +} + +int +main() +{ + static_assert(test_all<std::layout_left>()); + static_assert(test_all<std::layout_right>()); + static_assert(test_all<std::layout_stride>()); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/mapping.cc b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/mapping.cc new file mode 100644 index 0000000..963c804 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/mapping.cc @@ -0,0 +1,568 @@ +// { dg-do run { target c++23 } } +#include <mdspan> + +#include <cstdint> +#include <testsuite_hooks.h> + +constexpr size_t dyn = std::dynamic_extent; + +template<typename Layout, typename Extents> + constexpr bool + test_mapping_properties() + { + using M = typename Layout::mapping<Extents>; + static_assert(std::__mdspan::__is_extents<typename M::extents_type>); + static_assert(std::__mdspan::__mapping_alike<M>); + static_assert(std::copyable<M>); + static_assert(std::is_nothrow_move_constructible_v<M>); + static_assert(std::is_nothrow_move_assignable_v<M>); + static_assert(std::is_nothrow_swappable_v<M>); + static_assert(std::is_same_v<typename M::extents_type, Extents>); + static_assert(std::is_same_v<typename M::index_type, + typename M::extents_type::index_type>); + static_assert(std::is_same_v<typename M::size_type, + typename M::extents_type::size_type>); + static_assert(std::is_same_v<typename M::rank_type, + typename M::extents_type::rank_type>); + static_assert(std::is_same_v<typename M::layout_type, Layout>); + + static_assert(std::is_trivially_copyable_v<M>); + static_assert(std::regular<M>); + + static_assert(M::is_always_unique() && M::is_unique()); + static_assert(M::is_always_strided() && M::is_strided()); + if constexpr (!std::is_same_v<Layout, std::layout_stride>) + static_assert(M::is_always_exhaustive() && M::is_exhaustive()); + return true; + } + +template<typename Layout> + constexpr bool + test_mapping_properties_all() + { + test_mapping_properties<Layout, std::extents<int>>(); + test_mapping_properties<Layout, std::extents<int, 1>>(); + test_mapping_properties<Layout, std::extents<int, dyn>>(); + test_mapping_properties<Layout, std::extents<int, dyn, dyn>>(); + return true; + } + +// Check operator()(Indices...) +template<typename Mapping, size_t N> + constexpr typename Mapping::index_type + linear_index(const Mapping& mapping, + const std::array<typename Mapping::index_type, N>& indices) + { + typename Mapping::index_type ret = 0; + for(size_t r = 0; r < indices.size(); ++r) + ret += indices[r] * mapping.stride(r); + return ret; + } + +template<typename Mapping, typename... Indices> + constexpr void + test_linear_index(const Mapping& m, Indices... i) + { + using index_type = typename Mapping::index_type; + index_type expected = linear_index(m, std::array{index_type(i)...}); + VERIFY(m(i...) == expected); + VERIFY(m(uint8_t(i)...) == expected); + } + +template<typename Layout> + constexpr void + test_linear_index_0d() + { + constexpr typename Layout::mapping<std::extents<int>> m; + VERIFY(m() == 0); + } + +template<typename Layout> + constexpr void + test_linear_index_1d() + { + typename Layout::mapping<std::extents<int, 5>> m; + test_linear_index(m, 0); + test_linear_index(m, 1); + test_linear_index(m, 4); + } + +template<typename Layout> + constexpr void + test_linear_index_2d() + { + typename Layout::mapping<std::extents<int, 3, 256>> m; + test_linear_index(m, 0, 0); + test_linear_index(m, 1, 0); + test_linear_index(m, 0, 1); + test_linear_index(m, 1, 1); + test_linear_index(m, 2, 4); + } + +template<typename Layout> + struct MappingFactory + { + template<typename Extents> + static constexpr typename Layout::mapping<Extents> + create(Extents exts) + { return exts; } + }; + +template<> + struct MappingFactory<std::layout_stride> + { + template<typename Extents> + static constexpr std::layout_stride::mapping<Extents> + create(Extents exts) + { + if constexpr (Extents::rank() == 0) + { + auto strides = std::array<size_t, 0>{}; + return std::layout_stride::mapping(exts, strides); + } + else if constexpr (Extents::rank() == 1) + { + auto strides = std::array<size_t, 1>{2}; + return std::layout_stride::mapping(exts, strides); + } + else if constexpr (Extents::rank() == 2) + { + size_t m = exts.extent(1); + auto strides = std::array<size_t, 2>{3*m, 2}; + return std::layout_stride::mapping(exts, strides); + } + else if constexpr (Extents::rank() == 3) + { + size_t n = exts.extent(0); + size_t m = exts.extent(1); + auto strides = std::array<size_t, 3>{3*m, 2, 11*m*n}; + return std::layout_stride::mapping(exts, strides); + } + } + }; + +template<typename Layout> + constexpr void + test_linear_index_3d() + { + auto m = MappingFactory<Layout>::create(std::extents(3, 5, 7)); + test_linear_index(m, 0, 0, 0); + test_linear_index(m, 1, 0, 0); + test_linear_index(m, 0, 1, 0); + test_linear_index(m, 0, 0, 1); + test_linear_index(m, 1, 1, 0); + test_linear_index(m, 2, 4, 6); + } + +struct IntLikeA +{ + operator int() + { return 0; } +}; + +struct IntLikeB +{ + operator int() noexcept + { return 0; } +}; + +struct NotIntLike +{ }; + +template<typename Layout> + constexpr void + test_has_linear_index_0d() + { + using Mapping = typename Layout::mapping<std::extents<int>>; + static_assert(std::invocable<Mapping>); + static_assert(!std::invocable<Mapping, int>); + static_assert(!std::invocable<Mapping, IntLikeA>); + static_assert(!std::invocable<Mapping, IntLikeB>); + static_assert(!std::invocable<Mapping, NotIntLike>); + } + +template<typename Layout> + constexpr void + test_has_linear_index_1d() + { + using Mapping = typename Layout::mapping<std::extents<int, 3>>; + static_assert(std::invocable<Mapping, int>); + static_assert(!std::invocable<Mapping>); + static_assert(!std::invocable<Mapping, IntLikeA>); + static_assert(std::invocable<Mapping, IntLikeB>); + static_assert(!std::invocable<Mapping, NotIntLike>); + static_assert(std::invocable<Mapping, double>); + } + +template<typename Layout> + constexpr void + test_has_linear_index_2d() + { + using Mapping = typename Layout::mapping<std::extents<int, 3, 5>>; + static_assert(std::invocable<Mapping, int, int>); + static_assert(!std::invocable<Mapping, int>); + static_assert(!std::invocable<Mapping, IntLikeA, int>); + static_assert(std::invocable<Mapping, IntLikeB, int>); + static_assert(!std::invocable<Mapping, NotIntLike, int>); + static_assert(std::invocable<Mapping, double, double>); + } + +template<typename Layout> + constexpr bool + test_linear_index_all() + { + test_linear_index_0d<Layout>(); + test_linear_index_1d<Layout>(); + test_linear_index_2d<Layout>(); + test_linear_index_3d<Layout>(); + test_has_linear_index_0d<Layout>(); + test_has_linear_index_1d<Layout>(); + test_has_linear_index_2d<Layout>(); + return true; + } + +template<typename Mapping> + constexpr typename Mapping::index_type + linear_index_end(Mapping m) + { + using index_type = typename Mapping::index_type; + constexpr size_t rank = Mapping::extents_type::rank(); + + auto impl = [m]<index_type... Counts>( + std::integer_sequence<index_type, Counts...>) -> index_type + { + auto exts = m.extents(); + if(((exts.extent(Counts) == 0) || ...)) + return 0; + return m((exts.extent(Counts) - 1)...) + 1; + }; + + return impl(std::make_integer_sequence<index_type, rank>()); + } + +// Check required_span_size +template<typename Mapping> + constexpr void + test_required_span_size(Mapping m) + { VERIFY(m.required_span_size() == linear_index_end(m)); } + +template<typename Layout> + constexpr void + test_required_span_size_0d() + { + typename Layout::mapping<std::extents<int>> m; + test_required_span_size(m); + } + +template<typename Layout> + constexpr void + test_required_span_size_1d() + { + auto m = MappingFactory<Layout>::create(std::extents(3)); + test_required_span_size(m); + } + +template<typename Layout> + constexpr void + test_required_span_size_2d() + { + auto m = MappingFactory<Layout>::create(std::extents(3, 5)); + test_required_span_size(m); + } + +template<typename Layout> + constexpr void + test_required_span_size_3d() + { + auto m = MappingFactory<Layout>::create(std::extents(3, 5, 7)); + test_required_span_size(m); + } + +template<typename Layout> + constexpr void + test_required_span_size_zero_1d() + { + auto m = MappingFactory<Layout>::create(std::extents(3, 0)); + test_required_span_size(m); + } + +template<typename Layout> + constexpr void + test_required_span_size_zero_3d() + { + auto m = MappingFactory<Layout>::create(std::extents(3, 0, 7)); + test_required_span_size(m); + } + +template<typename Layout> + constexpr bool + test_required_span_size_all() + { + test_required_span_size_0d<Layout>(); + test_required_span_size_1d<Layout>(); + test_required_span_size_2d<Layout>(); + test_required_span_size_3d<Layout>(); + test_required_span_size_zero_1d<Layout>(); + test_required_span_size_zero_3d<Layout>(); + return true; + } + +// Check stride +template<typename Layout> + constexpr void + test_stride_1d() + { + std::layout_left::mapping<std::extents<int, 3>> m; + VERIFY(m.stride(0) == 1); + } + +template<> + constexpr void + test_stride_1d<std::layout_stride>() + { + std::array<int, 1> strides{13}; + std::layout_stride::mapping m(std::extents<int, 3>{}, strides); + VERIFY(m.stride(0) == strides[0]); + VERIFY(m.strides() == strides); + } + +template<typename Layout> + constexpr void + test_stride_2d(); + +template<> + constexpr void + test_stride_2d<std::layout_left>() + { + std::layout_left::mapping<std::extents<int, 3, 5>> m; + VERIFY(m.stride(0) == 1); + VERIFY(m.stride(1) == 3); + } + +template<> + constexpr void + test_stride_2d<std::layout_right>() + { + std::layout_right::mapping<std::extents<int, 3, 5>> m; + VERIFY(m.stride(0) == 5); + VERIFY(m.stride(1) == 1); + } + +template<> + constexpr void + test_stride_2d<std::layout_stride>() + { + std::array<int, 2> strides{13, 2}; + std::layout_stride::mapping m(std::extents<int, 3, 5>{}, strides); + VERIFY(m.stride(0) == strides[0]); + VERIFY(m.stride(1) == strides[1]); + VERIFY(m.strides() == strides); + } + +template<typename Layout> + constexpr void + test_stride_3d(); + +template<> + constexpr void + test_stride_3d<std::layout_left>() + { + std::layout_left::mapping m(std::dextents<int, 3>(3, 5, 7)); + VERIFY(m.stride(0) == 1); + VERIFY(m.stride(1) == 3); + VERIFY(m.stride(2) == 3*5); + } + +template<> + constexpr void + test_stride_3d<std::layout_right>() + { + std::layout_right::mapping m(std::dextents<int, 3>(3, 5, 7)); + VERIFY(m.stride(0) == 5*7); + VERIFY(m.stride(1) == 7); + VERIFY(m.stride(2) == 1); + } + +template<> + constexpr void + test_stride_3d<std::layout_stride>() + { + std::dextents<int, 3> exts(3, 5, 7); + std::array<int, 3> strides{11, 2, 41}; + std::layout_stride::mapping<std::dextents<int, 3>> m(exts, strides); + VERIFY(m.stride(0) == strides[0]); + VERIFY(m.stride(1) == strides[1]); + VERIFY(m.stride(2) == strides[2]); + VERIFY(m.strides() == strides); + } + +template<typename Layout> + constexpr bool + test_stride_all() + { + test_stride_1d<Layout>(); + test_stride_2d<Layout>(); + test_stride_3d<Layout>(); + return true; + } + +template<typename Mapping> + concept has_stride = requires (Mapping m) + { + { m.stride(0) } -> std::same_as<typename Mapping::index_type>; + }; + +template<typename Layout> + constexpr void + test_has_stride_0d() + { + using Mapping = typename Layout::mapping<std::extents<int>>; + constexpr bool expected = std::is_same_v<Layout, std::layout_stride>; + static_assert(has_stride<Mapping> == expected); + } + +template<typename Layout> + constexpr void + test_has_stride_1d() + { static_assert(has_stride<typename Layout::mapping<std::extents<int, 1>>>); } + +template<typename Layout> + constexpr void + test_has_stride_2d() + { + using Extents = std::extents<int, 1, 2>; + static_assert(has_stride<typename Layout::mapping<Extents>>); + } + +// Check operator== +template<typename Layout> + constexpr void + test_eq() + { + typename Layout::mapping<std::extents<int, 1, 2>> m1; + typename Layout::mapping<std::extents<int, 2, 2>> m2; + typename Layout::mapping<std::dextents<int, 2>> m3(m1); + + VERIFY(m1 == m1); + VERIFY(m1 != m2); + VERIFY(m1 == m3); + VERIFY(m2 != m3); + } + +template<typename Layout> + constexpr void + test_eq_zero() + { + typename Layout::mapping<std::extents<int, 0, 2>> m1; + typename Layout::mapping<std::extents<int, 0, 2>> m2; + typename Layout::mapping<std::extents<int, 2, 0>> m3; + + VERIFY(m1 == m2); + VERIFY(m1 != m3); + } + +template<typename M1, typename M2> + concept has_op_eq = requires (M1 m1, M2 m2) + { + { m1 == m2 } -> std::same_as<bool>; + { m2 == m1 } -> std::same_as<bool>; + { m1 != m2 } -> std::same_as<bool>; + { m2 != m1 } -> std::same_as<bool>; + }; + +template<typename SLayout, typename OLayout, bool Expected> + constexpr void + test_has_op_eq() + { + static_assert(has_op_eq< + typename SLayout::mapping<std::extents<int>>, + typename OLayout::mapping<std::extents<int>>> == Expected); + + static_assert(!has_op_eq< + typename SLayout::mapping<std::extents<int>>, + typename OLayout::mapping<std::extents<int, 1>>>); + + static_assert(has_op_eq< + typename SLayout::mapping<std::extents<int, 1>>, + typename OLayout::mapping<std::extents<int, 1>>> == Expected); + + static_assert(has_op_eq< + typename SLayout::mapping<std::extents<int, 1>>, + typename OLayout::mapping<std::extents<int, 2>>> == Expected); + + static_assert(!has_op_eq< + typename SLayout::mapping<std::extents<int, 1>>, + typename OLayout::mapping<std::extents<int, 1, 2>>>); + + static_assert(has_op_eq< + typename SLayout::mapping<std::extents<int, 1, 2>>, + typename OLayout::mapping<std::extents<int, 1, 2>>> == Expected); + + static_assert(has_op_eq< + typename SLayout::mapping<std::extents<int, 1, 2>>, + typename OLayout::mapping<std::extents<int, 2, 2>>> == Expected); + + static_assert(!has_op_eq< + typename SLayout::mapping<std::extents<int, 1, 2>>, + typename OLayout::mapping<std::extents<int, 1, 2, 3>>>); + } + +constexpr void +test_has_op_eq_peculiar() +{ + static_assert(has_op_eq< + std::layout_right::mapping<std::extents<int>>, + std::layout_left::mapping<std::extents<unsigned int>>>); + + static_assert(has_op_eq< + std::layout_right::mapping<std::extents<int, 1>>, + std::layout_left::mapping<std::extents<int, dyn>>>); + + static_assert(!has_op_eq< + std::layout_right::mapping<std::extents<int, 1, 2>>, + std::layout_left::mapping<std::extents<int, dyn, 2>>>); +} + +template<typename Layout> + constexpr bool + test_mapping_all() + { + test_linear_index_all<Layout>(); + test_required_span_size_all<Layout>(); + test_stride_all<Layout>(); + + test_eq<Layout>(); + test_eq_zero<Layout>(); + return true; + } + +template<typename Layout> + constexpr void + test_all() + { + static_assert(std::is_trivially_default_constructible_v<Layout>); + static_assert(std::is_trivially_copyable_v<Layout>); + static_assert(test_mapping_properties_all<Layout>()); + + test_mapping_all<Layout>(); + static_assert(test_mapping_all<Layout>()); + + test_has_stride_0d<Layout>(); + test_has_stride_1d<Layout>(); + test_has_stride_2d<Layout>(); + test_has_op_eq<Layout, Layout, true>(); + } + +int +main() +{ + test_all<std::layout_left>(); + test_all<std::layout_right>(); + test_all<std::layout_stride>(); + + test_has_op_eq<std::layout_right, std::layout_left, false>(); + test_has_op_eq<std::layout_right, std::layout_stride, true>(); + test_has_op_eq<std::layout_left, std::layout_stride, true>(); + test_has_op_eq_peculiar(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/stride.cc b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/stride.cc new file mode 100644 index 0000000..c8af5c6 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/stride.cc @@ -0,0 +1,526 @@ +// { dg-do run { target c++23 } } +#include <mdspan> + +#include <testsuite_hooks.h> + +constexpr size_t dyn = std::dynamic_extent; + +template<typename MappingStride> + constexpr void + test_ctor_default_stride() + { + using Extents = typename MappingStride::extents_type; + MappingStride actual; + typename std::layout_right::mapping<Extents> expected; + + constexpr auto rank = MappingStride::extents_type::rank(); + if constexpr (rank > 0) + for(size_t i = 0; i < rank; ++i) + VERIFY(actual.stride(i) == expected.stride(i)); + } + +constexpr bool +test_ctor_default_stride_all() +{ + test_ctor_default_stride< + std::layout_stride::mapping<std::extents<int, 3>>>(); + + test_ctor_default_stride< + std::layout_stride::mapping<std::extents<int, 3, 5, 7>>>(); + + test_ctor_default_stride< + std::layout_stride::mapping<std::dextents<int, 3>>>(); + + test_ctor_default_stride< + std::layout_stride::mapping<std::extents<int, 0, 5, 7>>>(); + + test_ctor_default_stride< + std::layout_stride::mapping<std::extents<int, 3, dyn, dyn>>>(); + + test_ctor_default_stride< + std::layout_stride::mapping<std::extents<int, dyn, dyn, 3>>>(); + return true; +} + +struct IntLikeA +{ + operator int() + { return 0; } +}; + +struct IntLikeB +{ + operator int() noexcept + { return 0; } +}; + +struct NotIntLike +{ }; + +template<typename E, typename E_arg, typename T, size_t N, bool Expected> +constexpr void +test_stride_constructible() +{ + static_assert(std::is_nothrow_constructible_v< + std::layout_stride::mapping<E>, E_arg, std::span<T, N>> == Expected); + static_assert(std::is_nothrow_constructible_v< + std::layout_stride::mapping<E>, E_arg, std::array<T, N>> == Expected); + static_assert(!std::is_constructible_v<std::layout_stride::mapping<E>, + E_arg>); +} + +constexpr void +test_stride_constructible_all() +{ + using E0 = std::extents<int>; + using E1 = std::extents<int, 2>; + using E2 = std::extents<int, dyn>; + + test_stride_constructible<E0, E0, int, 0, true>(); + test_stride_constructible<E0, E0, IntLikeA, 0, false>(); + test_stride_constructible<E0, E0, IntLikeB, 0, true>(); + test_stride_constructible<E0, E0, NotIntLike, 0, false>(); + test_stride_constructible<E1, E1, int, 1, true>(); + test_stride_constructible<E2, E1, int, 1, true>(); + test_stride_constructible<E1, E1, int, 2, false>(); + test_stride_constructible<E1, E0, int, 1, false>(); +} + +template<typename Extents, typename Shape> + constexpr void + test_ctor_shape_strides(Extents exts, Shape strides) + { + using M = std::layout_stride::mapping<Extents>; + M m(exts, strides); + + if constexpr (Extents::rank() > 0) + for(size_t i = 0; i < exts.rank(); ++i) + { + VERIFY(m.stride(i) == strides[i]); + VERIFY(m.extents().extent(i) == exts.extent(i)); + } + } + +constexpr bool +test_ctor_shape_stride_all() +{ + test_ctor_shape_strides(std::extents<int>{}, std::array<int, 0>{}); + test_ctor_shape_strides(std::extents<int, 2>{}, std::array<int, 1>{3}); + test_ctor_shape_strides(std::extents<int, 2, 4, 6>{}, + std::array<int, 3>{20, 5, 45}); + return true; +} + +template<typename Extents, std::array<bool, 2> Strided, + std::array<bool, 2> Unique, std::array<bool, 2> Exhautive, + typename Extents::index_type Offset = 0> + struct MappingLike + { + using extents_type = Extents; + using index_type = typename Extents::index_type; + + constexpr + MappingLike(extents_type extents, + std::array<index_type, Extents::rank()> strides) + : _extents(extents), _strides(strides) + { } + + static constexpr bool + is_always_strided() requires (Strided[0]) + { return Strided[1]; } + + static constexpr bool + is_always_unique() requires (Unique[0]) + { return Unique[1]; } + + static constexpr bool + is_always_exhaustive() requires (Exhautive[0]) + { return Exhautive[1]; } + + constexpr Extents + extents() const { return _extents; } + + constexpr index_type + stride(size_t i) const { return _strides[i]; } + + template<typename... Indices> + constexpr index_type + operator()(Indices... indices) const + { + if (empty()) + VERIFY(false); + + std::array<index_type, Extents::rank()> ind_arr{indices...}; + index_type ret = Offset; + for(size_t i = 0; i < Extents::rank(); ++i) + ret += ind_arr[i]*_strides[i]; + return ret; + } + + private: + constexpr bool + empty() const + { + for (size_t i = 0; i < extents_type::rank(); ++i) + if (_extents.extent(i) == 0) + return true; + return false; + } + + Extents _extents; + std::array<index_type, Extents::rank()> _strides; + }; + + +template<size_t Rank> +struct ExtentLike +{ + using index_type = int; + + static constexpr size_t + rank() { return Rank; } +}; + + +template<typename E1> +constexpr void +test_mapping_like_constructible() +{ + using M = std::layout_stride::mapping<E1>; + using E2 = std::dextents<typename E1::index_type, E1::rank()>; + using E3 = std::dextents<typename E1::index_type, E1::rank() + 1>; + using E4 = ExtentLike<E1::rank()>; + + constexpr auto TT = std::array{true, true}; + constexpr auto FT = std::array{false, true}; + constexpr auto TF = std::array{true, false}; + + static_assert(std::is_constructible_v<M, MappingLike<E1, TT, TT, TT>>); + static_assert(std::is_constructible_v<M, MappingLike<E2, TT, TT, TT>>); + static_assert(!std::is_constructible_v<M, MappingLike<E3, TT, TT, TT>>); + static_assert(!std::is_constructible_v<M, MappingLike<E1, FT, TT, TT>>); + static_assert(!std::is_constructible_v<M, MappingLike<E1, TF, TT, TT>>); + static_assert(!std::is_constructible_v<M, MappingLike<E1, TT, FT, TT>>); + static_assert(!std::is_constructible_v<M, MappingLike<E1, TT, TF, TT>>); + static_assert(!std::is_constructible_v<M, MappingLike<E1, TT, TT, FT>>); + static_assert(std::is_constructible_v<M, MappingLike<E1, TT, TT, TF>>); + static_assert(!std::is_constructible_v<M, MappingLike<E4, TT, TT, TF>>); + static_assert(!std::is_constructible_v<M, MappingLike<E4, TT, TT, TT>>); +} + +constexpr void +test_mapping_like_constructible_all() +{ + test_mapping_like_constructible<std::extents<int>>(); + test_mapping_like_constructible<std::extents<int, 2>>(); + test_mapping_like_constructible<std::extents<int, 2, 3>>(); +} + +template<typename E1, typename E2> +constexpr void +test_mapping_like_convertible() +{ + using M1 = std::layout_stride::mapping<E1>; + using M2 = std::layout_stride::mapping<E2>; + constexpr auto TT = std::array{true, true}; + + static_assert(!std::is_convertible_v<MappingLike<E1, TT, TT, TT>, M1>); + static_assert(!std::is_convertible_v<MappingLike<E2, TT, TT, TT>, M1>); + static_assert(!std::is_convertible_v<MappingLike<E1, TT, TT, TT>, M2>); + + static_assert(std::is_convertible_v<std::layout_stride::mapping<E2>, M1>); + static_assert(std::is_convertible_v<std::layout_left::mapping<E2>, M1>); + static_assert(std::is_convertible_v<std::layout_right::mapping<E2>, M1>); + + static_assert(!std::is_convertible_v<std::layout_stride::mapping<E1>, M2>); + static_assert(!std::is_convertible_v<std::layout_left::mapping<E1>, M2>); + static_assert(!std::is_convertible_v<std::layout_right::mapping<E1>, M2>); +} + +constexpr void +test_mapping_like_convertible_all() +{ + test_mapping_like_convertible<std::extents<unsigned int>, + std::extents<int>>(); + test_mapping_like_convertible<std::extents<unsigned int, 2>, + std::extents<int, 2>>(); + test_mapping_like_convertible<std::extents<int, dyn, 3>, + std::extents<int, 2, 3>>(); +} + +template<typename Extents> +constexpr void +test_ctor_stride_like(Extents exts, std::array<int, Extents::rank()> strides) +{ + auto other_right = std::layout_right::mapping(exts); + auto other_left = std::layout_left::mapping(exts); + auto other_stride = std::layout_stride::mapping(exts, strides); + + VERIFY(std::layout_stride::mapping<Extents>(other_right) == other_right); + VERIFY(std::layout_stride::mapping<Extents>(other_left) == other_left); + VERIFY(std::layout_stride::mapping<Extents>(other_stride) == other_stride); +} + +constexpr void +test_ctor_stride_like_all() +{ + using E1 = std::extents<int>; + auto s1 = std::array<int, 0>{}; + test_ctor_stride_like(E1{}, s1); + + using E2 = std::extents<int, 3>; + auto s2 = std::array<int, 1>{2}; + test_ctor_stride_like(E2{}, s2); + + using E3 = std::extents<int, 3, 5, 7>; + auto s3 = std::array<int, 3>{5, 1, 15}; + test_ctor_stride_like(E3{}, s3); +} + +constexpr bool +test_ctor_strides_all() +{ + test_ctor_default_stride_all(); + test_ctor_shape_stride_all(); + test_ctor_stride_like_all(); + return true; +} + +// Check is_exhaustive. +template<typename Extents, typename Strides> + constexpr void + test_is_exhaustive(Extents extents, Strides strides, bool expected) + { + std::layout_stride::mapping<Extents> m(extents, strides); + VERIFY(m.is_exhaustive() == expected); + + bool always_exhaustive = extents.rank() == 0 || m.required_span_size() == 0; + VERIFY(m.is_always_exhaustive() == always_exhaustive); + } + +constexpr void +test_is_exhaustive_zero_1d() +{ + std::extents<int, 0> extents; + test_is_exhaustive(extents, std::array{1}, true); + test_is_exhaustive(extents, std::array{2}, true); +} + +constexpr void +test_is_exhaustive_zero_3d() +{ + std::extents<int, 3, 0, 7> extents; + + test_is_exhaustive(extents, std::array{1, 1, 1}, true); + test_is_exhaustive(extents, std::array{1, 2*21, 2*3}, true); + test_is_exhaustive(extents, std::array{7, 2*21, 1}, true); + test_is_exhaustive(extents, std::array{1, 21, 3}, true); + test_is_exhaustive(extents, std::array{7, 21, 1}, true); +} + +constexpr void +test_is_exhaustive_0d() +{ + std::extents<int> extents; + test_is_exhaustive(extents, std::array<int, 0>{}, true); +} + +constexpr void +test_is_exhaustive_1d() +{ + std::extents<int, 3> extents; + test_is_exhaustive(extents, std::array{1}, true); + test_is_exhaustive(extents, std::array{3}, false); +} + + +constexpr void +test_is_exhaustive_3d() +{ + std::extents<int, 3, dyn, 7> extents(5); + + test_is_exhaustive(extents, std::array{1, 3, 3*5}, true); + test_is_exhaustive(extents, std::array{5*7, 1, 5}, true); + test_is_exhaustive(extents, std::array{7, 3*7, 1}, true); + + test_is_exhaustive(extents, std::array{1, 3, 2*3*5}, false); + test_is_exhaustive(extents, std::array{2*5*7, 1, 2*5}, false); + test_is_exhaustive(extents, std::array{2*7, 2*3*7, 2}, false); +} + +constexpr void +test_is_exhaustive_ones() +{ + std::extents<int, 1, 1, 3, 1> extents; + test_is_exhaustive(extents, std::array{1, 1, 1, 1}, true); + test_is_exhaustive(extents, std::array{1, 1, 1, 3}, true); + test_is_exhaustive(extents, std::array{3, 3, 1, 3}, true); + test_is_exhaustive(extents, std::array{3, 1, 1, 3}, true); +} + +constexpr bool +test_is_exhaustive_all() +{ + test_is_exhaustive_zero_1d(); + test_is_exhaustive_zero_3d(); + test_is_exhaustive_ones(); + test_is_exhaustive_0d(); + test_is_exhaustive_1d(); + test_is_exhaustive_3d(); + return true; +} + +template<typename Extents, int Offset> + using OffsetMapping = MappingLike<Extents, {true, true}, {true, true}, + {true, false}, Offset>; + +template<typename Extents> + constexpr void + test_eq(Extents exts, + std::array<typename Extents::index_type, Extents::rank()> left_strides, + std::array<typename Extents::index_type, Extents::rank()> right_strides, + std::array<typename Extents::index_type, Extents::rank()> padded_strides) + { + using DExtents = std::dextents<int, Extents::rank()>; + + std::layout_left::mapping<Extents> ml; + std::layout_right::mapping<DExtents> mr(exts); + + std::layout_stride::mapping<Extents> msd; + std::layout_stride::mapping<Extents> msl(exts, left_strides); + std::layout_stride::mapping<Extents> msr(exts, right_strides); + std::layout_stride::mapping<Extents> msp(exts, padded_strides); + + OffsetMapping<Extents, 0> mor{exts, right_strides}; + OffsetMapping<Extents, 0> mol{exts, left_strides}; + OffsetMapping<Extents, 0> mop{exts, padded_strides}; + OffsetMapping<Extents, 1> moo{exts, right_strides}; + + VERIFY(msd == mr); + VERIFY(msd == mor); + VERIFY(msd != msp); + VERIFY(msd != mop); + + VERIFY(msl == ml); + VERIFY(msl == mol); + VERIFY(msd != msp); + VERIFY(msl != mop); + + VERIFY(msp == mop); + VERIFY(msp != ml); + VERIFY(msp != mr); + + VERIFY(msd != moo); + } + +constexpr void +test_eq_0d() +{ + using Extents = std::extents<int>; + Extents exts; + std::layout_left::mapping<Extents> ml; + std::layout_right::mapping<Extents> mr; + std::layout_stride::mapping<Extents> ms; + OffsetMapping<Extents, 0> mor{exts, {}}; + OffsetMapping<Extents, 1> moo{exts, {}}; + + VERIFY(ms == ml); + VERIFY(ms == mr); + VERIFY(ms == mor); + VERIFY(ms != moo); +} + +constexpr void +test_eq_1d() +{ + using Extents = std::extents<int, 2>; + auto exhaustive_strides = std::array{1}; + auto padded_strides = std::array{2}; + + test_eq(Extents{}, exhaustive_strides, exhaustive_strides, padded_strides); +} + +constexpr void +test_eq_2d() +{ + using Extents = std::extents<int, 1, 2>; + auto left_strides = std::array{1, 1}; + auto right_strides = std::array{2, 1}; + auto padded_strides = std::array{2, 8}; + + test_eq(Extents{}, left_strides, right_strides, padded_strides); +} + +constexpr void +test_eq_zero() +{ + using Extents = std::extents<int, 0, 2>; + using Mapping = std::layout_stride::mapping<Extents>; + + Extents exts; + std::array<int, 2> sl{1, 5}; + std::array<int, 2> sr{5, 1}; + + Mapping m1(exts, sl); + Mapping m2(exts, sl); + Mapping m3(exts, sr); + OffsetMapping<Extents, 0> m4(exts, sl); + + VERIFY(m1 == m2); + VERIFY(m1 != m3); + VERIFY(m1 == m4); + +} + +constexpr bool +test_eq_all() +{ + test_eq_0d(); + test_eq_1d(); + test_eq_2d(); + test_eq_zero(); + return true; +} + +template<typename M1, typename M2> + concept has_op_eq = requires (M1 m1, M2 m2) + { + { m1 == m2 } -> std::same_as<bool>; + { m2 == m1 } -> std::same_as<bool>; + { m1 != m2 } -> std::same_as<bool>; + { m2 != m1 } -> std::same_as<bool>; + }; + +constexpr void +test_has_op_eq() +{ + using E1 = std::extents<int>; + using E2 = std::extents<int, 2>; + using E3 = std::extents<int, 1, 2>; + constexpr auto FT = std::array{false, true}; + + static_assert(!has_op_eq< + std::layout_stride::mapping<E1>, MappingLike<E1, FT, FT, FT>>); + + static_assert(!has_op_eq< + std::layout_stride::mapping<E2>, MappingLike<E2, FT, FT, FT>>); + + static_assert(!has_op_eq< + std::layout_stride::mapping<E3>, MappingLike<E3, FT, FT, FT>>); +} + +int +main() +{ + test_ctor_strides_all(); + static_assert(test_ctor_strides_all()); + test_mapping_like_convertible_all(); + test_mapping_like_constructible_all(); + test_stride_constructible_all(); + test_is_exhaustive_all(); + static_assert(test_is_exhaustive_all()); + test_eq_all(); + static_assert(test_eq_all()); + test_has_op_eq(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/multimap/48101_neg.cc b/libstdc++-v3/testsuite/23_containers/multimap/48101_neg.cc index f597ef3..1c1c79d 100644 --- a/libstdc++-v3/testsuite/23_containers/multimap/48101_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/multimap/48101_neg.cc @@ -28,8 +28,8 @@ test01() c2.find(2); // { dg-error "here" } } -// { dg-error "_Compare = std::(__8::)?less<int.>" "" { target *-*-* } 0 } -// { dg-error "_Compare = std::(__8::)?allocator<int>" "" { target *-*-* } 0 } +// { dg-error "_Compare = std::less<int.>" "" { target *-*-* } 0 } +// { dg-error "_Compare = std::allocator<int>" "" { target *-*-* } 0 } // { dg-error "comparison object must be invocable" "" { target *-*-* } 0 } // { dg-prune-output "no match for call" } // { dg-prune-output "invalid conversion" } diff --git a/libstdc++-v3/testsuite/23_containers/multimap/cons/deduction.cc b/libstdc++-v3/testsuite/23_containers/multimap/cons/deduction.cc index f0699e2..de5e6ac 100644 --- a/libstdc++-v3/testsuite/23_containers/multimap/cons/deduction.cc +++ b/libstdc++-v3/testsuite/23_containers/multimap/cons/deduction.cc @@ -210,3 +210,49 @@ test_p1518r2() std::multimap s2(std::move(m), p); check_type<MMap>(s2); } + +struct MyPred +{ + template<typename T, typename U> + bool operator()(T const&, U const&) const; +}; + +template<typename K, typename V> +constexpr bool test_lwg4223() +{ + using KD = std::remove_cv_t<std::remove_reference_t<K>>; + using VD = std::remove_cv_t<std::remove_reference_t<V>>; + using Alloc = __gnu_test::SimpleAllocator<std::pair<const KD, VD>>; + + std::initializer_list<std::pair<K, V>> il = {}; + Alloc a; + MyPred p; + + // The remove_cvref_t is not applied here. + // static_assert(std::is_same_v< + // decltype(std::multimap(il)), + // std::multimap<KD, VD>>); + + static_assert(std::is_same_v< + decltype(std::multimap(il.begin(), il.end())), + std::multimap<KD, VD>>); + + static_assert(std::is_same_v< + decltype(std::multimap(il.begin(), il.end(), p)), + std::multimap<KD, VD, MyPred>>); + + static_assert(std::is_same_v< + decltype(std::multimap(il.begin(), il.end(), a)), + std::multimap<KD, VD, std::less<KD>, Alloc>>); + + static_assert(std::is_same_v< + decltype(std::multimap(il.begin(), il.end(), p, a)), + std::multimap<KD, VD, MyPred, Alloc>>); + + return true; +} + +static_assert(test_lwg4223<const int, const float>()); +static_assert(test_lwg4223<int&, float&>()); +static_assert(test_lwg4223<int&&, float&&>()); +static_assert(test_lwg4223<const int&, const float&>()); diff --git a/libstdc++-v3/testsuite/23_containers/multimap/cons/from_range.cc b/libstdc++-v3/testsuite/23_containers/multimap/cons/from_range.cc index 3e456f5..5907bab 100644 --- a/libstdc++-v3/testsuite/23_containers/multimap/cons/from_range.cc +++ b/libstdc++-v3/testsuite/23_containers/multimap/cons/from_range.cc @@ -1,7 +1,12 @@ // { dg-do run { target c++23 } } -#include <algorithm> #include <map> + +#if __cpp_lib_containers_ranges != 202202L +# error "Feature-test macro __cpp_lib_containers_ranges has wrong value in <map>" +#endif + +#include <algorithm> #include <ranges> #include <span> #include <testsuite_allocator.h> @@ -38,11 +43,11 @@ test_deduction_guide() __gnu_test::test_input_range<std::pair<const long, const float>> r2(0, 0); std::multimap m5(std::from_range, r2); - static_assert(std::is_same_v<decltype(m5), std::multimap<long, const float>>); + static_assert(std::is_same_v<decltype(m5), std::multimap<long, float>>); - // LWG4223: deduces multimap<const long&, float&> - //__gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, 0); - // std::multimap m6(std::from_range, r3); + __gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, 0); + std::multimap m6(std::from_range, r3); + static_assert(std::is_same_v<decltype(m6), std::multimap<long, float>>); __gnu_test::test_input_range<std::tuple<long, float>> r4(0, 0); std::multimap m7(std::from_range, r4); diff --git a/libstdc++-v3/testsuite/23_containers/multiset/48101_neg.cc b/libstdc++-v3/testsuite/23_containers/multiset/48101_neg.cc index f0786cf..3cc0658 100644 --- a/libstdc++-v3/testsuite/23_containers/multiset/48101_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/multiset/48101_neg.cc @@ -29,7 +29,6 @@ test01() // { dg-error "non-const, non-volatile value_type" "" { target *-*-* } 0 } // { dg-error "comparison object must be invocable" "" { target *-*-* } 0 } -// { dg-prune-output "std::allocator<.* has no member named " } // { dg-prune-output "must have the same value_type as its allocator" } // { dg-prune-output "no match for call" } // { dg-prune-output "invalid conversion" } diff --git a/libstdc++-v3/testsuite/23_containers/multiset/cons/from_range.cc b/libstdc++-v3/testsuite/23_containers/multiset/cons/from_range.cc index 43821ca..cdba7eb 100644 --- a/libstdc++-v3/testsuite/23_containers/multiset/cons/from_range.cc +++ b/libstdc++-v3/testsuite/23_containers/multiset/cons/from_range.cc @@ -1,8 +1,13 @@ // { dg-do run { target c++23 } } +#include <set> + +#if __cpp_lib_containers_ranges != 202202L +# error "Feature-test macro __cpp_lib_containers_ranges has wrong value in <set>" +#endif + #include <algorithm> #include <ranges> -#include <set> #include <span> #include <testsuite_allocator.h> #include <testsuite_hooks.h> diff --git a/libstdc++-v3/testsuite/23_containers/priority_queue/cons_from_range.cc b/libstdc++-v3/testsuite/23_containers/priority_queue/cons_from_range.cc index 977ef98..87e404b 100644 --- a/libstdc++-v3/testsuite/23_containers/priority_queue/cons_from_range.cc +++ b/libstdc++-v3/testsuite/23_containers/priority_queue/cons_from_range.cc @@ -1,7 +1,12 @@ // { dg-do run { target c++23 } } -#include <algorithm> #include <queue> + +#if __cpp_lib_containers_ranges != 202202L +# error "Feature-test macro __cpp_lib_containers_ranges has wrong value in <queue>" +#endif + +#include <algorithm> #include <ranges> #include <span> #include <testsuite_allocator.h> diff --git a/libstdc++-v3/testsuite/23_containers/queue/cons_from_range.cc b/libstdc++-v3/testsuite/23_containers/queue/cons_from_range.cc index c21f52c..039d084 100644 --- a/libstdc++-v3/testsuite/23_containers/queue/cons_from_range.cc +++ b/libstdc++-v3/testsuite/23_containers/queue/cons_from_range.cc @@ -1,7 +1,12 @@ // { dg-do run { target c++23 } } -#include <list> #include <queue> + +#if __cpp_lib_containers_ranges != 202202L +# error "Feature-test macro __cpp_lib_containers_ranges has wrong value in <queue>" +#endif + +#include <list> #include <span> #include <testsuite_allocator.h> #include <testsuite_hooks.h> diff --git a/libstdc++-v3/testsuite/23_containers/set/48101_neg.cc b/libstdc++-v3/testsuite/23_containers/set/48101_neg.cc index e8dec72..fe38d1a 100644 --- a/libstdc++-v3/testsuite/23_containers/set/48101_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/set/48101_neg.cc @@ -29,7 +29,6 @@ test01() // { dg-error "non-const, non-volatile value_type" "" { target *-*-* } 0 } // { dg-error "comparison object must be invocable" "" { target *-*-* } 0 } -// { dg-prune-output "std::allocator<.* has no member named " } // { dg-prune-output "must have the same value_type as its allocator" } // { dg-prune-output "no match for call" } // { dg-prune-output "invalid conversion" } diff --git a/libstdc++-v3/testsuite/23_containers/set/cons/from_range.cc b/libstdc++-v3/testsuite/23_containers/set/cons/from_range.cc index 869326f..efde05d 100644 --- a/libstdc++-v3/testsuite/23_containers/set/cons/from_range.cc +++ b/libstdc++-v3/testsuite/23_containers/set/cons/from_range.cc @@ -1,8 +1,13 @@ // { dg-do run { target c++23 } } +#include <set> + +#if __cpp_lib_containers_ranges != 202202L +# error "Feature-test macro __cpp_lib_containers_ranges has wrong value in <set>" +#endif + #include <algorithm> #include <ranges> -#include <set> #include <span> #include <testsuite_allocator.h> #include <testsuite_hooks.h> diff --git a/libstdc++-v3/testsuite/23_containers/stack/cons_from_range.cc b/libstdc++-v3/testsuite/23_containers/stack/cons_from_range.cc index e957d0c..2ee52e1 100644 --- a/libstdc++-v3/testsuite/23_containers/stack/cons_from_range.cc +++ b/libstdc++-v3/testsuite/23_containers/stack/cons_from_range.cc @@ -1,8 +1,13 @@ // { dg-do run { target c++23 } } +#include <stack> + +#if __cpp_lib_containers_ranges != 202202L +# error "Feature-test macro __cpp_lib_containers_ranges has wrong value in <span>" +#endif + #include <ranges> #include <span> -#include <stack> #include <testsuite_allocator.h> #include <testsuite_hooks.h> #include <testsuite_iterators.h> diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/96088.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/96088.cc index c7dfd4f..0ec0bba 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_map/96088.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_map/96088.cc @@ -1,6 +1,6 @@ // { dg-do run { target c++17 } } // { dg-require-effective-target std_allocator_new } -// { dg-xfail-run-if "AIX operator new" { powerpc-ibm-aix* } } +// { dg-require-effective-target c++20 { target powerpc-ibm-aix* } } // Copyright (C) 2021-2025 Free Software Foundation, Inc. // diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/cons/66055.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/cons/66055.cc index c7a12c1..0f95976 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_map/cons/66055.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_map/cons/66055.cc @@ -27,7 +27,10 @@ using alloc_type = test_type::allocator_type; test_type h1(10, alloc_type()); test_type h2(10, hasher_type(), alloc_type()); -test_type h3(h1.begin(), h1.end(), 10, alloc_type()); -test_type h4(h1.begin(), h1.end(), 10, hasher_type(), alloc_type()); -test_type h5({ { 1, 1 } }, 10, alloc_type()); -test_type h6({ { 1, 1 } }, 10, hasher_type(), alloc_type()); +test_type h3(h1.begin(), h1.end(), alloc_type()); +test_type h4(h1.begin(), h1.end(), 10, alloc_type()); +test_type h5(h1.begin(), h1.end(), 10, hasher_type(), alloc_type()); +test_type h6({ { 1, 1 } }, alloc_type()); +test_type h7({ { 1, 1 } }, 10, alloc_type()); +test_type h8({ { 1, 1 } }, 10, hasher_type(), alloc_type()); + diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/cons/deduction.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/cons/deduction.cc index 8b69af8..26013da 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_map/cons/deduction.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_map/cons/deduction.cc @@ -16,12 +16,28 @@ static_assert(std::is_same_v< std::unordered_map<int, double>>); static_assert(std::is_same_v< + decltype(std::unordered_map{{std::pair{1, 2.0}, + {2, 3.0}, {3, 4.0}}, + SimpleAllocator<std::pair<const int, double>>{}}), + std::unordered_map<int, double, std::hash<int>, + std::equal_to<int>, + SimpleAllocator<std::pair<const int, double>>>>); + +static_assert(std::is_same_v< decltype(std::unordered_map{ {std::pair{1, 2.0}, {2, 3.0}, {3, 4.0}}, 1}), std::unordered_map<int, double>>); static_assert(std::is_same_v< + decltype(std::unordered_map{ + {std::pair{1, 2.0}, {2, 3.0}, {3, 4.0}}, + 1, SimpleAllocator<std::pair<const int, double>>{}}), + std::unordered_map<int, double, std::hash<int>, + std::equal_to<int>, + SimpleAllocator<std::pair<const int, double>>>>); + +static_assert(std::is_same_v< decltype(std::unordered_map{{std::pair{1, 2.0}, {2, 3.0}, {3, 4.0}}, {}, std::hash<int>{}, std::equal_to<int>{}}), @@ -98,6 +114,18 @@ void f() static_assert(std::is_same_v< decltype(std::unordered_map{x.begin(), x.end(), + std::allocator<std::pair<const int, double>>{}}), + std::unordered_map<int, double>>); + + static_assert(std::is_same_v< + decltype(std::unordered_map{x.begin(), x.end(), + SimpleAllocator<std::pair<const int, double>>{}}), + std::unordered_map<int, double, std::hash<int>, + std::equal_to<int>, + SimpleAllocator<std::pair<const int, double>>>>); + + static_assert(std::is_same_v< + decltype(std::unordered_map{x.begin(), x.end(), 1, std::hash<int>{}, std::allocator<std::pair<const int, double>>{}}), std::unordered_map<int, double>>); @@ -162,3 +190,72 @@ test_p1518r2() std::unordered_map s2(std::move(m), p); check_type<UMap>(s2); } + +struct MyHash +{ + template<typename T> + std::size_t operator()(T const&) const; +}; + +struct MyPred +{ + template<typename T, typename U> + bool operator()(T const&, U const&) const; +}; + +template<typename K, typename V> +constexpr bool test_lwg4223() +{ + using KD = std::remove_cv_t<std::remove_reference_t<K>>; + using VD = std::remove_cv_t<std::remove_reference_t<V>>; + using Alloc = __gnu_test::SimpleAllocator<std::pair<const KD, VD>>; + + std::initializer_list<std::pair<K, V>> il = {}; + Alloc a; + MyHash h; + MyPred p; + + // The remove_cvref_t is not applied here. + // static_assert(std::is_same_v< + // decltype(std::unordered_map(il)), + // std::unordered_map<KD, VD>>); + + static_assert(std::is_same_v< + decltype(std::unordered_map(il.begin(), il.end())), + std::unordered_map<KD, VD>>); + + static_assert(std::is_same_v< + decltype(std::unordered_map(il.begin(), il.end(), 0)), + std::unordered_map<KD, VD>>); + + static_assert(std::is_same_v< + decltype(std::unordered_map(il.begin(), il.end(), 0, h)), + std::unordered_map<KD, VD, MyHash>>); + + static_assert(std::is_same_v< + decltype(std::unordered_map(il.begin(), il.end(), 0, h, p)), + std::unordered_map<KD, VD, MyHash, MyPred>>); + + static_assert(std::is_same_v< + decltype(std::unordered_map(il.begin(), il.end(), a)), + std::unordered_map<KD, VD, std::hash<KD>, std::equal_to<KD>, Alloc>>); + + static_assert(std::is_same_v< + decltype(std::unordered_map(il.begin(), il.end(), 0, a)), + std::unordered_map<KD, VD, std::hash<KD>, std::equal_to<KD>, Alloc>>); + + static_assert(std::is_same_v< + decltype(std::unordered_map(il.begin(), il.end(), 0, h, a)), + std::unordered_map<KD, VD, MyHash, std::equal_to<KD>, Alloc>>); + + static_assert(std::is_same_v< + decltype(std::unordered_map(il.begin(), il.end(), 0, h, p, a)), + std::unordered_map<KD, VD, MyHash, MyPred, Alloc>>); + + return true; +} + +static_assert(test_lwg4223<const int, const float>()); +static_assert(test_lwg4223<int&, float&>()); +static_assert(test_lwg4223<int&&, float&&>()); +static_assert(test_lwg4223<const int&, const float&>()); diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/cons/from_range.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/cons/from_range.cc index 6d1da5b..04479a5e 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_map/cons/from_range.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_map/cons/from_range.cc @@ -1,7 +1,12 @@ // { dg-do run { target c++23 } } -#include <algorithm> #include <unordered_map> + +#if __cpp_lib_containers_ranges != 202202L +# error "Feature-test macro __cpp_lib_containers_ranges has wrong value in <unordered_map>" +#endif + +#include <algorithm> #include <span> #include <testsuite_allocator.h> #include <testsuite_hooks.h> @@ -73,13 +78,11 @@ test_deduction_guide() __gnu_test::test_input_range<std::pair<const long, const float>> r2(0, 0); std::unordered_map m9(std::from_range, r2); - static_assert(std::is_same_v< - decltype(m9), - std::unordered_map<long, const float>>); + static_assert(std::is_same_v<decltype(m9), std::unordered_map<long, float>>); - // LWG4223: deduces map<const long&, float&> - // __gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, 0); - // std::unordered_map m10(std::from_range, r3); + __gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, 0); + std::unordered_map m10(std::from_range, r3); + static_assert(std::is_same_v<decltype(m10), std::unordered_map<long, float>>); __gnu_test::test_input_range<std::tuple<long, float>> r4(0, 0); std::unordered_map m11(std::from_range, r4); diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_arrow_operator_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_arrow_operator_neg.cc new file mode 100644 index 0000000..09870a7 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_arrow_operator_neg.cc @@ -0,0 +1,17 @@ +// { dg-do run { target c++11 xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include <unordered_map> +#include <debug/unordered_checks.h> + +void test01() +{ + __gnu_test::invalid_local_iterator_arrow_operator + <std::unordered_map<int, int>>(); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_const_conversion_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_const_conversion_neg.cc new file mode 100644 index 0000000..7bfe3a8 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_const_conversion_neg.cc @@ -0,0 +1,17 @@ +// { dg-do run { target c++11 xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include <unordered_map> +#include <debug/unordered_checks.h> + +void test01() +{ + __gnu_test::invalid_local_iterator_const_conversion + <std::unordered_map<int, int>>(); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_copy_assignment_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_copy_assignment_neg.cc new file mode 100644 index 0000000..d3b671b --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_copy_assignment_neg.cc @@ -0,0 +1,17 @@ +// { dg-do run { target c++11 xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include <unordered_map> +#include <debug/unordered_checks.h> + +void test01() +{ + __gnu_test::invalid_local_iterator_copy_assignment + <std::unordered_map<int, int>>(); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_copy_construction_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_copy_construction_neg.cc new file mode 100644 index 0000000..d609671 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_copy_construction_neg.cc @@ -0,0 +1,17 @@ +// { dg-do run { target c++11 xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include <unordered_map> +#include <debug/unordered_checks.h> + +void test01() +{ + __gnu_test::invalid_local_iterator_copy_construction + <std::unordered_map<int, int>>(); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_move_assignment_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_move_assignment_neg.cc new file mode 100644 index 0000000..8d2ed6b --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_move_assignment_neg.cc @@ -0,0 +1,17 @@ +// { dg-do run { target c++11 xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include <unordered_map> +#include <debug/unordered_checks.h> + +void test01() +{ + __gnu_test::invalid_local_iterator_move_assignment + <std::unordered_map<int, int>>(); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_move_construction_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_move_construction_neg.cc new file mode 100644 index 0000000..dd9b7dc --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_move_construction_neg.cc @@ -0,0 +1,17 @@ +// { dg-do run { target c++11 xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include <unordered_map> +#include <debug/unordered_checks.h> + +void test01() +{ + __gnu_test::invalid_local_iterator_move_construction + <std::unordered_map<int, int>>(); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/debug/max_load_factor_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/max_load_factor_neg.cc index 7fbc453..2596798 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_map/debug/max_load_factor_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/max_load_factor_neg.cc @@ -22,7 +22,7 @@ void test01() { - std::unordered_multimap<int, int> um; + std::unordered_map<int, int> um; um.max_load_factor(-1.0f); } diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/96088.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/96088.cc index 6f94296..3c1de37 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_multimap/96088.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/96088.cc @@ -1,6 +1,6 @@ // { dg-do run { target c++17 } } // { dg-require-effective-target std_allocator_new } -// { dg-xfail-run-if "AIX operator new" { powerpc-ibm-aix* } } +// { dg-require-effective-target c++20 { target powerpc-ibm-aix* } } // Copyright (C) 2021-2025 Free Software Foundation, Inc. // diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/66055.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/66055.cc index dc0a651..eecc600 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/66055.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/66055.cc @@ -27,7 +27,9 @@ using alloc_type = test_type::allocator_type; test_type h1(10, alloc_type()); test_type h2(10, hasher_type(), alloc_type()); -test_type h3(h1.begin(), h1.end(), 10, alloc_type()); -test_type h4(h1.begin(), h1.end(), 10, hasher_type(), alloc_type()); -test_type h5({ { 1, 1 } }, 10, alloc_type()); -test_type h6({ { 1, 1 } }, 10, hasher_type(), alloc_type()); +test_type h3(h1.begin(), h1.end(), alloc_type()); +test_type h4(h1.begin(), h1.end(), 10, alloc_type()); +test_type h5(h1.begin(), h1.end(), 10, hasher_type(), alloc_type()); +test_type h6({ { 1, 1 } }, alloc_type()); +test_type h7({ { 1, 1 } }, 10, alloc_type()); +test_type h8({ { 1, 1 } }, 10, hasher_type(), alloc_type()); diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/deduction.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/deduction.cc index e7e535b..1db58a0 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/deduction.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/deduction.cc @@ -16,6 +16,28 @@ static_assert(std::is_same_v< std::unordered_multimap<int, double>>); static_assert(std::is_same_v< + decltype(std::unordered_multimap{ + {std::pair{1, 2.0}, {2, 3.0}, {3, 4.0}}, + SimpleAllocator<std::pair<const int, double>>{}}), + std::unordered_multimap<int, double, std::hash<int>, + std::equal_to<int>, + SimpleAllocator<std::pair<const int, double>>>>); + +static_assert(std::is_same_v< + decltype(std::unordered_multimap{ + {std::pair{1, 2.0}, {2, 3.0}, {3, 4.0}}, + 1}), + std::unordered_multimap<int, double>>); + +static_assert(std::is_same_v< + decltype(std::unordered_multimap{ + {std::pair{1, 2.0}, {2, 3.0}, {3, 4.0}}, + 1, SimpleAllocator<std::pair<const int, double>>{}}), + std::unordered_multimap<int, double, std::hash<int>, + std::equal_to<int>, + SimpleAllocator<std::pair<const int, double>>>>); + +static_assert(std::is_same_v< decltype(std::unordered_multimap{{std::pair{1, 2.0}, {2, 3.0}, {3, 4.0}}, {}, std::hash<int>{}, std::equal_to<int>{}}), @@ -107,6 +129,18 @@ void f() static_assert(std::is_same_v< decltype(std::unordered_multimap{x.begin(), x.end(), + std::allocator<std::pair<const int, double>>{}}), + std::unordered_multimap<int, double>>); + + static_assert(std::is_same_v< + decltype(std::unordered_multimap{x.begin(), x.end(), + SimpleAllocator<std::pair<const int, double>>{}}), + std::unordered_multimap<int, double, std::hash<int>, + std::equal_to<int>, + SimpleAllocator<std::pair<const int, double>>>>); + + static_assert(std::is_same_v< + decltype(std::unordered_multimap{x.begin(), x.end(), 1, std::hash<int>{}, std::allocator<std::pair<const int, double>>{}}), std::unordered_multimap<int, double>>); @@ -171,3 +205,72 @@ test_p1518r2() std::unordered_multimap s2(std::move(m), p); check_type<UMMap>(s2); } + +struct MyHash +{ + template<typename T> + std::size_t operator()(T const&) const; +}; + +struct MyPred +{ + template<typename T, typename U> + bool operator()(T const&, U const&) const; +}; + +template<typename K, typename V> +constexpr bool test_lwg4223() +{ + using KD = std::remove_cv_t<std::remove_reference_t<K>>; + using VD = std::remove_cv_t<std::remove_reference_t<V>>; + using Alloc = __gnu_test::SimpleAllocator<std::pair<const KD, VD>>; + + std::initializer_list<std::pair<K, V>> il = {}; + Alloc a; + MyHash h; + MyPred p; + + // The remove_cvref_t is not applied here. + // static_assert(std::is_same_v< + // decltype(std::unordered_multimap(il)), + // std::unordered_multimap<KD, VD>>); + + static_assert(std::is_same_v< + decltype(std::unordered_multimap(il.begin(), il.end())), + std::unordered_multimap<KD, VD>>); + + static_assert(std::is_same_v< + decltype(std::unordered_multimap(il.begin(), il.end(), 0)), + std::unordered_multimap<KD, VD>>); + + static_assert(std::is_same_v< + decltype(std::unordered_multimap(il.begin(), il.end(), 0, h)), + std::unordered_multimap<KD, VD, MyHash>>); + + static_assert(std::is_same_v< + decltype(std::unordered_multimap(il.begin(), il.end(), 0, h, p)), + std::unordered_multimap<KD, VD, MyHash, MyPred>>); + + static_assert(std::is_same_v< + decltype(std::unordered_multimap(il.begin(), il.end(), a)), + std::unordered_multimap<KD, VD, std::hash<KD>, std::equal_to<KD>, Alloc>>); + + static_assert(std::is_same_v< + decltype(std::unordered_multimap(il.begin(), il.end(), 0, a)), + std::unordered_multimap<KD, VD, std::hash<KD>, std::equal_to<KD>, Alloc>>); + + static_assert(std::is_same_v< + decltype(std::unordered_multimap(il.begin(), il.end(), 0, h, a)), + std::unordered_multimap<KD, VD, MyHash, std::equal_to<KD>, Alloc>>); + + static_assert(std::is_same_v< + decltype(std::unordered_multimap(il.begin(), il.end(), 0, h, p, a)), + std::unordered_multimap<KD, VD, MyHash, MyPred, Alloc>>); + + return true; +} + +static_assert(test_lwg4223<const int, const float>()); +static_assert(test_lwg4223<int&, float&>()); +static_assert(test_lwg4223<int&&, float&&>()); +static_assert(test_lwg4223<const int&, const float&>()); diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/from_range.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/from_range.cc index 2ca93d3..4567bd8 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/from_range.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/from_range.cc @@ -1,7 +1,12 @@ // { dg-do run { target c++23 } } -#include <algorithm> #include <unordered_map> + +#if __cpp_lib_containers_ranges != 202202L +# error "Feature-test macro __cpp_lib_containers_ranges has wrong value in <unordered_map>" +#endif + +#include <algorithm> #include <ranges> #include <span> #include <testsuite_allocator.h> @@ -81,11 +86,13 @@ test_deduction_guide() std::unordered_multimap m9(std::from_range, r2); static_assert(std::is_same_v< decltype(m9), - std::unordered_multimap<long, const float>>); + std::unordered_multimap<long, float>>); - // LWG4223: deduces map<const long&, float&> - // __gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, 0); - // std::unordered_multimap m10(std::from_range, r3); + __gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, 0); + std::unordered_multimap m10(std::from_range, r3); + static_assert(std::is_same_v< + decltype(m10), + std::unordered_multimap<long, float>>); __gnu_test::test_input_range<std::tuple<long, float>> r4(0, 0); std::unordered_multimap m11(std::from_range, r4); diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/begin2_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/begin2_neg.cc index ff787cf..b2d67fb 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/begin2_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/begin2_neg.cc @@ -22,8 +22,8 @@ void test01() { - std::unordered_map<int, int> um; - const std::unordered_map<int, int>& cum = um; + std::unordered_multimap<int, int> um; + const std::unordered_multimap<int, int>& cum = um; cum.begin(um.bucket_count()); } diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/bucket_size_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/bucket_size_neg.cc index b5ddb18..4d5cb84 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/bucket_size_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/bucket_size_neg.cc @@ -22,7 +22,7 @@ void test01() { - std::unordered_map<int, int> um; + std::unordered_multimap<int, int> um; um.bucket_size(um.bucket_count()); } diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/cbegin_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/cbegin_neg.cc index 5ba1da5..654d409 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/cbegin_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/cbegin_neg.cc @@ -22,7 +22,7 @@ void test01() { - std::unordered_map<int, int> um; + std::unordered_multimap<int, int> um; um.cbegin(um.bucket_count()); } diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/cend_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/cend_neg.cc index 031be37..f7149d4 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/cend_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/cend_neg.cc @@ -22,7 +22,7 @@ void test01() { - std::unordered_map<int, int> um; + std::unordered_multimap<int, int> um; um.cend(um.bucket_count()); } diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/end1_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/end1_neg.cc index d412fcf..fd0f981 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/end1_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/end1_neg.cc @@ -22,7 +22,7 @@ void test01() { - std::unordered_map<int, int> um; + std::unordered_multimap<int, int> um; um.end(um.bucket_count()); } diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/end2_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/end2_neg.cc index 0115351..0c3f86c 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/end2_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/end2_neg.cc @@ -22,8 +22,8 @@ void test01() { - std::unordered_map<int, int> um; - const std::unordered_map<int, int>& cum = um; + std::unordered_multimap<int, int> um; + const std::unordered_multimap<int, int>& cum = um; cum.end(um.bucket_count()); } diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_arrow_operator_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_arrow_operator_neg.cc new file mode 100644 index 0000000..8b23020 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_arrow_operator_neg.cc @@ -0,0 +1,17 @@ +// { dg-do run { target c++11 xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include <unordered_map> +#include <debug/unordered_checks.h> + +void test01() +{ + __gnu_test::invalid_local_iterator_arrow_operator + <std::unordered_multimap<int, int>>(); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_const_conversion_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_const_conversion_neg.cc new file mode 100644 index 0000000..62c0280 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_const_conversion_neg.cc @@ -0,0 +1,17 @@ +// { dg-do run { target c++11 xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include <unordered_map> +#include <debug/unordered_checks.h> + +void test01() +{ + __gnu_test::invalid_local_iterator_const_conversion + <std::unordered_multimap<int, int>>(); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_copy_assignment_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_copy_assignment_neg.cc new file mode 100644 index 0000000..9ac5b35 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_copy_assignment_neg.cc @@ -0,0 +1,17 @@ +// { dg-do run { target c++11 xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include <unordered_map> +#include <debug/unordered_checks.h> + +void test01() +{ + __gnu_test::invalid_local_iterator_copy_assignment + <std::unordered_multimap<int, int>>(); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_copy_construction_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_copy_construction_neg.cc new file mode 100644 index 0000000..4140272 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_copy_construction_neg.cc @@ -0,0 +1,17 @@ +// { dg-do run { target c++11 xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include <unordered_map> +#include <debug/unordered_checks.h> + +void test01() +{ + __gnu_test::invalid_local_iterator_copy_construction + <std::unordered_multimap<int, int>>(); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_move_assignment_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_move_assignment_neg.cc new file mode 100644 index 0000000..32c847c --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_move_assignment_neg.cc @@ -0,0 +1,17 @@ +// { dg-do run { target c++11 xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include <unordered_map> +#include <debug/unordered_checks.h> + +void test01() +{ + __gnu_test::invalid_local_iterator_move_assignment + <std::unordered_multimap<int, int>>(); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_move_construction_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_move_construction_neg.cc new file mode 100644 index 0000000..124b9ec --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_move_construction_neg.cc @@ -0,0 +1,17 @@ +// { dg-do run { target c++11 xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include <unordered_map> +#include <debug/unordered_checks.h> + +void test01() +{ + __gnu_test::invalid_local_iterator_move_construction + <std::unordered_multimap<int, int>>(); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/max_load_factor_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/max_load_factor_neg.cc index 2596798..7fbc453 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/max_load_factor_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/max_load_factor_neg.cc @@ -22,7 +22,7 @@ void test01() { - std::unordered_map<int, int> um; + std::unordered_multimap<int, int> um; um.max_load_factor(-1.0f); } diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multiset/96088.cc b/libstdc++-v3/testsuite/23_containers/unordered_multiset/96088.cc index 6f79ddf..c016c88 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_multiset/96088.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_multiset/96088.cc @@ -1,6 +1,6 @@ // { dg-do run { target c++17 } } // { dg-require-effective-target std_allocator_new } -// { dg-xfail-run-if "AIX operator new" { powerpc-ibm-aix* } } +// { dg-require-effective-target c++20 { target powerpc-ibm-aix* } } // Copyright (C) 2021-2025 Free Software Foundation, Inc. // diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/66055.cc b/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/66055.cc index 5c34b94..3ba609f 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/66055.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/66055.cc @@ -27,7 +27,9 @@ using alloc_type = test_type::allocator_type; test_type h1(10, alloc_type()); test_type h2(10, hasher_type(), alloc_type()); -test_type h3(h1.begin(), h1.end(), 10, alloc_type()); -test_type h4(h1.begin(), h1.end(), 10, hasher_type(), alloc_type()); -test_type h5({ 1, 1 }, 10, alloc_type()); -test_type h6({ 1, 1 }, 10, hasher_type(), alloc_type()); +test_type h3(h1.begin(), h1.end(), alloc_type()); +test_type h4(h1.begin(), h1.end(), 10, alloc_type()); +test_type h5(h1.begin(), h1.end(), 10, hasher_type(), alloc_type()); +test_type h6({ 1, 1 }, alloc_type()); +test_type h7({ 1, 1 }, 10, alloc_type()); +test_type h9({ 1, 1 }, 10, hasher_type(), alloc_type()); diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/deduction.cc b/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/deduction.cc index 22b7297..46cd210 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/deduction.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/deduction.cc @@ -20,6 +20,22 @@ static_assert(std::is_same_v< std::unordered_multiset<int>>); static_assert(std::is_same_v< + decltype(std::unordered_multiset{{1, 2, 3}}), + std::unordered_multiset<int>>); + +static_assert(std::is_same_v< + decltype(std::unordered_multiset{{1, 2, 3}, + std::allocator<int>{}}), + std::unordered_multiset<int>>); + +static_assert(std::is_same_v< + decltype(std::unordered_multiset{{1, 2, 3}, + SimpleAllocator<int>{}}), + std::unordered_multiset<int, std::hash<int>, + std::equal_to<int>, + SimpleAllocator<int>>>); + +static_assert(std::is_same_v< decltype(std::unordered_multiset{{1, 2, 3}, {}}), std::unordered_multiset<int>>); @@ -88,6 +104,18 @@ void f() static_assert(std::is_same_v< decltype(std::unordered_multiset{x.begin(), x.end(), + std::allocator<int>{}}), + std::unordered_multiset<int>>); + + static_assert(std::is_same_v< + decltype(std::unordered_multiset{x.begin(), x.end(), + SimpleAllocator<int>{}}), + std::unordered_multiset<int, std::hash<int>, + std::equal_to<int>, + SimpleAllocator<int>>>); + + static_assert(std::is_same_v< + decltype(std::unordered_multiset{x.begin(), x.end(), {}, std::hash<int>{}, std::allocator<int>{}}), std::unordered_multiset<int>>); diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/from_range.cc b/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/from_range.cc index 45c3848..d44598d 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/from_range.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/from_range.cc @@ -1,7 +1,12 @@ // { dg-do run { target c++23 } } -#include <algorithm> #include <unordered_set> + +#if __cpp_lib_containers_ranges != 202202L +# error "Feature-test macro __cpp_lib_containers_ranges has wrong value in <unordered_set>" +#endif + +#include <algorithm> #include <ranges> #include <span> #include <testsuite_allocator.h> diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_arrow_operator_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_arrow_operator_neg.cc new file mode 100644 index 0000000..1677b20 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_arrow_operator_neg.cc @@ -0,0 +1,17 @@ +// { dg-do run { target c++11 xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include <unordered_set> +#include <debug/unordered_checks.h> + +void test01() +{ + __gnu_test::invalid_local_iterator_arrow_operator + <std::unordered_multiset<int>>(); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_const_conversion_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_const_conversion_neg.cc new file mode 100644 index 0000000..0d64a41 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_const_conversion_neg.cc @@ -0,0 +1,17 @@ +// { dg-do run { target c++11 xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include <unordered_set> +#include <debug/unordered_checks.h> + +void test01() +{ + __gnu_test::invalid_local_iterator_const_conversion + <std::unordered_multiset<int>>(); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_copy_assignment_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_copy_assignment_neg.cc new file mode 100644 index 0000000..b0d7b9f --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_copy_assignment_neg.cc @@ -0,0 +1,17 @@ +// { dg-do run { target c++11 xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include <unordered_set> +#include <debug/unordered_checks.h> + +void test01() +{ + __gnu_test::invalid_local_iterator_copy_assignment + <std::unordered_multiset<int>>(); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_copy_construction_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_copy_construction_neg.cc new file mode 100644 index 0000000..fa9c5ee --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_copy_construction_neg.cc @@ -0,0 +1,17 @@ +// { dg-do run { target c++11 xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include <unordered_set> +#include <debug/unordered_checks.h> + +void test01() +{ + __gnu_test::invalid_local_iterator_copy_construction + <std::unordered_multiset<int>>(); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_move_assignment_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_move_assignment_neg.cc new file mode 100644 index 0000000..b25fedc --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_move_assignment_neg.cc @@ -0,0 +1,17 @@ +// { dg-do run { target c++11 xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include <unordered_set> +#include <debug/unordered_checks.h> + +void test01() +{ + __gnu_test::invalid_local_iterator_move_assignment + <std::unordered_multiset<int>>(); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_move_construction_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_move_construction_neg.cc new file mode 100644 index 0000000..8b855b2 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_move_construction_neg.cc @@ -0,0 +1,17 @@ +// { dg-do run { target c++11 xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include <unordered_set> +#include <debug/unordered_checks.h> + +void test01() +{ + __gnu_test::invalid_local_iterator_move_construction + <std::unordered_multiset<int>>(); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/96088.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/96088.cc index c09e6f7..10838c4 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_set/96088.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_set/96088.cc @@ -1,6 +1,6 @@ // { dg-do run { target c++17 } } // { dg-require-effective-target std_allocator_new } -// { dg-xfail-run-if "AIX operator new" { powerpc-ibm-aix* } } +// { dg-require-effective-target c++20 { target powerpc-ibm-aix* } } // Copyright (C) 2021-2025 Free Software Foundation, Inc. // diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/cons/66055.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/cons/66055.cc index 0d318a0..96c0ca3 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_set/cons/66055.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_set/cons/66055.cc @@ -27,7 +27,9 @@ using alloc_type = test_type::allocator_type; test_type h1(10, alloc_type()); test_type h2(10, hasher_type(), alloc_type()); -test_type h3(h1.begin(), h1.end(), 10, alloc_type()); -test_type h4(h1.begin(), h1.end(), 10, hasher_type(), alloc_type()); -test_type h5({ 1, 1 }, 10, alloc_type()); -test_type h6({ 1, 1 }, 10, hasher_type(), alloc_type()); +test_type h3(h1.begin(), h1.end(), alloc_type()); +test_type h4(h1.begin(), h1.end(), 10, alloc_type()); +test_type h5(h1.begin(), h1.end(), 10, hasher_type(), alloc_type()); +test_type h6({ 1, 1 }, alloc_type()); +test_type h7({ 1, 1 }, 10, alloc_type()); +test_type h9({ 1, 1 }, 10, hasher_type(), alloc_type()); diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/cons/deduction.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/cons/deduction.cc index db58581..9558d70 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_set/cons/deduction.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_set/cons/deduction.cc @@ -20,6 +20,22 @@ static_assert(std::is_same_v< std::unordered_set<int>>); static_assert(std::is_same_v< + decltype(std::unordered_set{{1, 2, 3}}), + std::unordered_set<int>>); + +static_assert(std::is_same_v< + decltype(std::unordered_set{{1, 2, 3}, + std::allocator<int>{}}), + std::unordered_set<int>>); + +static_assert(std::is_same_v< + decltype(std::unordered_set{{1, 2, 3}, + SimpleAllocator<int>{}}), + std::unordered_set<int, std::hash<int>, + std::equal_to<int>, + SimpleAllocator<int>>>); + +static_assert(std::is_same_v< decltype(std::unordered_set{{1, 2, 3}, {}}), std::unordered_set<int>>); @@ -92,6 +108,18 @@ void f() std::unordered_set<int>>); static_assert(std::is_same_v< + decltype(std::unordered_set{x.begin(), x.end(), + std::allocator<int>{}}), + std::unordered_set<int>>); + + static_assert(std::is_same_v< + decltype(std::unordered_set{x.begin(), x.end(), + SimpleAllocator<int>{}}), + std::unordered_set<int, std::hash<int>, + std::equal_to<int>, + SimpleAllocator<int>>>); + + static_assert(std::is_same_v< decltype(std::unordered_set{x.begin(), x.end(), 1}), std::unordered_set<int>>); diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/cons/from_range.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/cons/from_range.cc index 0806045..8259be8 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_set/cons/from_range.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_set/cons/from_range.cc @@ -1,7 +1,12 @@ // { dg-do run { target c++23 } } -#include <algorithm> #include <unordered_set> + +#if __cpp_lib_containers_ranges != 202202L +# error "Feature-test macro __cpp_lib_containers_ranges has wrong value in <unordered_set>" +#endif + +#include <algorithm> #include <span> #include <testsuite_allocator.h> #include <testsuite_hooks.h> diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_arrow_operator_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_arrow_operator_neg.cc new file mode 100644 index 0000000..f62ed6b --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_arrow_operator_neg.cc @@ -0,0 +1,17 @@ +// { dg-do run { target c++11 xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include <unordered_set> +#include <debug/unordered_checks.h> + +void test01() +{ + __gnu_test::invalid_local_iterator_arrow_operator + <std::unordered_set<int>>(); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_const_conversion_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_const_conversion_neg.cc new file mode 100644 index 0000000..839f9ae --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_const_conversion_neg.cc @@ -0,0 +1,17 @@ +// { dg-do run { target c++11 xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include <unordered_set> +#include <debug/unordered_checks.h> + +void test01() +{ + __gnu_test::invalid_local_iterator_const_conversion + <std::unordered_set<int>>(); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_copy_assignment_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_copy_assignment_neg.cc new file mode 100644 index 0000000..377019f --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_copy_assignment_neg.cc @@ -0,0 +1,17 @@ +// { dg-do run { target c++11 xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include <unordered_set> +#include <debug/unordered_checks.h> + +void test01() +{ + __gnu_test::invalid_local_iterator_copy_assignment + <std::unordered_set<int>>(); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_copy_construction_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_copy_construction_neg.cc new file mode 100644 index 0000000..1f7e6dd --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_copy_construction_neg.cc @@ -0,0 +1,17 @@ +// { dg-do run { target c++11 xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include <unordered_set> +#include <debug/unordered_checks.h> + +void test01() +{ + __gnu_test::invalid_local_iterator_copy_construction + <std::unordered_set<int>>(); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_move_assignment_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_move_assignment_neg.cc new file mode 100644 index 0000000..d16a154 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_move_assignment_neg.cc @@ -0,0 +1,17 @@ +// { dg-do run { target c++11 xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include <unordered_set> +#include <debug/unordered_checks.h> + +void test01() +{ + __gnu_test::invalid_local_iterator_move_assignment + <std::unordered_set<int>>(); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_move_construction_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_move_construction_neg.cc new file mode 100644 index 0000000..d878abf --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_move_construction_neg.cc @@ -0,0 +1,17 @@ +// { dg-do run { target c++11 xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include <unordered_set> +#include <debug/unordered_checks.h> + +void test01() +{ + __gnu_test::invalid_local_iterator_move_construction + <std::unordered_set<int>>(); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/vector/allocator/default_init.cc b/libstdc++-v3/testsuite/23_containers/vector/allocator/default_init.cc index 195cd2d..486c44c 100644 --- a/libstdc++-v3/testsuite/23_containers/vector/allocator/default_init.cc +++ b/libstdc++-v3/testsuite/23_containers/vector/allocator/default_init.cc @@ -59,6 +59,17 @@ void test02() tmp->~test_type(); } +#ifdef __cpp_lib_constexpr_vector +constexpr bool +test03() +{ + using alloc_type = default_init_allocator<T>; + std::vector<T, alloc_type> v; + return v.get_allocator().state == 0; +} +static_assert( test03() ); +#endif + int main() { test01(); diff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/allocator/default_init.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/allocator/default_init.cc index 3914b7f..c95cb6b 100644 --- a/libstdc++-v3/testsuite/23_containers/vector/bool/allocator/default_init.cc +++ b/libstdc++-v3/testsuite/23_containers/vector/bool/allocator/default_init.cc @@ -59,6 +59,17 @@ void test02() tmp->~test_type(); } +#ifdef __cpp_lib_constexpr_vector +constexpr bool +test03() +{ + using alloc_type = default_init_allocator<T>; + std::vector<T, alloc_type> v; + return v.get_allocator().state == 0; +} +static_assert( test03() ); +#endif + int main() { test01(); diff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/cons/from_range.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/cons/from_range.cc index 37f0ecf..339c06bd 100644 --- a/libstdc++-v3/testsuite/23_containers/vector/bool/cons/from_range.cc +++ b/libstdc++-v3/testsuite/23_containers/vector/bool/cons/from_range.cc @@ -1,5 +1,11 @@ // { dg-do run { target c++23 } } +#include <unordered_set> + +#if __cpp_lib_containers_ranges != 202202L +# error "Feature-test macro __cpp_lib_containers_ranges has wrong value in <unordered_set>" +#endif + #include <vector> #include <span> #include <testsuite_hooks.h> diff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/format.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/format.cc new file mode 100644 index 0000000..cecc535 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/vector/bool/format.cc @@ -0,0 +1,72 @@ +// { dg-do run { target c++23 } } +// { dg-timeout-factor 2 } + +#include <format> +#include <vector> +#include <testsuite_hooks.h> + +static_assert(!std::formattable<std::vector<bool>::reference, int>); +static_assert(!std::formattable<std::vector<bool>::reference, char32_t>); + +template<typename... Args> +bool +is_format_string_for(const char* str, Args&&... args) +{ + try { + (void) std::vformat(str, std::make_format_args(args...)); + return true; + } catch (const std::format_error&) { + return false; + } +} + +#define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S) +#define WIDEN(S) WIDEN_(CharT, S) + +void +test_format_string() +{ + std::vector<bool> v(1, true); + VERIFY( !is_format_string_for("{:?}", v[0]) ); + VERIFY( !is_format_string_for("{:P}", v[0]) ); + + // width needs to be integer type + VERIFY( !is_format_string_for("{:{}}", v[0], 1.0f) ); +} + +template<typename CharT> +void +test_output() +{ + std::basic_string<CharT> res; + size_t size = 0; + std::vector<bool> v{true, false}; + + res = std::format(WIDEN("{}"), v[0]); + VERIFY( res == WIDEN("true") ); + + res = std::format(WIDEN("{:s}"), v[1]); + VERIFY( res == WIDEN("false") ); + + res = std::format(WIDEN("{:d} {:#B} {:#o} {:#x}"), v[0], v[1], v[0], v[1]); + VERIFY( res == WIDEN("1 0B0 01 0x0") ); + + res = std::format(WIDEN("{:{}}"), v[0], 6); + VERIFY( res == WIDEN("true ") ); + + res = std::format(WIDEN("{:=^#7X}"), v[1]); + VERIFY( res == WIDEN("==0X0==") ); + + res = std::format(WIDEN("{}"), v); + VERIFY( res == WIDEN("[true, false]") ); + + res = std::format(WIDEN("{::d}"), v); + VERIFY( res == WIDEN("[1, 0]") ); +} + +int main() +{ + test_format_string(); + test_output<char>(); + test_output<wchar_t>(); +} diff --git a/libstdc++-v3/testsuite/23_containers/vector/capacity/114945.cc b/libstdc++-v3/testsuite/23_containers/vector/capacity/114945.cc new file mode 100644 index 0000000..daafc59 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/vector/capacity/114945.cc @@ -0,0 +1,36 @@ +// { dg-options "-O2 -Werror=stringop-overflow -Werror=array-bounds" } +// { dg-do compile { target c++11 } } + +// Bug libstdc++/114945 +// Sporadic std::vector::resize() -Wstringop-overflow or -Warray-bounds warning + +#include <stdint.h> +#include <vector> +template <typename a> struct b { + void resize(std::size_t c) { d.resize(c); } + template <typename e> void f(a, e); + std::vector<char> d; +}; +#include <regex> +std::regex g; +uint64_t h; +uint32_t i; +struct s { + enum class j : size_t; + void k(); + using l = b<j>; + std::vector<l> m; +}; +enum class s::j : size_t { n }; +void o() { g = ""; } +void s::k() { + l p; + auto q = uint32_t(), r = uint32_t(); + if (h) + r = i; + b<size_t> t; + if (q || r) + p.f(j::n, 5); + t.resize(4); + m.push_back(p); +} diff --git a/libstdc++-v3/testsuite/23_containers/vector/cons/destructible_debug_neg.cc b/libstdc++-v3/testsuite/23_containers/vector/cons/destructible_debug_neg.cc index 61b99d3..e6689f7 100644 --- a/libstdc++-v3/testsuite/23_containers/vector/cons/destructible_debug_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/vector/cons/destructible_debug_neg.cc @@ -43,11 +43,8 @@ test02() std::vector<PrivateDtor> v; } -// { dg-error "value type is destructible" "" { target *-*-* } 0 } +// { dg-error "deleted function .*DeletedDtor" "" { target *-*-* } 0 } +// { dg-error "PrivateDtor.* is private" "" { target *-*-* } 0 } // In Debug Mode the "required from here" errors come from <debug/vector> // { dg-error "required from here" "" { target *-*-* } 182 } - -// Needed because of PR c++/92193 -// { dg-prune-output "deleted function" } -// { dg-prune-output "private within this context" } diff --git a/libstdc++-v3/testsuite/23_containers/vector/cons/destructible_neg.cc b/libstdc++-v3/testsuite/23_containers/vector/cons/destructible_neg.cc index 0807d15..2bd15bc 100644 --- a/libstdc++-v3/testsuite/23_containers/vector/cons/destructible_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/vector/cons/destructible_neg.cc @@ -42,8 +42,5 @@ test02() std::vector<PrivateDtor> v; // { dg-error "here" } } -// { dg-error "value type is destructible" "" { target *-*-* } 0 } - -// Needed because of PR c++/92193 -// { dg-prune-output "deleted function" } -// { dg-prune-output "private within this context" } +// { dg-error "deleted function .*DeletedDtor" "" { target *-*-* } 0 } +// { dg-error "PrivateDtor.* is private" "" { target *-*-* } 0 } diff --git a/libstdc++-v3/testsuite/23_containers/vector/cons/from_range.cc b/libstdc++-v3/testsuite/23_containers/vector/cons/from_range.cc index ed2e3ca..3784b9c 100644 --- a/libstdc++-v3/testsuite/23_containers/vector/cons/from_range.cc +++ b/libstdc++-v3/testsuite/23_containers/vector/cons/from_range.cc @@ -1,6 +1,11 @@ // { dg-do run { target c++23 } } #include <vector> + +#if __cpp_lib_containers_ranges != 202202L +# error "Feature-test macro __cpp_lib_containers_ranges has wrong value in <vector>" +#endif + #include <span> #include <testsuite_hooks.h> #include <testsuite_iterators.h> @@ -101,8 +106,30 @@ test_constexpr() return true; } +void +test_pr120367() +{ +#ifdef __cpp_exceptions + struct X + { + X(int) { throw 1; } // Cannot successfully construct an X. + ~X() { VERIFY(false); } // So should never need to destroy one. + }; + + try + { + int i[1]{}; + std::vector<X> v(std::from_range, i); + } + catch (int) + { + } +#endif +} + int main() { test_ranges(); static_assert( test_constexpr() ); + test_pr120367(); } diff --git a/libstdc++-v3/testsuite/24_iterators/indirect_callable/projected.cc b/libstdc++-v3/testsuite/24_iterators/indirect_callable/projected.cc index 0b18616..e2fbf7d 100644 --- a/libstdc++-v3/testsuite/24_iterators/indirect_callable/projected.cc +++ b/libstdc++-v3/testsuite/24_iterators/indirect_callable/projected.cc @@ -22,12 +22,7 @@ template<typename T> using PI = std::projected<T, std::identity>; -#if __GLIBCXX__ -// Verify our projected<I, identity> optimization. -static_assert(std::same_as<PI<int*>, int*>); -#else static_assert(std::same_as<PI<int*>::value_type, int>); -#endif static_assert(std::same_as<decltype(*std::declval<const PI<int*>&>()), int&>); struct X diff --git a/libstdc++-v3/testsuite/24_iterators/operations/prev_neg.cc b/libstdc++-v3/testsuite/24_iterators/operations/prev_neg.cc index f9de894..5fdfa9e 100644 --- a/libstdc++-v3/testsuite/24_iterators/operations/prev_neg.cc +++ b/libstdc++-v3/testsuite/24_iterators/operations/prev_neg.cc @@ -38,5 +38,5 @@ test02() { const Y array[1] = { }; (void) std::prev(array + 1); - // { dg-error "forward_iterator" "" { target *-*-* } 241 } + // { dg-error "forward_iterator" "" { target *-*-* } 242 } } diff --git a/libstdc++-v3/testsuite/24_iterators/range_generators/lwg3899.cc b/libstdc++-v3/testsuite/24_iterators/range_generators/lwg3899.cc new file mode 100644 index 0000000..5a812ec --- /dev/null +++ b/libstdc++-v3/testsuite/24_iterators/range_generators/lwg3899.cc @@ -0,0 +1,57 @@ +// { dg-do run { target c++23 } } + +// LWG 3899. +// co_yielding elements of an lvalue generator is unnecessarily inefficient + +#include <generator> +#include <memory_resource> +#include <testsuite_hooks.h> + +struct memory_resource : std::pmr::memory_resource +{ + std::size_t count = 0; + + void* do_allocate(std::size_t n, std::size_t a) override + { + count += n; + return std::pmr::new_delete_resource()->allocate(n, a); + } + + void do_deallocate(void* p, std::size_t n, std::size_t a) override + { + return std::pmr::new_delete_resource()->deallocate(p, n, a); + } + + bool do_is_equal(const std::pmr::memory_resource& mr) const noexcept override + { return this == &mr; } +}; + +std::pmr::generator<int> +f(std::allocator_arg_t, std::pmr::polymorphic_allocator<>, int init) +{ + co_yield init + 0; + co_yield init + 1; +} + +std::pmr::generator<int> +g(std::allocator_arg_t, std::pmr::polymorphic_allocator<> alloc) +{ + auto gen = f(std::allocator_arg, alloc, 0); + auto gen2 = f(std::allocator_arg, alloc, 2); + co_yield std::ranges::elements_of(std::move(gen), alloc); + co_yield std::ranges::elements_of(gen2, alloc); +} + +int +main() +{ + std::size_t counts[4]; + memory_resource mr; + for (auto d : g(std::allocator_arg , &mr)) + counts[d] = mr.count; + VERIFY(counts[0] != 0); + // No allocations after the first one: + VERIFY(counts[1] == counts[0]); + VERIFY(counts[2] == counts[0]); + VERIFY(counts[3] == counts[0]); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/ends_with/1.cc b/libstdc++-v3/testsuite/25_algorithms/ends_with/1.cc new file mode 100644 index 0000000..612c27a --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/ends_with/1.cc @@ -0,0 +1,165 @@ +// { dg-do run { target c++23 } } + +#include <algorithm> +#include <ranges> + +#include <testsuite_hooks.h> +#include <testsuite_iterators.h> + +namespace ranges = std::ranges; + +template<typename Range1, typename Range2> +void +test01() +{ + int n[] = {1,2,3,4,5,6,7,8,9,10}; + + Range1 haystack(n, n+10); + Range2 needle(n+7, n+10); + VERIFY( ranges::ends_with(haystack, needle) ); + + haystack = Range1(n); + needle = Range2(n, n+10); + VERIFY( ranges::ends_with(haystack, needle) ); + + haystack = Range1(n); + needle = Range2(n+6, n+9); + VERIFY( !ranges::ends_with(haystack, needle) ); + + haystack = Range1(n); + needle = Range2(n+6, n+9); + VERIFY( ranges::ends_with(haystack, needle, + [](int n, int m) { return std::abs(n - m) <= 1; }) ); + + haystack = Range1(n); + needle = Range2(n+6, n+9); + VERIFY( ranges::ends_with(haystack, needle, + ranges::equal_to{}, + [](int n) { return n - 1; }) ); + + haystack = Range1(n); + needle = Range2(n+6, n+9); + VERIFY( ranges::ends_with(haystack, needle, + ranges::equal_to{}, + std::identity{}, + [](int n) { return n + 1; }) ); + + haystack = Range1(n, n+5); + needle = Range2(n, n+10); + VERIFY( !ranges::ends_with(haystack, needle) ); +} + +template<typename Range1, typename Range2> +void +test02() +{ + int n[] = {1,2,3,4,5,6,7,8,9,10}; + + Range1 haystack(n, n+10); + Range2 needle(n+7, n+10); + VERIFY( ranges::ends_with(haystack.begin(), haystack.end(), + needle.begin(), needle.end()) ); + + haystack = Range1(n); + needle = Range2(n, n+10); + VERIFY( ranges::ends_with(haystack.begin(), haystack.end(), + needle.begin(), needle.end()) ); + + haystack = Range1(n); + needle = Range2(n+6, n+9); + VERIFY( !ranges::ends_with(haystack.begin(), haystack.end(), + needle.begin(), needle.end()) ); + + haystack = Range1(n); + needle = Range2(n+6, n+9); + VERIFY( ranges::ends_with(haystack.begin(), haystack.end(), + needle.begin(), needle.end(), + [](int n, int m) { return std::abs(n - m) <= 1; }) ); + + haystack = Range1(n); + needle = Range2(n+6, n+9); + VERIFY( ranges::ends_with(haystack.begin(), haystack.end(), + needle.begin(), needle.end(), + ranges::equal_to{}, + [](int n) { return n - 1; }) ); + + haystack = Range1(n); + needle = Range2(n+6, n+9); + VERIFY( ranges::ends_with(haystack.begin(), haystack.end(), + needle.begin(), needle.end(), + ranges::equal_to{}, + std::identity{}, + [](int n) { return n + 1; }) ); + + haystack = Range1(n, n+5); + needle = Range2(n, n+10); + VERIFY( !ranges::ends_with(haystack.begin(), haystack.end(), + needle.begin(), needle.end()) ); + + haystack = Range1(n, n+5); + needle = Range2(n+10, n+10); + VERIFY( ranges::ends_with(haystack.begin(), haystack.end(), + needle.begin(), needle.end()) ); +} + +void +test03() +{ + auto haystack = std::views::iota(0, 10); + auto needle = std::views::iota(5, 10); + +#if __SIZEOF_INT128__ + auto haystack_ict = std::views::iota(__int128(0), __int128(10)); + auto needle_ict = std::views::iota(__int128(5), __int128(10)); +#else + auto haystack_ict = std::views::iota(0ll, 10ll); + auto needle_ict = std::views::iota(5ll, 10ll); +#endif + + VERIFY( ranges::ends_with(haystack, needle_ict) ); + VERIFY( ranges::ends_with(haystack.begin(), haystack.end(), + needle_ict.begin(), needle_ict.end()) ); + + VERIFY( ranges::ends_with(haystack_ict, needle) ); + VERIFY( ranges::ends_with(haystack_ict.begin(), haystack_ict.end(), + needle.begin(), needle.end()) ); + + VERIFY( ranges::ends_with(haystack_ict, needle_ict) ); + VERIFY( ranges::ends_with(haystack_ict.begin(), haystack_ict.end(), + needle_ict.begin(), needle_ict.end()) ); +} + +int +main() +{ + using namespace __gnu_test; + using forward = test_forward_range<int>; + using bidirectional_common = bidirectional_container<int>; + using input_sized = test_input_sized_range<int>; + using input_sized_sent = test_sized_range_sized_sent<int, input_iterator_wrapper>; + using random_access = test_random_access_range<int>; + using random_access_sized = test_random_access_sized_range<int>; + using random_access_sized_sent = test_sized_range_sized_sent<int, random_access_iterator_wrapper>; + + test01<forward, forward>(); + test01<random_access, random_access>(); + test02<forward, forward>(); + test02<random_access, random_access>(); + + test01<bidirectional_common, bidirectional_common>(); + test02<bidirectional_common, bidirectional_common>(); + test01<bidirectional_common, forward>(); + test02<bidirectional_common, forward>(); + + test01<input_sized, input_sized>(); + test01<random_access_sized, random_access_sized>(); + // test02<input_sized, input_sized>(); constraint violation + test02<random_access_sized, random_access_sized>(); + + test01<input_sized_sent, input_sized_sent>(); + test01<random_access_sized_sent, random_access_sized_sent>(); + test02<input_sized_sent, input_sized_sent>(); + test02<random_access_sized_sent, random_access_sized_sent>(); + + test03(); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/heap/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/heap/constrained.cc index 8037a2d..5486c85 100644 --- a/libstdc++-v3/testsuite/25_algorithms/heap/constrained.cc +++ b/libstdc++-v3/testsuite/25_algorithms/heap/constrained.cc @@ -20,6 +20,7 @@ #include <algorithm> #include <random> +#include <ranges> #include <testsuite_hooks.h> #include <testsuite_iterators.h> @@ -97,10 +98,55 @@ test02() return ok; } +constexpr bool +test03() +{ + // PR libstdc++/100795 - ranges::heap algos should not use std::heap directly +#if __SIZEOF_INT128__ + auto v = std::views::iota(__int128(0), __int128(20)); +#else + auto v = std::views::iota(0ll, 20ll); +#endif + + int storage[20] = {2,5,4,3,1,6,7,9,10,8,11,14,12,13,15,16,18,0,19,17}; + auto w = v | std::views::transform([&](auto i) -> int& { return storage[i]; }); + using type = decltype(w); + using cat = std::iterator_traits<std::ranges::iterator_t<type>>::iterator_category; + static_assert( std::same_as<cat, std::output_iterator_tag> ); + static_assert( std::ranges::random_access_range<type> ); + + for (int i = 1; i < 20; i++) + ranges::push_heap(w.begin(), w.begin() + i); + ranges::sort_heap(w); + VERIFY( ranges::equal(w, v) ); + ranges::make_heap(w); + auto it = ranges::pop_heap(w); + VERIFY( it[-1] == 19 ); + + for (int i = 1; i < 20; i++) + ranges::push_heap(w.begin(), w.begin() + i, std::ranges::greater{}); + ranges::sort_heap(w, std::ranges::greater{}); + VERIFY( ranges::equal(w, v | std::views::reverse) ); + ranges::make_heap(w, std::ranges::greater{}); + it = ranges::pop_heap(w, std::ranges::greater{}); + VERIFY( it[-1] == 0 ); + + for (int i = 1; i < 20; i++) + ranges::push_heap(w.begin(), w.begin() + i, std::ranges::greater{}, std::negate{}); + ranges::sort_heap(w, std::ranges::greater{}, std::negate{}); + VERIFY( ranges::equal(w, v) ); + ranges::make_heap(w, std::ranges::greater{}, std::negate{}); + it = ranges::pop_heap(w, std::ranges::greater{}, std::negate{}); + VERIFY( it[-1] == 19 ); + + return true; +} + int main() { test01<test_range>(); test01<test_container>(); static_assert(test02()); + static_assert(test03()); } diff --git a/libstdc++-v3/testsuite/25_algorithms/inplace_merge/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/inplace_merge/constrained.cc index b569c91..5634588 100644 --- a/libstdc++-v3/testsuite/25_algorithms/inplace_merge/constrained.cc +++ b/libstdc++-v3/testsuite/25_algorithms/inplace_merge/constrained.cc @@ -18,6 +18,7 @@ // { dg-do run { target c++20 } } #include <algorithm> +#include <ranges> #include <vector> #include <testsuite_hooks.h> #include <testsuite_iterators.h> @@ -60,9 +61,44 @@ test02() } +void +test03() +{ + // PR libstdc++/100795 - ranges::inplace_merge should not use + // std::inplace_merge directly +#if __SIZEOF_INT128__ + auto v = std::views::iota(__int128(0), __int128(20)); +#else + auto v = std::views::iota(0ll, 20ll); +#endif + + int storage[20] = {2,5,4,3,1,6,7,9,10,8,11,14,12,13,15,16,18,0,19,17}; + auto w = v | std::views::transform([&](auto i) -> int& { return storage[i]; }); + using type = decltype(w); + using cat = std::iterator_traits<std::ranges::iterator_t<type>>::iterator_category; + static_assert( std::same_as<cat, std::output_iterator_tag> ); + static_assert( std::ranges::random_access_range<type> ); + + ranges::sort(w | std::views::take(10)); + ranges::sort(w | std::views::drop(10)); + ranges::inplace_merge(w, w.begin() + 10); + VERIFY( ranges::equal(w, v) ); + + ranges::sort(w | std::views::take(10), std::ranges::greater{}); + ranges::sort(w | std::views::drop(10), std::ranges::greater{}); + ranges::inplace_merge(w, w.begin() + 10, std::ranges::greater{}); + VERIFY( ranges::equal(w, v | std::views::reverse) ); + + ranges::sort(w | std::views::take(10), std::ranges::greater{}, std::negate{}); + ranges::sort(w | std::views::drop(10), std::ranges::greater{}, std::negate{}); + ranges::inplace_merge(w, w.begin() + 10, std::ranges::greater{}, std::negate{}); + VERIFY( ranges::equal(w, v) ); +} + int main() { test01(); test02(); + test03(); } diff --git a/libstdc++-v3/testsuite/25_algorithms/nth_element/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/nth_element/constrained.cc index 3189b22..8cb1625 100644 --- a/libstdc++-v3/testsuite/25_algorithms/nth_element/constrained.cc +++ b/libstdc++-v3/testsuite/25_algorithms/nth_element/constrained.cc @@ -20,6 +20,7 @@ #include <algorithm> #include <random> +#include <ranges> #include <testsuite_hooks.h> #include <testsuite_iterators.h> @@ -67,9 +68,39 @@ test02() return x[3] == 4; } +constexpr bool +test03() +{ + // PR libstdc++/100795 - ranges::sort should not use std::sort directly +#if __SIZEOF_INT128__ + auto v = std::views::iota(__int128(0), __int128(20)); +#else + auto v = std::views::iota(0ll, 20ll); +#endif + + int storage[20] = {2,5,4,3,1,6,7,9,10,8,11,14,12,13,15,16,18,0,19,17}; + auto w = v | std::views::transform([&](auto i) -> int& { return storage[i]; }); + using type = decltype(w); + using cat = std::iterator_traits<std::ranges::iterator_t<type>>::iterator_category; + static_assert( std::same_as<cat, std::output_iterator_tag> ); + static_assert( std::ranges::random_access_range<type> ); + + ranges::nth_element(w, w.begin() + 10); + VERIFY( w[10] == 10 ); + + ranges::nth_element(w, w.begin() + 5, std::ranges::greater{}); + VERIFY( w[5] == 19 - 5 ); + + ranges::nth_element(w, w.begin() + 15, std::ranges::greater{}, std::negate{}); + VERIFY( w[15] == 15 ); + + return true; +} + int main() { test01(); static_assert(test02()); + static_assert(test03()); } diff --git a/libstdc++-v3/testsuite/25_algorithms/remove_if/120789.cc b/libstdc++-v3/testsuite/25_algorithms/remove_if/120789.cc new file mode 100644 index 0000000..c1f4eeb --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/remove_if/120789.cc @@ -0,0 +1,36 @@ +// PR libstdc++/120789 - ranges::remove_if should use ranges::iter_move +// { dg-do compile { target c++20 } } + +#include <algorithm> + +struct A +{ + bool operator==(const A&) const; +}; + +struct B +{ + B(B&&) = delete; + B& operator=(const A&) const; + + operator A() const; + bool operator==(const B&) const; +}; + +struct I +{ + using value_type = A; + using difference_type = int; + B operator*() const; + I& operator++(); + I operator++(int); + bool operator==(const I&) const; + friend A iter_move(const I&); +}; + +void +test01() +{ + std::ranges::subrange<I, I> r; + auto [begin, end] = std::ranges::remove_if(r, [](auto&&) { return true; }); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/sample/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/sample/constrained.cc index b9945b1..0ec3e0b 100644 --- a/libstdc++-v3/testsuite/25_algorithms/sample/constrained.cc +++ b/libstdc++-v3/testsuite/25_algorithms/sample/constrained.cc @@ -20,6 +20,7 @@ #include <algorithm> #include <random> +#include <ranges> #include <testsuite_hooks.h> #include <testsuite_iterators.h> @@ -59,9 +60,34 @@ test01() } } +void +test02() +{ + // PR libstdc++/100795 - ranges::sample should not use std::sample +#if 0 // FIXME: ranges::sample rejects integer-class difference types. +#if __SIZEOF_INT128__ + auto v = std::views::iota(__int128(0), __int128(20)); +#else + auto v = std::views::iota(0ll, 20ll); +#endif +#else + auto v = std::views::iota(0, 20); +#endif + + int storage[20] = {2,5,4,3,1,6,7,9,10,8,11,14,12,13,15,16,18,0,19,17}; + auto w = v | std::views::transform([&](auto i) -> int& { return storage[i]; }); + using type = decltype(w); + static_assert( std::ranges::random_access_range<type> ); + + ranges::sample(v, w.begin(), 20, rng); + ranges::sort(w); + VERIFY( ranges::equal(w, v) ); +} + int main() { test01<forward_iterator_wrapper, output_iterator_wrapper>(); test01<input_iterator_wrapper, random_access_iterator_wrapper>(); + test02(); } diff --git a/libstdc++-v3/testsuite/25_algorithms/shuffle/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/shuffle/constrained.cc index d0977a2..70c6bdf 100644 --- a/libstdc++-v3/testsuite/25_algorithms/shuffle/constrained.cc +++ b/libstdc++-v3/testsuite/25_algorithms/shuffle/constrained.cc @@ -20,6 +20,7 @@ #include <algorithm> #include <random> +#include <ranges> #include <vector> #include <testsuite_hooks.h> #include <testsuite_iterators.h> @@ -62,8 +63,32 @@ test01() } } +void +test02() +{ + // PR libstdc++/100795 - ranges::shuffle should not use std::shuffle directly +#if 0 // FIXME: ranges::shuffle rejects integer-class difference types. +#if __SIZEOF_INT128__ + auto v = std::views::iota(__int128(0), __int128(20)); +#else + auto v = std::views::iota(0ll, 20ll); +#endif +#else + auto v = std::views::iota(0, 20); +#endif + + int storage[20] = {2,5,4,3,1,6,7,9,10,8,11,14,12,13,15,16,18,0,19,17}; + auto w = v | std::views::transform([&](auto i) -> int& { return storage[i]; }); + using type = decltype(w); + static_assert( std::ranges::random_access_range<type> ); + + std::ranlux48_base g; + ranges::shuffle(w, g); +} + int main() { test01(); + test02(); } diff --git a/libstdc++-v3/testsuite/25_algorithms/sort/118209.cc b/libstdc++-v3/testsuite/25_algorithms/sort/118209.cc new file mode 100644 index 0000000..6dedbde --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/sort/118209.cc @@ -0,0 +1,23 @@ +// PR libstdc++ - ranges::sort doesn't use iter_move, cannot sort zip of move-only type +// { dg-do compile { target c++23 } } + +#include <algorithm> +#include <ranges> +#include <vector> + +struct F { + int a = -1; + explicit F(int d) : a(d) { } + F(const F&) = delete; + F(F&& o) : a(o.a) { } + void operator=(const F&) = delete; + F& operator=(F&& o) { return *this; } + auto operator<=>(const F&) const = default; +}; + +int main () { + int a[] = {3,2,1}; + std::vector<F> v(a, a+3); + std::ranges::sort(v); // OK + std::ranges::sort(std::views::zip(v)); // didn't compile +} diff --git a/libstdc++-v3/testsuite/25_algorithms/sort/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/sort/constrained.cc index 82754af..930dbd7 100644 --- a/libstdc++-v3/testsuite/25_algorithms/sort/constrained.cc +++ b/libstdc++-v3/testsuite/25_algorithms/sort/constrained.cc @@ -20,6 +20,7 @@ #include <algorithm> #include <random> +#include <ranges> #include <vector> #include <testsuite_hooks.h> #include <testsuite_iterators.h> @@ -72,9 +73,39 @@ test02() && ranges::equal(x, y, {}, &X::i, &X::i)); } +constexpr bool +test03() +{ + // PR libstdc++/100795 - ranges::sort should not use std::sort directly +#if __SIZEOF_INT128__ + auto v = std::views::iota(__int128(0), __int128(20)); +#else + auto v = std::views::iota(0ll, 20ll); +#endif + + int storage[20] = {2,5,4,3,1,6,7,9,10,8,11,14,12,13,15,16,18,0,19,17}; + auto w = v | std::views::transform([&](auto i) -> int& { return storage[i]; }); + using type = decltype(w); + using cat = std::iterator_traits<std::ranges::iterator_t<type>>::iterator_category; + static_assert( std::same_as<cat, std::output_iterator_tag> ); + static_assert( std::ranges::random_access_range<type> ); + + ranges::sort(w); + VERIFY( ranges::equal(w, v) ); + + ranges::sort(w, std::ranges::greater{}); + VERIFY( ranges::equal(w, v | std::views::reverse) ); + + ranges::sort(w, std::ranges::greater{}, std::negate{}); + VERIFY( ranges::equal(w, v) ); + + return true; +} + int main() { test01(); static_assert(test02()); + static_assert(test03()); } diff --git a/libstdc++-v3/testsuite/25_algorithms/stable_partition/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/stable_partition/constrained.cc index fc11c64..4dc2678 100644 --- a/libstdc++-v3/testsuite/25_algorithms/stable_partition/constrained.cc +++ b/libstdc++-v3/testsuite/25_algorithms/stable_partition/constrained.cc @@ -21,6 +21,7 @@ // { dg-require-effective-target hosted } #include <algorithm> +#include <ranges> #include <testsuite_hooks.h> #include <testsuite_iterators.h> @@ -70,9 +71,34 @@ test02() } } +void +test03() +{ + // PR libstdc++/100795 - ranges::stable_partition should not use + // std::stable_partition directly +#if __SIZEOF_INT128__ + auto v = std::views::iota(__int128(0), __int128(20)); +#else + auto v = std::views::iota(0ll, 20ll); +#endif + + int storage[20] = {2,5,4,3,1,6,7,9,10,8,11,14,12,13,15,16,18,0,19,17}; + auto w = v | std::views::transform([&](auto i) -> int& { return storage[i]; }); + using type = decltype(w); + using cat = std::iterator_traits<std::ranges::iterator_t<type>>::iterator_category; + static_assert( std::same_as<cat, std::output_iterator_tag> ); + static_assert( std::ranges::random_access_range<type> ); + + auto pred = [] (int a) { return a%2==0; }; + ranges::stable_partition(w, pred); + VERIFY( ranges::all_of(w.begin(), w.begin() + 10, pred) ); + VERIFY( ranges::none_of(w.begin() + 10, w.end(), pred) ); +} + int main() { test01(); test02(); + test03(); } diff --git a/libstdc++-v3/testsuite/25_algorithms/stable_sort/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/stable_sort/constrained.cc index 0bd438f..5504344 100644 --- a/libstdc++-v3/testsuite/25_algorithms/stable_sort/constrained.cc +++ b/libstdc++-v3/testsuite/25_algorithms/stable_sort/constrained.cc @@ -20,6 +20,7 @@ #include <algorithm> #include <random> +#include <ranges> #include <vector> #include <testsuite_hooks.h> #include <testsuite_iterators.h> @@ -62,8 +63,37 @@ test01() } } +void +test02() +{ + // PR libstdc++/100795 - ranges::stable_sort should not use std::stable_sort + // directly +#if __SIZEOF_INT128__ + auto v = std::views::iota(__int128(0), __int128(20)); +#else + auto v = std::views::iota(0ll, 20ll); +#endif + + int storage[20] = {2,5,4,3,1,6,7,9,10,8,11,14,12,13,15,16,18,0,19,17}; + auto w = v | std::views::transform([&](auto i) -> int& { return storage[i]; }); + using type = decltype(w); + using cat = std::iterator_traits<std::ranges::iterator_t<type>>::iterator_category; + static_assert( std::same_as<cat, std::output_iterator_tag> ); + static_assert( std::ranges::random_access_range<type> ); + + ranges::stable_sort(w); + VERIFY( ranges::equal(w, v) ); + + ranges::stable_sort(w, std::ranges::greater{}); + VERIFY( ranges::equal(w, v | std::views::reverse) ); + + ranges::stable_sort(w, std::ranges::greater{}, std::negate{}); + VERIFY( ranges::equal(w, v) ); +} + int main() { test01(); + test02(); } diff --git a/libstdc++-v3/testsuite/25_algorithms/starts_with/1.cc b/libstdc++-v3/testsuite/25_algorithms/starts_with/1.cc new file mode 100644 index 0000000..0c288d8 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/starts_with/1.cc @@ -0,0 +1,158 @@ +// { dg-do run { target c++23 } } + +#include <algorithm> +#include <ranges> + +#include <testsuite_hooks.h> +#include <testsuite_iterators.h> + +namespace ranges = std::ranges; + +template<typename Range1, typename Range2> +void +test01() +{ + int n[] = {1,2,3,4,5,6,7,8,9,10}; + + Range1 haystack(n, n+10); + Range2 needle(n, n+3); + VERIFY( ranges::starts_with(haystack, needle) ); + + haystack = Range1(n); + needle = Range2(n, n+10); + VERIFY( ranges::starts_with(haystack, needle) ); + + haystack = Range1(n); + needle = Range2(n+1, n+4); + VERIFY( !ranges::starts_with(haystack, needle) ); + + haystack = Range1(n); + needle = Range2(n+1, n+4); + VERIFY( ranges::starts_with(haystack, needle, + [](int n, int m) { return std::abs(n - m) <= 1; }) ); + + haystack = Range1(n); + needle = Range2(n+1, n+4); + VERIFY( ranges::starts_with(haystack, needle, + ranges::equal_to{}, + [](int n) { return n + 1; }) ); + + haystack = Range1(n); + needle = Range2(n+1, n+4); + VERIFY( ranges::starts_with(haystack, needle, + ranges::equal_to{}, + std::identity{}, + [](int n) { return n - 1; }) ); + + haystack = Range1(n, n+5); + needle = Range2(n, n+10); + VERIFY( !ranges::starts_with(haystack, needle) ); + + haystack = Range1(n, n+5); + needle = Range2(n+10, n+10); + VERIFY( ranges::starts_with(haystack, needle) ); +} + +template<typename Range1, typename Range2> +void +test02() +{ + int n[] = {1,2,3,4,5,6,7,8,9,10}; + + Range1 haystack(n, n+10); + Range2 needle(n, n+3); + VERIFY( ranges::starts_with(haystack.begin(), haystack.end(), + needle.begin(), needle.end()) ); + + haystack = Range1(n); + needle = Range2(n, n+10); + VERIFY( ranges::starts_with(haystack.begin(), haystack.end(), + needle.begin(), needle.end()) ); + + haystack = Range1(n); + needle = Range2(n+1, n+4); + VERIFY( !ranges::starts_with(haystack.begin(), haystack.end(), + needle.begin(), needle.end()) ); + + haystack = Range1(n); + needle = Range2(n+1, n+4); + VERIFY( ranges::starts_with(haystack.begin(), haystack.end(), + needle.begin(), needle.end(), + [](int n, int m) { return std::abs(n - m) <= 1; }) ); + + haystack = Range1(n); + needle = Range2(n+1, n+4); + VERIFY( ranges::starts_with(haystack.begin(), haystack.end(), + needle.begin(), needle.end(), + ranges::equal_to{}, + [](int n) { return n + 1; }) ); + + haystack = Range1(n); + needle = Range2(n+1, n+4); + VERIFY( ranges::starts_with(haystack.begin(), haystack.end(), + needle.begin(), needle.end(), + ranges::equal_to{}, + std::identity{}, + [](int n) { return n - 1; }) ); + + haystack = Range1(n, n+5); + needle = Range2(n, n+10); + VERIFY( !ranges::starts_with(haystack.begin(), haystack.end(), + needle.begin(), needle.end()) ); +} + +void +test03() +{ + auto haystack = std::views::iota(0, 10); + auto needle = std::views::iota(0, 5); + +#if __SIZEOF_INT128__ + auto haystack_ict = std::views::iota(__int128(0), __int128(10)); + auto needle_ict = std::views::iota(__int128(0), __int128(5)); +#else + auto haystack_ict = std::views::iota(0ll, 10ll); + auto needle_ict = std::views::iota(0ll, 5ll); +#endif + + VERIFY( ranges::starts_with(haystack, needle_ict) ); + VERIFY( ranges::starts_with(haystack.begin(), haystack.end(), + needle_ict.begin(), needle_ict.end()) ); + + VERIFY( ranges::starts_with(haystack_ict, needle) ); + VERIFY( ranges::starts_with(haystack_ict.begin(), haystack_ict.end(), + needle.begin(), needle.end()) ); + + VERIFY( ranges::starts_with(haystack_ict, needle_ict) ); + VERIFY( ranges::starts_with(haystack_ict.begin(), haystack_ict.end(), + needle_ict.begin(), needle_ict.end()) ); +} + +int +main() +{ + using namespace __gnu_test; + using input = test_input_range<int>; + using input_sized = test_input_sized_range<int>; + using input_sized_sent = test_sized_range_sized_sent<int, input_iterator_wrapper>; + using random_access = test_random_access_range<int>; + using random_access_sized = test_random_access_sized_range<int>; + using random_access_sized_sent = test_sized_range_sized_sent<int, random_access_iterator_wrapper>; + + test01<input, input>(); + test01<random_access, random_access>(); + test02<input, input>(); + test02<random_access, random_access>(); + + test01<input_sized, input_sized>(); + test01<random_access_sized, random_access_sized>(); + test02<input_sized, input_sized>(); + test02<random_access_sized, random_access_sized>(); + + test01<input_sized_sent, input_sized_sent>(); + test01<random_access_sized_sent, random_access_sized_sent>(); + test02<input_sized_sent, input_sized_sent>(); + test02<random_access_sized_sent, random_access_sized_sent>(); + + test03(); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/unique/120789.cc b/libstdc++-v3/testsuite/25_algorithms/unique/120789.cc new file mode 100644 index 0000000..24b1071 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/unique/120789.cc @@ -0,0 +1,36 @@ +// PR libstdc++/120789 - ranges::unique should use ranges::iter_move +// { dg-do compile { target c++20 } } + +#include <algorithm> + +struct A +{ + bool operator==(const A&) const; +}; + +struct B +{ + B(B&&) = delete; + B& operator=(const A&) const; + + operator A() const; + bool operator==(const B&) const; +}; + +struct I +{ + using value_type = A; + using difference_type = int; + B operator*() const; + I& operator++(); + I operator++(int); + bool operator==(const I&) const; + friend A iter_move(const I&); +}; + +void +test01() +{ + std::ranges::subrange<I, I> r; + auto [begin, end] = std::ranges::unique(r); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/unique_copy/120384.cc b/libstdc++-v3/testsuite/25_algorithms/unique_copy/120384.cc new file mode 100644 index 0000000..27cd337 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/unique_copy/120384.cc @@ -0,0 +1,12 @@ +// { dg-options "-D_GLIBCXX_CONCEPT_CHECKS" } +// { dg-do compile } + +// PR 120384 _BinaryPredicateConcept checks in std::unique_copy are wrong + +#include <algorithm> + +void +test_pr120384(const int* first, const int* last, int* out) +{ + std::unique_copy(first, last, out); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/unique_copy/lwg2439.cc b/libstdc++-v3/testsuite/25_algorithms/unique_copy/lwg2439.cc new file mode 100644 index 0000000..f2ec3e3 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/unique_copy/lwg2439.cc @@ -0,0 +1,127 @@ +// { dg-do run } + +#include <algorithm> +#include <testsuite_iterators.h> + +using namespace __gnu_test; + +int out[4]; +short out_shrt[4]; +short in[7] = { 1, 2, 2, 2, 3, 4, 4 }; + +template<typename T> +void +check_and_reset(T* p) +{ + VERIFY( p[0] == 1 ); + VERIFY( p[1] == 2 ); + VERIFY( p[2] == 3 ); + VERIFY( p[3] == 4 ); + std::fill_n(p, 4, 0); +} + +struct Eq +{ + bool operator()(short i, short j) const { return i == j; } + bool operator()(short, int) const { VERIFY(false); } + bool operator()(int, short) const { VERIFY(false); } +}; + +struct Eq2 +{ + bool operator()(const short& i, const short& j) const + { + // Both arguments should be elements of the 'in' array. + VERIFY( in+0 <= &i && &i < in+7 ); + VERIFY( in+0 <= &j && &j < in+7 ); + VERIFY( &i < &j ); + return i == j; + } + bool operator()(short, int) const { VERIFY(false); } + bool operator()(int, short) const { VERIFY(false); } +}; + +struct Eq3 +{ + bool operator()(const short& i, const short& j) const + { + // First argument should be element of the 'out' array. + // Second argument should be element of the 'in' array. + VERIFY( out_shrt+0 <= &i && &i < out_shrt+4 ); + VERIFY( in+0 <= &j && &j < in+7 ); + return i == j; + } + bool operator()(short, int) const { VERIFY(false); } + bool operator()(int, short) const { VERIFY(false); } +}; + +void +test_forward_source() +{ + // The input range uses forward iterators + test_container<short, forward_iterator_wrapper> inc(in); + test_container<int, output_iterator_wrapper> outc(out); + std::unique_copy(inc.begin(), inc.end(), outc.begin()); + check_and_reset(out); + + test_container<short, forward_iterator_wrapper> inc2(in); + test_container<int, output_iterator_wrapper> outc2(out); + std::unique_copy(inc2.begin(), inc2.end(), outc2.begin(), Eq2()); + check_and_reset(out); +} + +void +test_output_dest() +{ + // The input range uses input iterators. + // The output range uses output iterators. + test_container<short, input_iterator_wrapper> inc(in); + test_container<int, output_iterator_wrapper> outc(out); + std::unique_copy(inc.begin(), inc.end(), outc.begin()); + check_and_reset(out); + + test_container<short, input_iterator_wrapper> inc2(in); + test_container<int, output_iterator_wrapper> outc2(out); + std::unique_copy(inc2.begin(), inc2.end(), outc2.begin(), Eq()); + check_and_reset(out); +} + +void +test_forward_dest_diff_type() +{ + // The input range uses input iterators. + // The output range uses forward iterators, but with different value type. + test_container<short, input_iterator_wrapper> inc(in); + test_container<int, forward_iterator_wrapper> outc(out); + std::unique_copy(inc.begin(), inc.end(), outc.begin()); + check_and_reset(out); + + test_container<short, input_iterator_wrapper> inc2(in); + test_container<int, forward_iterator_wrapper> outc2(out); + std::unique_copy(inc2.begin(), inc2.end(), outc2.begin(), Eq()); + check_and_reset(out); +} + +void +test_forward_dest_same_type() +{ + // The input range uses input iterators. + // The output range uses forward iterators, with same value type. + test_container<short, input_iterator_wrapper> inc(in); + test_container<short, forward_iterator_wrapper> outc(out_shrt); + std::unique_copy(inc.begin(), inc.end(), outc.begin()); + check_and_reset(out_shrt); + + test_container<short, input_iterator_wrapper> inc2(in); + test_container<short, forward_iterator_wrapper> outc2(out_shrt); + std::unique_copy(inc2.begin(), inc2.end(), outc2.begin(), Eq3()); + check_and_reset(out_shrt); +} + +int main() +{ + test_forward_source(); + test_output_dest(); + test_forward_dest_diff_type(); + test_forward_dest_same_type(); +} diff --git a/libstdc++-v3/testsuite/26_numerics/complex/fabs_neg.cc b/libstdc++-v3/testsuite/26_numerics/complex/fabs_neg.cc new file mode 100644 index 0000000..36c483e --- /dev/null +++ b/libstdc++-v3/testsuite/26_numerics/complex/fabs_neg.cc @@ -0,0 +1,13 @@ +// { dg-do compile } +// Bug 120235 std::fabs(const std::complex<T>&) should not be defined + +#include <complex> + +void test_pr120235(std::complex<double> c) +{ + (void) std::fabs(c); + // { dg-error "no matching function" "" { target c++98_only } 8 } + // { dg-warning "deprecated: use 'std::abs'" "" { target c++11 } 8 } +} + +// { dg-prune-output "no type named '__type'" } diff --git a/libstdc++-v3/testsuite/26_numerics/headers/cmath/82644.cc b/libstdc++-v3/testsuite/26_numerics/headers/cmath/82644.cc index 3274f05..40abb2c 100644 --- a/libstdc++-v3/testsuite/26_numerics/headers/cmath/82644.cc +++ b/libstdc++-v3/testsuite/26_numerics/headers/cmath/82644.cc @@ -15,8 +15,9 @@ // with this library; see the file COPYING3. If not see // <http://www.gnu.org/licenses/>. -// { dg-options "-D__STDCPP_WANT_MATH_SPEC_FUNCS__ -D__STRICT_ANSI__" } +// { dg-options "-D__STDCPP_WANT_MATH_SPEC_FUNCS__" } // { dg-do compile { target c++11 } } +// // { dg-add-options strict_std } #define conf_hyperg 1 #define conf_hypergf 2 diff --git a/libstdc++-v3/testsuite/26_numerics/headers/cstdlib/abs128.cc b/libstdc++-v3/testsuite/26_numerics/headers/cstdlib/abs128.cc new file mode 100644 index 0000000..cfb0562 --- /dev/null +++ b/libstdc++-v3/testsuite/26_numerics/headers/cstdlib/abs128.cc @@ -0,0 +1,16 @@ +// { dg-do compile } +// { dg-add-options strict_std } + +#include <cstdlib> + +template<typename T> T same_type(T, T) { return T(); } + +#ifdef __SIZEOF_INT128__ +__int128 i = 0; +__int128 j = same_type(std::abs(i), i); +#endif + +#ifdef __SIZEOF_FLOAT128__ +__float128 f = 0.0; +__float128 g = same_type(std::abs(f), f); +#endif diff --git a/libstdc++-v3/testsuite/26_numerics/pstl/numeric_ops/108236.cc b/libstdc++-v3/testsuite/26_numerics/pstl/numeric_ops/108236.cc index e0e3027..cbef8ab 100644 --- a/libstdc++-v3/testsuite/26_numerics/pstl/numeric_ops/108236.cc +++ b/libstdc++-v3/testsuite/26_numerics/pstl/numeric_ops/108236.cc @@ -8,30 +8,6 @@ #include <execution> #include <testsuite_hooks.h> -struct Mint -{ - Mint(int i = 0) : val(i) { } - Mint(Mint&&) = default; - Mint& operator=(Mint&&) = default; - - operator int() const { return val; } - -private: - int val; -}; - -void -test_move_only() -{ - const int input[]{10, 20, 30}; - int output[3]; - std::exclusive_scan(std::execution::seq, input, input+3, output, Mint(5), - std::plus<int>{}); - VERIFY( output[0] == 5 ); - VERIFY( output[1] == 15 ); - VERIFY( output[2] == 35 ); -} - void test_pr108236() { @@ -45,6 +21,5 @@ test_pr108236() int main() { - test_move_only(); test_pr108236(); } diff --git a/libstdc++-v3/testsuite/26_numerics/pstl/numeric_ops/move_only.cc b/libstdc++-v3/testsuite/26_numerics/pstl/numeric_ops/move_only.cc new file mode 100644 index 0000000..38ad3c2 --- /dev/null +++ b/libstdc++-v3/testsuite/26_numerics/pstl/numeric_ops/move_only.cc @@ -0,0 +1,90 @@ +// { dg-options "-ltbb" } +// { dg-do run { target c++17 } } +// { dg-require-effective-target tbb_backend } + +#include <numeric> +#include <execution> +#include <testsuite_hooks.h> + +struct Mint +{ + Mint(int i = 0) : val(i) { } + + Mint(Mint&& m) : val(m.val) { m.val = -1; } + + Mint& operator=(Mint&& m) + { + val = m.val; + m.val = -1; + return *this; + } + + operator int() const + { + VERIFY(val >= 0); // Check we don't read value of a moved-from instance. + return val; + } + + friend Mint operator+(const Mint& lhs, const Mint& rhs) + { return Mint(lhs.val + rhs.val); } + +private: + int val; +}; + +void +test_reduce() +{ + Mint input[]{1, 2, 3}; + Mint m = std::reduce(std::execution::seq, input, input+3); + VERIFY( static_cast<int>(m) == 6 ); + + m = std::reduce(std::execution::seq, input, input+3, Mint(100)); + VERIFY( static_cast<int>(m) == 106 ); + + m = std::reduce(std::execution::seq, input, input+3, Mint(200), + std::plus<>{}); + VERIFY( static_cast<int>(m) == 206 ); +} + +void +test_transform_reduce() +{ +} + +void +test_exclusive_scan() +{ + const int input[]{10, 20, 30}; + int output[3]; + std::exclusive_scan(std::execution::seq, input, input+3, output, Mint(5), + std::plus<int>{}); + VERIFY( output[0] == 5 ); + VERIFY( output[1] == 15 ); + VERIFY( output[2] == 35 ); +} + +void +test_inclusive_scan() +{ +} + +void +test_transform_exclusive_scan() +{ +} + +void +test_transform_inclusive_scan() +{ +} + +int main() +{ + test_reduce(); + test_transform_reduce(); + test_exclusive_scan(); + test_inclusive_scan(); + test_transform_exclusive_scan(); + test_transform_inclusive_scan(); +} diff --git a/libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc b/libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc index 3c5aa7f..0afba65 100644 --- a/libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc +++ b/libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc @@ -12,4 +12,4 @@ auto x = std::generate_canonical<std::size_t, // { dg-error "static assertion failed: template argument must be a floating point type" "" { target *-*-* } 270 } -// { dg-error "static assertion failed: template argument must be a floating point type" "" { target *-*-* } 3351 } +// { dg-error "static assertion failed: template argument must be a floating point type" "" { target *-*-* } 3357 } diff --git a/libstdc++-v3/testsuite/27_io/basic_istringstream/cons/char/string_view.cc b/libstdc++-v3/testsuite/27_io/basic_istringstream/cons/char/string_view.cc new file mode 100644 index 0000000..f25b538 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/basic_istringstream/cons/char/string_view.cc @@ -0,0 +1,201 @@ +// C++26 [istringstream.general] + +// { dg-do run { target c++26 } } + +#include <sstream> +#include <string> +#include <string_view> +#include <testsuite_allocator.h> +#include <testsuite_hooks.h> + +// Check C++26 P2495 istringstream ctors and members str(s) that accept a +// string_view, or anything convertible to a string_view, in place of a +// string object. Mostly just verify plumbing. + +#ifndef C +# define C char +# define L(a) a +#endif + +using string = std::basic_string<C>; +using string_view = std::basic_string_view<C>; +using istringstream = std::basic_istringstream<C>; + +struct convertible_to_string_view { + string s; + operator string_view() const { return s; } +}; + +const string str(L("This is a test string")); +convertible_to_string_view cstr{str}; // a copy +const convertible_to_string_view ccstr{str}; // another copy + +template <typename istringstream = std::basic_istringstream<C>> +void +test01() +{ + // Test C++26 constructor and str(s) taking a generalized string_view + + static_assert(! requires { istringstream(1); }, + "istringstream ctor should reject what cannot be converted to a string_view"); + static_assert(! requires { istringstream().str(1); }, + "istringstream::str(s) should reject what cannot be converted to a string_view"); + + static_assert(!std::is_convertible_v<string_view, istringstream>, + "istringstream(string_view, ios::openmode) is explicit"); + static_assert(!std::is_convertible_v<const string_view, istringstream>, + "istringstream(string_view, ios::openmode) is explicit"); + static_assert(!std::is_convertible_v<convertible_to_string_view, istringstream>, + "istringstream(convertible_to_string_view, ios::openmode) is explicit"); + static_assert(!std::is_convertible_v<const convertible_to_string_view, istringstream>, + "istringstream(convertible_to_string_view, ios::openmode) is explicit"); + + { + istringstream istr(cstr); + VERIFY( istr.str() == cstr.s ); + VERIFY( istr.get() == cstr.s[0] ); + } + { + istringstream istr(ccstr); + VERIFY( istr.str() == ccstr.s ); + VERIFY( istr.get() == ccstr.s[0] ); + } + { + istringstream istr(cstr, std::ios_base::in); + VERIFY( istr.str() == cstr.s ); + VERIFY( istr.get() == cstr.s[0] ); + VERIFY( istr.rdbuf()->sputc('X') != 'X' ); + } + { + istringstream istr(cstr, std::ios_base::out); + VERIFY( istr.str() == cstr.s ); + VERIFY( istr.get() == cstr.s[0] ); + VERIFY( istr.rdbuf()->sputc('X') == 'X' ); + } +} + +void +test02() +{ + // Test various C++26 constructors taking string views + // and mix of other arguments + + auto const mode = std::ios_base::in | std::ios_base::out; + + { + // template <typename T> + // basic_istringstream(const T&, ios_base::openmode, const allocator_type&) + + istringstream::allocator_type a; + { + istringstream istr(cstr, mode, a); // ={} checks for non-explicit ctor + VERIFY( istr.str() == cstr.s ); + } + { + istringstream istr(cstr, std::ios::in, a); + VERIFY( istr.str() == cstr.s ); + VERIFY( istr.get() == cstr.s[0] ); + VERIFY( istr.rdbuf()->sputc('X') != 'X' ); + } + { + istringstream istr(cstr, std::ios::out, a); + VERIFY( istr.str() == cstr.s ); + VERIFY( istr.get() == cstr.s[0] ); + VERIFY( istr.rdbuf()->sputc('X') == 'X' ); + } + } + + { + // template <typename T> + // basic_istringstream(const T&, ios_base::openmode) + { + istringstream istr(cstr, mode); + VERIFY( istr.str() == cstr.s ); + VERIFY( istr.get() == cstr.s[0] ); + VERIFY( istr.rdbuf()->sputc('X') == 'X' ); + } + { + istringstream istr(cstr, std::ios::in); + VERIFY( istr.str() == cstr.s ); + VERIFY( istr.get() == cstr.s[0] ); + VERIFY( istr.rdbuf()->sputc('X') != 'X' ); + } + { + istringstream istr(cstr, std::ios::out); + VERIFY( istr.str() == cstr.s ); + VERIFY( istr.get() == cstr.s[0] ); + VERIFY( istr.rdbuf()->sputc('X') == 'X' ); + } + } + + { + // template <typename T> + // explicit + // basic_istringstream(const T&, ios_base::openmode = ios_base::in) + + istringstream istr(cstr); + VERIFY( istr.str() == cstr.s ); + VERIFY( istr.get() == cstr.s[0] ); + VERIFY( istr.rdbuf()->sputc('X') != 'X' ); + } +} + +using alloc_type = __gnu_test::uneq_allocator<C>; + +template<typename Alloc, typename CC = typename Alloc::value_type> + using istringstream_with_alloc + = std::basic_istringstream<CC, std::char_traits<CC>, Alloc>; + +void test03() +{ + alloc_type a{1}; + { + istringstream_with_alloc<alloc_type> istr(cstr, a); +#if _GLIBCXX_USE_CXX11_ABI + VERIFY( istr.rdbuf()->get_allocator() == a ); +#endif + VERIFY( string_view{istr.str()} == cstr ); + VERIFY( istr.get() == cstr.s[0] ); + } + { + istringstream_with_alloc<alloc_type> istr(cstr, std::ios::in, a); +#if _GLIBCXX_USE_CXX11_ABI + VERIFY( istr.rdbuf()->get_allocator() == a ); +#endif + VERIFY( string_view{istr.str()} == cstr ); + VERIFY( istr.get() == cstr.s[0] ); + VERIFY( istr.rdbuf()->sputc('X') != 'X' ); + } + { + istringstream_with_alloc<alloc_type> istr(cstr, std::ios::out, a); +#if _GLIBCXX_USE_CXX11_ABI + VERIFY( istr.rdbuf()->get_allocator() == a ); +#endif + VERIFY( string_view{istr.str()} == cstr ); + VERIFY( istr.get() == cstr.s[0] ); + VERIFY( istr.rdbuf()->sputc('X') == 'X' ); + } +} + +void test04() +{ + { + istringstream istr; + istr.str( cstr ); + VERIFY( istr.str() == cstr.s ); + } + { + istringstream istr; + istr.str( ccstr ); + VERIFY( istr.str() == ccstr.s ); + } +} + +int +main() +{ + test01(); + test02(); + test03(); + test04(); +} diff --git a/libstdc++-v3/testsuite/27_io/basic_istringstream/cons/wchar_t/string_view.cc b/libstdc++-v3/testsuite/27_io/basic_istringstream/cons/wchar_t/string_view.cc new file mode 100644 index 0000000..62fb03c --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/basic_istringstream/cons/wchar_t/string_view.cc @@ -0,0 +1,6 @@ +// C++26 [istringstream.general] +// { dg-do run { target c++26 } } + +#define C wchar_t +#define L(a) L##a +#include "../char/string_view.cc" diff --git a/libstdc++-v3/testsuite/27_io/basic_ostream/inserters_arithmetic/char/hexfloat.cc b/libstdc++-v3/testsuite/27_io/basic_ostream/inserters_arithmetic/char/hexfloat.cc index b1bc7fb..f694730 100644 --- a/libstdc++-v3/testsuite/27_io/basic_ostream/inserters_arithmetic/char/hexfloat.cc +++ b/libstdc++-v3/testsuite/27_io/basic_ostream/inserters_arithmetic/char/hexfloat.cc @@ -95,6 +95,11 @@ test01() void test02() { + /* If these conditions are not met, basic_string.h doesn't define + std::stold(const string&, size_t* = 0), and then the test would + fail to compile. */ +#if (_GLIBCXX_HAVE_STRTOLD && ! _GLIBCXX_HAVE_BROKEN_STRTOLD) \ + || __DBL_MANT_DIG__ == __LDBL_MANT_DIG__ ostringstream os; long double d = 272.L; // 0x1.1p+8L; os << hexfloat << setprecision(1); @@ -140,6 +145,7 @@ test02() cout << "got: " << os.str() << endl; #endif VERIFY( os && os.str() == "15" ); +#endif } int diff --git a/libstdc++-v3/testsuite/27_io/basic_ostringstream/cons/char/string_view.cc b/libstdc++-v3/testsuite/27_io/basic_ostringstream/cons/char/string_view.cc new file mode 100644 index 0000000..6279c19 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/basic_ostringstream/cons/char/string_view.cc @@ -0,0 +1,200 @@ +// C++26 [ostringstream.general] + +// { dg-do run { target c++26 } } + +#include <sstream> +#include <string> +#include <string_view> +#include <testsuite_allocator.h> +#include <testsuite_hooks.h> + +// Check C++26 P2495 ostringstream ctors and members str(s) that accept a +// string_view, or anything convertible to a string_view, in place of a +// string object. Mostly just verify plumbing. + +#ifndef C +# define C char +# define L(a) a +#endif + +using string = std::basic_string<C>; +using string_view = std::basic_string_view<C>; +using ostringstream = std::basic_ostringstream<C>; + +struct convertible_to_string_view { + string s; + operator string_view() const { return s; } +}; + +const string str(L("This is a test string")); +convertible_to_string_view cstr{str}; // a copy +const convertible_to_string_view ccstr{str}; // another copy + +template <typename ostringstream = std::basic_ostringstream<C>> +void +test01() +{ + // Test C++26 constructor and str(s) taking a generalized string_view + + static_assert(! requires { ostringstream(1); }, + "ostringstream ctor should reject what cannot be converted to a string_view"); + static_assert(! requires { ostringstream().str(1); }, + "ostringstream::str(s) should reject what cannot be converted to a string_view"); + + static_assert(!std::is_convertible_v<string_view, ostringstream>, + "ostringstream(string_view, ios::openmode) is explicit"); + static_assert(!std::is_convertible_v<const string_view, ostringstream>, + "ostringstream(string_view, ios::openmode) is explicit"); + static_assert(!std::is_convertible_v<convertible_to_string_view, ostringstream>, + "ostringstream(convertible_to_string_view, ios::openmode) is explicit"); + static_assert(!std::is_convertible_v<const convertible_to_string_view, ostringstream>, + "ostringstream(convertible_to_string_view, ios::openmode) is explicit"); + + { + ostringstream ostrstr(cstr); + VERIFY( ostrstr.str() == cstr.s ); + VERIFY( ostrstr.rdbuf()->sgetc() == ostringstream::traits_type::eof() ); + } + { + ostringstream ostrstr(ccstr); + VERIFY( ostrstr.str() == ccstr.s ); + VERIFY( ostrstr.rdbuf()->sgetc() == ostringstream::traits_type::eof() ); + } + { + ostringstream ostrstr(cstr, std::ios_base::in); + VERIFY( ostrstr.str() == cstr.s ); + VERIFY( ostrstr.rdbuf()->sgetc() == cstr.s[0]); + VERIFY( ostrstr.put('Y').rdstate() == ostrstr.goodbit ); + } + { + ostringstream ostrstr(cstr, std::ios_base::out); + VERIFY( ostrstr.str() == cstr.s ); + VERIFY( ostrstr.rdbuf()->sgetc() == ostringstream::traits_type::eof() ); + VERIFY( ostrstr.put('Y').rdstate() == ostrstr.goodbit ); + } +} + +void +test02() +{ + // Test plumbing of C++26 various constructors taking string views + + auto const mode = std::ios_base::in | std::ios_base::out; + + { + ostringstream::allocator_type a; + // template <typename T> + // basic_ostringstream(const T&, ios_base::openmode, const allocator_type&) + { + ostringstream ostrstr(cstr, mode, a); // ={} checks for non-explicit ctor + VERIFY( ostrstr.str() == cstr.s ); + } + { + ostringstream ostrstr(cstr, std::ios::in, a); + VERIFY( ostrstr.str() == cstr.s ); + VERIFY( ostrstr.rdbuf()->sgetc() == cstr.s[0]); + VERIFY( ostrstr.put('Y').rdstate() == ostrstr.goodbit ); + } + { + ostringstream ostrstr(cstr, std::ios::out, a); + VERIFY( ostrstr.str() == cstr.s ); + VERIFY( ostrstr.rdbuf()->sgetc() == ostringstream::traits_type::eof() ); + VERIFY( ostrstr.put('Y').rdstate() == ostrstr.goodbit ); + } + } + + { + // template <typename T> + // basic_ostringstream(const T&, ios_base::openmode) + { + ostringstream ostrstr(cstr, mode); + VERIFY( ostrstr.str() == cstr.s ); + VERIFY( ostrstr.rdbuf()->sgetc() == cstr.s[0]); + VERIFY( ostrstr.put('Y').good() ); + } + { + ostringstream ostrstr(cstr, std::ios::in); + VERIFY( ostrstr.str() == cstr.s ); + VERIFY( ostrstr.rdbuf()->sgetc() == cstr.s[0]); + VERIFY( ostrstr.put('X').good() ); + } + { + ostringstream ostrstr(cstr, std::ios::out); + VERIFY( ostrstr.str() == cstr.s ); + VERIFY( ostrstr.rdbuf()->sgetc() == ostringstream::traits_type::eof() ); + VERIFY( ostrstr.put('Y').rdstate() == ostrstr.goodbit ); + } + } + + { + // template <typename T> + // explicit + // basic_ostringstream(const T&, ios_base::openmode = ios_base::out) + + ostringstream ostrstr(cstr); + VERIFY( ostrstr.str() == cstr.s ); + VERIFY( ostrstr.rdbuf()->sgetc() == ostringstream::traits_type::eof() ); + VERIFY( ostrstr.put('Y').good() ); + } +} + +using alloc_type = __gnu_test::uneq_allocator<C>; + +template<typename Alloc, typename CC = typename Alloc::value_type> + using ostringstream_with_alloc + = std::basic_ostringstream<CC, std::char_traits<CC>, Alloc>; + +void test03() +{ + alloc_type a{1}; + { + ostringstream_with_alloc<alloc_type> ostrstr(cstr, a); +#if _GLIBCXX_USE_CXX11_ABI + VERIFY( ostrstr.rdbuf()->get_allocator() == a ); +#endif + VERIFY( string_view{ostrstr.str()} == cstr ); + VERIFY( ostrstr.rdbuf()->sgetc() == ostringstream::traits_type::eof() ); + VERIFY( ostrstr.put('X').good() ); + } + { + ostringstream_with_alloc<alloc_type> ostrstr(cstr, std::ios::in, a); +#if _GLIBCXX_USE_CXX11_ABI + VERIFY( ostrstr.rdbuf()->get_allocator() == a ); +#endif + VERIFY( string_view{ostrstr.str()} == cstr ); + VERIFY( ostrstr.rdbuf()->sgetc() == cstr.s[0]); + VERIFY( ostrstr.put('X').good() ); + } + { + ostringstream_with_alloc<alloc_type> ostrstr(cstr, std::ios::out, a); +#if _GLIBCXX_USE_CXX11_ABI + VERIFY( ostrstr.rdbuf()->get_allocator() == a ); +#endif + VERIFY( string_view{ostrstr.str()} == cstr ); + VERIFY( ostrstr.rdbuf()->sgetc() == ostringstream::traits_type::eof() ); + VERIFY( ostrstr.put('Y').rdstate() == ostrstr.goodbit ); + } +} + +void test04() +{ + { + ostringstream ostrstr; + ostrstr.str(cstr); + VERIFY( ostrstr.str() == cstr.s ); + } + { + ostringstream ostrstr; + ostrstr.str(ccstr); + VERIFY( ostrstr.str() == ccstr.s ); + } +} + +int +main() +{ + test01(); + test02(); + test03(); + test04(); +} diff --git a/libstdc++-v3/testsuite/27_io/basic_ostringstream/cons/wchar_t/string_view.cc b/libstdc++-v3/testsuite/27_io/basic_ostringstream/cons/wchar_t/string_view.cc new file mode 100644 index 0000000..ee6ac8d --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/basic_ostringstream/cons/wchar_t/string_view.cc @@ -0,0 +1,6 @@ +// C++26 [ostringstream.general] +// { dg-do run { target c++26 } } + +#define C wchar_t +#define L(a) L##a +#include "../char/string_view.cc" diff --git a/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/char/string_view.cc b/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/char/string_view.cc new file mode 100644 index 0000000..14278b3 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/char/string_view.cc @@ -0,0 +1,211 @@ +// C++26 31.8.2.1 [stringbuf.general] + +// { dg-do run { target c++26 } } + +#include <sstream> +#include <string> +#include <string_view> +#include <testsuite_allocator.h> +#include <testsuite_hooks.h> + +// Check C++26 P2495 stringbuf ctors and members str(s) that accept a +// string_view, or anything convertible to a string_view, in place of a +// string object. + +#ifndef C +# define C char +# define L(a) a +#endif + +using string = std::basic_string<C>; +using string_view = std::basic_string_view<C>; +using stringbuf = std::basic_stringbuf<C>; + +struct convertible_to_string_view { + string s; + operator string_view() const { return s; } +}; + +const string str(L("This is a test string")); +convertible_to_string_view cstr{str}; // a copy +const convertible_to_string_view ccstr{str}; // another copy + +template <typename stringbuf = std::basic_stringbuf<C>> +void +test01() +{ + // Test C++26 constructor and str(s) taking a generalized string_view + + static_assert(! requires { stringbuf(1); }, + "stringbuf ctor should reject what cannot be converted to a string_view"); + static_assert(! requires { stringbuf().str(1); }, + "stringbuf::str(s) should reject what cannot be converted to a string_view"); + + static_assert(!std::is_convertible_v<string_view, stringbuf>, + "stringbuf(string_view, ios::openmode) is explicit"); + static_assert(!std::is_convertible_v<const string_view, stringbuf>, + "stringbuf(string_view, ios::openmode) is explicit"); + static_assert(!std::is_convertible_v<convertible_to_string_view, stringbuf>, + "stringbuf(convertible_to_string_view, ios::openmode) is explicit"); + static_assert( + !std::is_convertible_v<const convertible_to_string_view, stringbuf>, + "stringbuf(convertible_to_string_view, ios::openmode) is explicit"); + + { + stringbuf sbuf(cstr); + VERIFY( sbuf.str() == cstr.s ); + VERIFY( sbuf.sgetc() == cstr.s[0] ); + } + { + stringbuf sbuf(ccstr); + VERIFY( sbuf.str() == ccstr.s ); + VERIFY( sbuf.sgetc() == ccstr.s[0] ); + } + { + stringbuf sbuf(cstr, std::ios_base::in); + VERIFY( sbuf.str() == cstr.s ); + VERIFY( sbuf.sgetc() == cstr.s[0] ); + VERIFY( sbuf.sputc('X') == stringbuf::traits_type::eof() ); + } + { + stringbuf sbuf(ccstr, std::ios_base::in); + VERIFY( sbuf.str() == ccstr.s ); + VERIFY( sbuf.sgetc() == ccstr.s[0] ); + VERIFY( sbuf.sputc('X') == stringbuf::traits_type::eof() ); + } + { + stringbuf sbuf(cstr, std::ios_base::out); + VERIFY( sbuf.str() == cstr.s ); + VERIFY( sbuf.sputc('Y') == 'Y' ); + VERIFY( sbuf.sgetc() == stringbuf::traits_type::eof() ); + } + { + stringbuf sbuf(ccstr, std::ios_base::out); + VERIFY( sbuf.str() == ccstr.s ); + VERIFY( sbuf.sputc('Y') == 'Y' ); + VERIFY( sbuf.sgetc() == stringbuf::traits_type::eof() ); + } +} + +void +test02() +{ + // Test C++26 constructors taking string views using different allocators + + auto const mode = std::ios_base::in | std::ios_base::out; + + { + // template <typename T> + // basic_stringbuf(const T&, ios_base::openmode, const allocator_type&) + + stringbuf::allocator_type a; + { + stringbuf sbuf(cstr, mode, a); // ={} checks for non-explicit ctor + VERIFY( sbuf.str() == cstr.s ); + } + { + stringbuf sbuf(cstr, std::ios::in, a); + VERIFY( sbuf.str() == cstr.s ); + VERIFY( sbuf.sgetc() == cstr.s[0] ); + VERIFY( sbuf.sputc('X') == stringbuf::traits_type::eof() ); + } + + { + stringbuf sbuf(cstr, std::ios::out, a); + VERIFY( sbuf.str() == cstr.s ); + VERIFY( sbuf.sputc('X') == 'X' ); + VERIFY( sbuf.sgetc() == stringbuf::traits_type::eof() ); + } + } + + { + // template <typename T> + // basic_stringbuf(const T&, ios_base::openmode) + { + stringbuf sbuf(cstr, mode); + VERIFY( sbuf.str() == cstr.s ); + } + { + stringbuf sbuf(cstr, std::ios::in); + VERIFY( sbuf.str() == cstr.s ); + VERIFY( sbuf.sgetc() == cstr.s[0] ); + VERIFY( sbuf.sputc('X') == stringbuf::traits_type::eof() ); + } + { + stringbuf sbuf(cstr, std::ios::out); + VERIFY( sbuf.str() == cstr.s ); + VERIFY( sbuf.sputc('X') == 'X' ); + VERIFY( sbuf.sgetc() == stringbuf::traits_type::eof() ); + } + } + + { + // template <typename T> + // explicit + // basic_stringbuf(const T&, ios_base::openmode = ios_base::in|ios_base::out) + + stringbuf sbuf(cstr); + VERIFY( sbuf.str() == cstr.s ); + VERIFY( sbuf.sgetc() == cstr.s[0] ); + } +} + +using alloc_type = __gnu_test::uneq_allocator<C>; + +template<typename Alloc, typename CC = typename Alloc::value_type> + using stringbuf_with_alloc + = std::basic_stringbuf<CC, std::char_traits<CC>, Alloc>; + +void test03() +{ + alloc_type a{1}; + { + stringbuf_with_alloc<alloc_type> sbuf(cstr, a); +#if _GLIBCXX_USE_CXX11_ABI + VERIFY( sbuf.get_allocator() == a ); +#endif + VERIFY( string_view{sbuf.str()} == cstr ); + VERIFY( sbuf.sgetc() == cstr.s[0] ); + } + { + stringbuf_with_alloc<alloc_type> sbuf(cstr, std::ios::in, a); +#if _GLIBCXX_USE_CXX11_ABI + VERIFY( sbuf.get_allocator() == a ); +#endif + VERIFY( string_view{sbuf.str()} == cstr ); + VERIFY( sbuf.sgetc() == cstr.s[0] ); + VERIFY( sbuf.sputc('X') == stringbuf::traits_type::eof() ); + } + { + stringbuf_with_alloc<alloc_type> sbuf(cstr, std::ios::out, a); +#if _GLIBCXX_USE_CXX11_ABI + VERIFY( sbuf.get_allocator() == a ); +#endif + VERIFY( string_view{sbuf.str()} == cstr ); + VERIFY( sbuf.sputc('X') == 'X' ); + VERIFY( sbuf.sgetc() == stringbuf::traits_type::eof() ); + } +} + +void test04() +{ + { + stringbuf sbuf; + sbuf.str(cstr); + VERIFY( sbuf.str() == cstr.s ); + } + { + stringbuf sbuf; + sbuf.str(ccstr); + VERIFY( sbuf.str() == ccstr.s ); + } +} + +int +main() +{ + test01(); + test02(); + test03(); + test04(); +} diff --git a/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/wchar_t/string_view.cc b/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/wchar_t/string_view.cc new file mode 100644 index 0000000..c428491 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/wchar_t/string_view.cc @@ -0,0 +1,6 @@ +// C++26 [stringbuf.general] +// { dg-do run { target c++26 } } + +#define C wchar_t +#define L(a) L##a +#include "../char/string_view.cc" diff --git a/libstdc++-v3/testsuite/27_io/basic_stringstream/cons/char/string_view.cc b/libstdc++-v3/testsuite/27_io/basic_stringstream/cons/char/string_view.cc new file mode 100644 index 0000000..1c9ecea --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/basic_stringstream/cons/char/string_view.cc @@ -0,0 +1,210 @@ +// C++26 31.8.2.1 [stringstream.general] + +// { dg-do run { target c++26 } } + +#include <sstream> +#include <string> +#include <string_view> +#include <testsuite_allocator.h> +#include <testsuite_hooks.h> + +// Check C++26 P2495 stringstream ctors and members str(s) that accept a +// string_view, or anything convertible to a string_view, in place of a +// string object. Mostly just verify plumbing. + +#ifndef C +# define C char +# define L(a) a +#endif + +using string = std::basic_string<C>; +using string_view = std::basic_string_view<C>; +using stringstream = std::basic_stringstream<C>; + +struct convertible_to_string_view { + string s; + operator string_view() const { return s; } +}; + +const string str(L("This is a test string")); +convertible_to_string_view cstr{str}; // a copy +const convertible_to_string_view ccstr{str}; // another copy + +template <typename stringstream = std::basic_stringstream<C>> +void +test01() +{ + // Test C++26 constructor and str(s) taking a generalized string_view + + static_assert(! requires { stringstream(1); }, + "stringstream ctor should reject what cannot be converted to a string_view"); + static_assert(! requires { stringstream().str(1); }, + "stringstream::str(s) should reject what cannot be converted to a string_view"); + + static_assert(!std::is_convertible_v<string_view, stringstream>, + "stringstream(string_view, ios::openmode) is explicit"); + static_assert(!std::is_convertible_v<const string_view, stringstream>, + "stringstream(string_view, ios::openmode) is explicit"); + static_assert(!std::is_convertible_v<convertible_to_string_view, stringstream>, + "stringstream(convertible_to_string_view, ios::openmode) is explicit"); + static_assert(!std::is_convertible_v<const convertible_to_string_view, stringstream>, + "stringstream(convertible_to_string_view, ios::openmode) is explicit"); + + { + stringstream strstr(cstr); + VERIFY( strstr.str() == cstr.s ); + VERIFY( strstr.get() == cstr.s[0] ); + } + { + stringstream strstr(ccstr); + VERIFY( strstr.str() == ccstr.s ); + VERIFY( strstr.get() == ccstr.s[0] ); + } + { + stringstream strstr(cstr, std::ios_base::in); + VERIFY( strstr.str() == cstr.s ); + VERIFY( strstr.get() == cstr.s[0] ); + VERIFY( strstr.put('X').rdstate() == strstr.badbit ); + } + { + stringstream strstr(cstr, std::ios_base::out); + VERIFY( strstr.str() == cstr.s ); + VERIFY( strstr.put('Y').good() ); + VERIFY( strstr.get() == stringstream::traits_type::eof()); + } +} + +void +test02() +{ + // Test C++26 various constructors taking string views + + auto const mode = std::ios_base::in | std::ios_base::out; + + { + // template <typename T> + // basic_stringstream(const T&, ios_base::openmode, const allocator_type&) + + stringstream::allocator_type a; + { + stringstream strstr(cstr, mode, a); // ={} checks for non-explicit ctor + VERIFY( strstr.str() == cstr.s ); + } + { + stringstream strstr(cstr, std::ios::in, a); + VERIFY( strstr.str() == cstr.s ); + VERIFY( strstr.get() == cstr.s[0] ); + VERIFY( strstr.put('X').rdstate() == strstr.badbit ); + } + { + stringstream strstr(cstr, std::ios::out, a); + VERIFY( strstr.str() == cstr.s ); + VERIFY( strstr.put('X').good() ); + VERIFY( strstr.get() == stringstream::traits_type::eof()); + } + } + + { + // template <typename T> + // basic_stringstream(const T&, ios_base::openmode) + + { + stringstream strstr(cstr, mode); + VERIFY( strstr.str() == cstr.s ); + VERIFY( strstr.get() == cstr.s[0] ); + VERIFY( strstr.put('X').good() ); + } + { + stringstream strstr(cstr, std::ios::in); + VERIFY( strstr.str() == cstr.s ); + VERIFY( strstr.get() == cstr.s[0] ); + VERIFY( strstr.put('X').rdstate() == strstr.badbit ); + } + { + stringstream strstr(cstr, std::ios::out); + VERIFY( strstr.str() == cstr.s ); + VERIFY( strstr.put('X').good() ); + VERIFY( strstr.get() == stringstream::traits_type::eof()); + } + } + + { + // template <typename T> + // explicit + // basic_stringstream(const T&, ios_base::openmode = ios_base::in|ios_base::out) + + stringstream strstr(cstr); + VERIFY( strstr.str() == cstr.s ); + VERIFY( strstr.get() == cstr.s[0] ); + VERIFY( strstr.put('X').good() ); + } +} + +// A minimal allocator with no default constructor +template<typename T> + struct NoDefaultCons : __gnu_test::SimpleAllocator<T> + { + using __gnu_test::SimpleAllocator<T>::SimpleAllocator; + NoDefaultCons() = delete; + NoDefaultCons(int) { } + }; + +using alloc_type = __gnu_test::uneq_allocator<C>; + +template<typename Alloc, typename CC = typename Alloc::value_type> + using stringstream_with_alloc + = std::basic_stringstream<CC, std::char_traits<CC>, Alloc>; + +void test03() +{ + alloc_type a{1}; + { + stringstream_with_alloc<alloc_type> strstr(cstr, a); +#if _GLIBCXX_USE_CXX11_ABI + VERIFY( strstr.rdbuf()->get_allocator() == a ); +#endif + VERIFY( string_view{strstr.str()} == cstr ); + VERIFY( strstr.get() == cstr.s[0] ); + } + { + stringstream_with_alloc<alloc_type> strstr(cstr, std::ios::in, a); +#if _GLIBCXX_USE_CXX11_ABI + VERIFY( strstr.rdbuf()->get_allocator() == a ); +#endif + VERIFY( string_view{strstr.str()} == cstr ); + VERIFY( strstr.get() == cstr.s[0] ); + VERIFY( strstr.put('X').rdstate() == strstr.badbit ); + } + { + stringstream_with_alloc<alloc_type> strstr(cstr, std::ios::out, a); +#if _GLIBCXX_USE_CXX11_ABI + VERIFY( strstr.rdbuf()->get_allocator() == a ); +#endif + VERIFY( string_view{strstr.str()} == cstr ); + VERIFY( strstr.put('X').good() ); + VERIFY( strstr.get() == stringstream::traits_type::eof()); + } +} + +void test04() +{ + { + stringstream strstr; + strstr.str( cstr ); + VERIFY( strstr.str() == cstr.s ); + } + { + stringstream strstr; + strstr.str( ccstr ); + VERIFY( strstr.str() == ccstr.s ); + } +} + +int +main() +{ + test01(); + test02(); + test03(); + test04(); +} diff --git a/libstdc++-v3/testsuite/27_io/basic_stringstream/cons/wchar_t/string_view.cc b/libstdc++-v3/testsuite/27_io/basic_stringstream/cons/wchar_t/string_view.cc new file mode 100644 index 0000000..921c0fe --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/basic_stringstream/cons/wchar_t/string_view.cc @@ -0,0 +1,6 @@ +// C++26 [stringstream.general] +// { dg-do run { target c++26 } } + +#define C wchar_t +#define L(a) L##a +#include "../char/string_view.cc" diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/concat/120029.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/concat/120029.cc new file mode 100644 index 0000000..5153d59 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/concat/120029.cc @@ -0,0 +1,72 @@ +// { dg-do run { target c++17 } } + +// Bug libstdc++/120029 +// Dangling iterator usage in path::operator+=(const path& p) when this == p + +#include <filesystem> +#include <testsuite_hooks.h> + +namespace fs = std::filesystem; + +void +test_root_dir() +{ + fs::path p = "/"; + p += p; + p += p; + VERIFY( p == "////" ); + p += p.filename(); + VERIFY( p == "////" ); + p += *std::prev(p.end()); + VERIFY( p == "////" ); +} + +void +test_root_name() +{ + fs::path p = "C:/"; + p += p; + p += p; + VERIFY( p == "C:/C:/C:/C:/" ); + p += p.filename(); + VERIFY( p == "C:/C:/C:/C:/" ); + p += *std::prev(p.end()); + VERIFY( p == "C:/C:/C:/C:/" ); +} + +void +test_filename() +{ + fs::path p = "file"; + p += p; + p += p; + VERIFY( p == "filefilefilefile" ); + p += p.filename(); + VERIFY( p == "filefilefilefilefilefilefilefile" ); + p += *std::prev(p.end()); + VERIFY( p == "filefilefilefilefilefilefilefilefilefilefilefilefilefilefilefile" ); +} + +void +test_multi() +{ + fs::path p = "/home/username/Documents/mu"; + p += p; + p += p; + VERIFY( p == "/home/username/Documents/mu/home/username/Documents/mu/home/username/Documents/mu/home/username/Documents/mu" ); + p += p.filename(); + VERIFY( p == "/home/username/Documents/mu/home/username/Documents/mu/home/username/Documents/mu/home/username/Documents/mumu" ); + p += *std::prev(p.end()); + VERIFY( p == "/home/username/Documents/mu/home/username/Documents/mu/home/username/Documents/mu/home/username/Documents/mumumumu" ); + auto n = std::distance(p.begin(), p.end()); + for (int i = 0; i < n; ++i) + p += *std::next(p.begin(), i); +} + +int main() +{ + test_root_dir(); + test_root_name(); + test_filename(); + test_multi(); +} diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/100334.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/100334.cc index 018c0c9..21ff570c 100644 --- a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/100334.cc +++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/100334.cc @@ -47,16 +47,17 @@ int main() { // all atomic share the same waiter -// atomics_sharing_same_waiter<char> atomics; atomics_sharing_same_waiter<char> atomics; for (auto& atom : atomics.a) { atom->store(0); } - auto a = &std::__detail::__waiter_pool_base::_S_for(reinterpret_cast<char *>(atomics.a[0])); - auto b = &std::__detail::__waiter_pool_base::_S_for(reinterpret_cast<char *>(atomics.a[1])); +#if 0 + auto a = &std::__detail::__waitable_state::_S_state_for((void*)(atomics.a[0])); + auto b = &std::__detail::__waitable_state::_S_state_for((void*)(atomics.a[1])); VERIFY( a == b ); +#endif auto fut0 = std::async(std::launch::async, [&] { atomics.a[0]->wait(0); }); auto fut1 = std::async(std::launch::async, [&] { atomics.a[1]->wait(0); }); diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_integral/wait_notify.cc b/libstdc++-v3/testsuite/29_atomics/atomic_integral/wait_notify.cc index c7f8779..6e74f2c 100644 --- a/libstdc++-v3/testsuite/29_atomics/atomic_integral/wait_notify.cc +++ b/libstdc++-v3/testsuite/29_atomics/atomic_integral/wait_notify.cc @@ -33,12 +33,16 @@ template<typename Tp> std::atomic<Tp> a{ Tp(1) }; VERIFY( a.load() == Tp(1) ); a.wait( Tp(0) ); + std::atomic<bool> b{false}; std::thread t([&] { - a.store(Tp(0)); - a.notify_one(); + b.store(true, std::memory_order_relaxed); + a.store(Tp(0)); + a.notify_one(); }); a.wait(Tp(1)); + // Ensure we actually waited until a.store(0) happened: + VERIFY( b.load(std::memory_order_relaxed) ); t.join(); } diff --git a/libstdc++-v3/testsuite/30_threads/barrier/1.cc b/libstdc++-v3/testsuite/30_threads/barrier/1.cc index eff8ef3..01c55d9 100644 --- a/libstdc++-v3/testsuite/30_threads/barrier/1.cc +++ b/libstdc++-v3/testsuite/30_threads/barrier/1.cc @@ -16,7 +16,8 @@ // <http://www.gnu.org/licenses/>. // { dg-do compile { target c++20 } } -// { dg-require-effective-target gthreads } +// { dg-require-effective-target gthreads { target { ! *-*-linux* } } } +// { dg-require-effective-target hosted } // { dg-add-options no_pch } #include <barrier> diff --git a/libstdc++-v3/testsuite/30_threads/barrier/2.cc b/libstdc++-v3/testsuite/30_threads/barrier/2.cc index e0188b3..728030b 100644 --- a/libstdc++-v3/testsuite/30_threads/barrier/2.cc +++ b/libstdc++-v3/testsuite/30_threads/barrier/2.cc @@ -16,7 +16,7 @@ // <http://www.gnu.org/licenses/>. // { dg-do compile { target c++20 } } -// { dg-require-effective-target gthreads } +// { dg-require-effective-target gthreads { target { ! *-*-linux* } } } // { dg-require-effective-target hosted } // { dg-add-options no_pch } diff --git a/libstdc++-v3/testsuite/30_threads/barrier/cons.cc b/libstdc++-v3/testsuite/30_threads/barrier/cons.cc new file mode 100644 index 0000000..0b80514 --- /dev/null +++ b/libstdc++-v3/testsuite/30_threads/barrier/cons.cc @@ -0,0 +1,6 @@ +// { dg-do compile { target c++20 } } + +#include <barrier> + +// PR 118395 Constructor of std::barrier is not constexpr +constinit std::barrier<> b(std::barrier<>::max()); diff --git a/libstdc++-v3/testsuite/30_threads/barrier/lwg3898.cc b/libstdc++-v3/testsuite/30_threads/barrier/lwg3898.cc new file mode 100644 index 0000000..e3160dc --- /dev/null +++ b/libstdc++-v3/testsuite/30_threads/barrier/lwg3898.cc @@ -0,0 +1,45 @@ +// { dg-do run { target c++20 } } +// { dg-require-effective-target gthreads } + +#include <barrier> +#include <exception> +#include <cstdlib> +#if !_GLIBCXX_USE_C99_STDLIB && defined _GLIBCXX_HAVE_UNISTD_H +# include <unistd.h> +#endif + +void handle_terminate() +{ +#if _GLIBCXX_USE_C99_STDLIB + std::_Exit(0); +#elif defined _GLIBCXX_HAVE_UNISTD_H + _exit(0); +#else + std::exit(0); +#endif +} + +struct F +{ + void operator()() + { + std::set_terminate(handle_terminate); + throw 1; + } +}; + +void +test_lwg3898() +{ + std::barrier<F> b(1, F{}); + // This should call the terminate handler and exit with zero status: + b.arrive_and_wait(); + // Should not reach here: + std::abort(); +} + +int +main() +{ + test_lwg3898(); +} diff --git a/libstdc++-v3/testsuite/30_threads/packaged_task/cons/dangling_ref.cc b/libstdc++-v3/testsuite/30_threads/packaged_task/cons/dangling_ref.cc index 51c6ade..8cc3f78 100644 --- a/libstdc++-v3/testsuite/30_threads/packaged_task/cons/dangling_ref.cc +++ b/libstdc++-v3/testsuite/30_threads/packaged_task/cons/dangling_ref.cc @@ -8,6 +8,5 @@ int f(); std::packaged_task<const int&()> task(f); // { dg-error "dangling reference" "" { target { c++14_down } } 0 } // { dg-error "reference to temporary" "" { target { c++14_down } } 0 } -// { dg-error "no matching function" "" { target c++17 } 0 } -// { dg-error "enable_if" "" { target c++17 } 0 } // { dg-error "static assertion failed" "" { target c++17 } 0 } +// { dg-error "note: .*std::is_invocable_r" "" { target c++17 } 0 } diff --git a/libstdc++-v3/testsuite/30_threads/packaged_task/cons/lwg4154_neg.cc b/libstdc++-v3/testsuite/30_threads/packaged_task/cons/lwg4154_neg.cc index 6ba1bb1..b3413c2 100644 --- a/libstdc++-v3/testsuite/30_threads/packaged_task/cons/lwg4154_neg.cc +++ b/libstdc++-v3/testsuite/30_threads/packaged_task/cons/lwg4154_neg.cc @@ -12,16 +12,16 @@ struct F { // Mandates: is_invocable_r_v<R, decay_t<F>&, ArgTypes...> is true. const F f; -std::packaged_task<void()> p(f); // { dg-error "here" "" { target c++17 } } -// { dg-error "static assertion failed" "" { target c++17 } 0 } -// { dg-error "invoke_r" "" { target *-*-* } 0 } -// { dg-prune-output "enable_if<false" } +std::packaged_task<void()> p(f); // { dg-error "here" } +// { dg-error "static assertion failed" "" { target *-*-* } 0 } +// { dg-error "note: .*std::is_invocable_r_v<void, " "" { target c++17 } 0 } // Only callable as rvalue struct Frv { int* operator()() && { return 0; } }; -std::packaged_task<int*()> p2(Frv{}); // { dg-error "here" "" { target c++17 } } +std::packaged_task<int*()> p2(Frv{}); // { dg-error "here" } +// { dg-error "note: .*std::is_invocable_r_v<int., " "" { target c++17 } 0 } // Only callable as non-const lvalue struct Fnc { diff --git a/libstdc++-v3/testsuite/30_threads/scoped_lock/requirements/typedefs.cc b/libstdc++-v3/testsuite/30_threads/scoped_lock/requirements/typedefs.cc index 4cd07da..ba52b36 100644 --- a/libstdc++-v3/testsuite/30_threads/scoped_lock/requirements/typedefs.cc +++ b/libstdc++-v3/testsuite/30_threads/scoped_lock/requirements/typedefs.cc @@ -1,5 +1,4 @@ // { dg-do compile { target c++17 } } -// { dg-require-gthreads "" } // { dg-add-options no_pch } // Copyright (C) 2017-2025 Free Software Foundation, Inc. @@ -29,9 +28,30 @@ # error "Feature-test macro for scoped_lock has wrong value" #endif +struct BasicLockable +{ + BasicLockable() = default; + ~BasicLockable() = default; + void lock() { } + void unlock() { } +}; + void test01() { - // Check for required typedefs - typedef std::scoped_lock<std::mutex> test_type; - typedef test_type::mutex_type mutex_type; + // Check for required typedef. + using test_type = std::scoped_lock<BasicLockable>; + static_assert(std::is_same_v<test_type::mutex_type, BasicLockable>); +} + +template<typename T, typename = void> +constexpr bool has_mutex_type = false; + +template<typename T> +constexpr bool has_mutex_type<T, std::void_t<typename T::mutex_type>> = true; + +void test02() +{ + // Check that typedef is absent as required. + using test_type = std::scoped_lock<BasicLockable, BasicLockable>; + static_assert(!has_mutex_type<test_type>); } diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/1.cc b/libstdc++-v3/testsuite/30_threads/semaphore/1.cc index ac9f97b..9472def 100644 --- a/libstdc++-v3/testsuite/30_threads/semaphore/1.cc +++ b/libstdc++-v3/testsuite/30_threads/semaphore/1.cc @@ -16,6 +16,8 @@ // <http://www.gnu.org/licenses/>. // { dg-do compile { target c++20 } } +// { dg-require-effective-target gthreads { target { ! *-*-linux* } } } +// { dg-require-effective-target hosted } // { dg-add-options no_pch } #include <semaphore> @@ -25,3 +27,25 @@ #elif __cpp_lib_semaphore != 201907L # error "Feature-test macro for semaphore has wrong value in <semaphore>" #endif + +static_assert(std::is_same_v<std::counting_semaphore<1>, + std::binary_semaphore>); + +static_assert(! std::is_same_v<std::counting_semaphore<2>, + std::binary_semaphore>); + +static_assert(! std::is_same_v<std::counting_semaphore<>, + std::binary_semaphore>); + +// The standard permits max() to be greater than the template argument, +// but for the current libstdc++ implementation it's always equal to it. +static_assert(std::binary_semaphore::max() == 1); +static_assert(std::counting_semaphore<0>::max() == 0); +static_assert(std::counting_semaphore<2>::max() == 2); + +#include <limits.h> + +static_assert(std::counting_semaphore<INT_MAX>::max() == INT_MAX); +static_assert(std::counting_semaphore<INT_MAX-1>::max() == INT_MAX-1); +static_assert(std::counting_semaphore<PTRDIFF_MAX>::max() == PTRDIFF_MAX); +static_assert(std::counting_semaphore<PTRDIFF_MAX-3>::max() == PTRDIFF_MAX-3); diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/100806.cc b/libstdc++-v3/testsuite/30_threads/semaphore/100806.cc index c770f05..4b761ce 100644 --- a/libstdc++-v3/testsuite/30_threads/semaphore/100806.cc +++ b/libstdc++-v3/testsuite/30_threads/semaphore/100806.cc @@ -12,7 +12,7 @@ #include <chrono> #include <vector> -std::counting_semaphore<4> semaphore{6}; +std::counting_semaphore<6> semaphore{6}; std::mutex mtx; std::vector<std::string> results; diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/104928-2.cc b/libstdc++-v3/testsuite/30_threads/semaphore/104928-2.cc new file mode 100644 index 0000000..7b90da8 --- /dev/null +++ b/libstdc++-v3/testsuite/30_threads/semaphore/104928-2.cc @@ -0,0 +1,101 @@ +// { dg-do run { target c++20 } } +// { dg-additional-options "-pthread" { target pthread } } +// { dg-require-gthreads "" } +// { dg-add-options libatomic } + +// Bug libstdc++/104928 - std::counting_semaphore on Linux can sleep forever + +#include <semaphore> +#include <thread> +#include <chrono> +#include <atomic> + +std::binary_semaphore t1(1); +std::binary_semaphore sem2(0); +std::atomic<int> room1 = 0; +int room2 = 0; + +std::atomic<bool> run{true}; + +enum class AcquireKind { Acquire, Try, TryFor }; + +template<std::ptrdiff_t N, AcquireKind Kind> +struct Morris +{ + using Semaphore = std::counting_semaphore<N>; + + Semaphore sem1{1}; + Semaphore sem2{0}; + unsigned counter = 0; + + void operator()() + { + while (run) + { + room1 += 1; + + acquire(sem1); + room2 += 1; + room1 -= 1; + if (room1 == 0) + sem2.release(); + else + sem1.release(); + + acquire(sem2); + room2 -= 1; + + // critical region + ++counter; + // end critical region + + if (room2 == 0) + sem1.release(); + else + sem2.release(); + } + } + + void acquire(Semaphore& sem) + { + using enum AcquireKind; + using namespace std::chrono; + if constexpr (Kind == Acquire) + sem.acquire(); + else if constexpr (Kind == Try) + while (!sem.try_acquire()) { } + else if constexpr (Kind == TryFor) + while (!sem.try_acquire_for(1h)) { } + } +}; + +template<std::ptrdiff_t N, AcquireKind Kind> +void +test_morris_kind() +{ + Morris<N, Kind> algo; + std::thread t1(std::ref(algo)); + std::thread t2(std::ref(algo)); + std::this_thread::sleep_for(std::chrono::seconds(2)); + run = false; + t1.join(); + t2.join(); +} + +template<std::ptrdiff_t N> +void +test_morris() +{ + test_morris_kind<N, AcquireKind::Acquire>(); + test_morris_kind<N, AcquireKind::Try>(); + test_morris_kind<N, AcquireKind::TryFor>(); +} + +int main() +{ + test_morris<1>(); // std::binary_semaphore + test_morris<1000>(); // std::counting_semaphore that can use futex +#if PTRDIFF_MAX > INT_MAX + // test_morris<PTRDIFF_MAX>(); // std::counting_semaphore that cannot use futex +#endif +} diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/104928.cc b/libstdc++-v3/testsuite/30_threads/semaphore/104928.cc new file mode 100644 index 0000000..f360da9 --- /dev/null +++ b/libstdc++-v3/testsuite/30_threads/semaphore/104928.cc @@ -0,0 +1,70 @@ +// { dg-do run { target c++20 } } +// { dg-additional-options "-pthread" { target pthread } } +// { dg-require-gthreads "" } +// { dg-add-options libatomic } +// { dg-options "-DSIMULATOR_TEST" { target simulator } } + +// Bug libstdc++/104928 - std::counting_semaphore on Linux can sleep forever + +#include <semaphore> +#include <thread> +#include <chrono> +#include <climits> + +#ifdef SIMULATOR_TEST +const int loop_count = 100; +const int thread_count = 6; +#else +const int loop_count = 1000000; +const int thread_count = 20; +#endif + +template<std::ptrdiff_t N, typename Acquire> +void +test_acquire(Acquire acq_func) +{ + std::counting_semaphore<N * loop_count> s{0}; + std::thread threads[thread_count]; + for (int i = 0; i < thread_count; i += 2) { + threads[i] = std::thread([&s, &acq_func]() { + for (int i = 0; i < loop_count; ++i) + acq_func(s); + }); + threads[i+1] = std::thread([&s]() { + for (int i = 0; i < loop_count; ++i) + s.release(); + }); + } + for (auto& t : threads) + t.join(); +} + +template<typename Acquire> +void +test_all(Acquire f) +{ + const int max = INT_MAX / loop_count; + test_acquire<max>(f); // can use futex +#if PTRDIFF_MAX > INT_MAX + test_acquire<max * 10>(f); // cannot use futex +#endif +} + +int main() +{ + test_all([](auto& sem) { sem.acquire(); }); + + test_all([](auto& sem) { while (!sem.try_acquire()) { } }); + + using namespace std::chrono; + + test_all([](auto& sem) { while (!sem.try_acquire_for(1h)) { } }); + + auto try_acquire_until = [](auto& sem, auto time) { + while (!sem.try_acquire_until(time + 1h)) + { } + }; + test_all([&](auto& sem) { try_acquire_until(sem, system_clock::now()); }); + test_all([&](auto& sem) { try_acquire_until(sem, steady_clock::now()); }); + test_all([&](auto& sem) { try_acquire_until(sem, utc_clock::now()); }); +} diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/2.cc b/libstdc++-v3/testsuite/30_threads/semaphore/2.cc index 251e96a..bff747c 100644 --- a/libstdc++-v3/testsuite/30_threads/semaphore/2.cc +++ b/libstdc++-v3/testsuite/30_threads/semaphore/2.cc @@ -16,6 +16,7 @@ // <http://www.gnu.org/licenses/>. // { dg-do compile { target c++20 } } +// { dg-require-effective-target gthreads { target { ! *-*-linux* } } } // { dg-require-effective-target hosted } // { dg-add-options no_pch } diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/3.cc b/libstdc++-v3/testsuite/30_threads/semaphore/3.cc new file mode 100644 index 0000000..51b9fbb --- /dev/null +++ b/libstdc++-v3/testsuite/30_threads/semaphore/3.cc @@ -0,0 +1,19 @@ +// { dg-do compile { target *-*-*linux* } } +// { dg-require-effective-target c++20 } +// { dg-require-effective-target hosted } + +#include <semaphore> +#include <limits.h> + +// on Linux these specializations all use a futex: +static_assert(sizeof(std::counting_semaphore<0>) == sizeof(int)); +static_assert(sizeof(std::counting_semaphore<1>) == sizeof(int)); +static_assert(sizeof(std::counting_semaphore<INT_MAX>) == sizeof(int)); +static_assert(sizeof(std::counting_semaphore<>) == sizeof(int)); + +// This will use a futex iff ptrdiff_t has 32 bits: +static_assert(sizeof(std::counting_semaphore<PTRDIFF_MAX>) == sizeof(std::ptrdiff_t)); + +#if PTRDIFF_MAX > INT_MAX +static_assert(sizeof(std::counting_semaphore<INT_MAX+1LL>) == sizeof(std::ptrdiff_t)); +#endif diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/cons.cc b/libstdc++-v3/testsuite/30_threads/semaphore/cons.cc new file mode 100644 index 0000000..790ff2e --- /dev/null +++ b/libstdc++-v3/testsuite/30_threads/semaphore/cons.cc @@ -0,0 +1,9 @@ +// { dg-do compile { target c++20 } } +// { dg-require-effective-target gthreads { target { ! *-*-linux* } } } +// { dg-require-effective-target hosted } + +#include <semaphore> + +// PR 110854 Constructor of std::counting_semaphore is not constexpr +constinit std::binary_semaphore b(0); +constinit std::counting_semaphore<5> c(2); diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/cons_neg.cc b/libstdc++-v3/testsuite/30_threads/semaphore/cons_neg.cc new file mode 100644 index 0000000..56e27d7 --- /dev/null +++ b/libstdc++-v3/testsuite/30_threads/semaphore/cons_neg.cc @@ -0,0 +1,12 @@ +// { dg-options "-D_GLIBCXX_ASSERTIONS" } +// { dg-do run { target c++20 xfail *-*-* } } +// { dg-require-effective-target hosted } +// { dg-add-options libatomic } + +#include <semaphore> + +int main() +{ + // Preconditions: desired >= 0 is true, and desired <= max() is true. + std::binary_semaphore b(2); +} diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc b/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc index 1498d38..e2680b1 100644 --- a/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc +++ b/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc @@ -16,8 +16,8 @@ // <http://www.gnu.org/licenses/>. // { dg-do compile { target c++20 } } -// { dg-require-effective-target pthread } -// { dg-require-gthreads "" } +// { dg-require-effective-target gthreads { target { ! *-*-linux* } } } +// { dg-require-effective-target hosted } #include <semaphore> diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/platform_try_acquire_for.cc b/libstdc++-v3/testsuite/30_threads/semaphore/platform_try_acquire_for.cc deleted file mode 100644 index 6d90564..0000000 --- a/libstdc++-v3/testsuite/30_threads/semaphore/platform_try_acquire_for.cc +++ /dev/null @@ -1,9 +0,0 @@ -// { dg-options "-D_GLIBCXX_USE_POSIX_SEMAPHORE" } -// { dg-do run { target c++20 } } -// { dg-additional-options "-pthread" { target pthread } } -// { dg-require-gthreads "" } -// { dg-add-options libatomic } - -#include "try_acquire_for.cc" - -// { dg-prune-output "ignoring _GLIBCXX_USE_POSIX_SEMAPHORE" } diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc index d709126..ea7859b 100644 --- a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc +++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc @@ -17,7 +17,8 @@ // { dg-do run { target c++20 } } // { dg-additional-options "-pthread" { target pthread } } -// { dg-require-gthreads "" } +// { dg-require-effective-target gthreads { target { ! *-*-linux* } } } +// { dg-require-effective-target hosted } // { dg-add-options libatomic } #include <semaphore> diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc deleted file mode 100644 index cf57455..0000000 --- a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright (C) 2020-2025 Free Software Foundation, Inc. -// -// This file is part of the GNU ISO C++ Library. This library is free -// software; you can redistribute it and/or modify it under the -// terms of the GNU General Public License as published by the -// Free Software Foundation; either version 3, or (at your option) -// any later version. - -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License along -// with this library; see the file COPYING3. If not see -// <http://www.gnu.org/licenses/>. - -// { dg-do run { target c++20 } } -// { dg-additional-options "-pthread" { target pthread } } -// { dg-require-gthreads "" } -// { dg-add-options libatomic } - -#include <semaphore> -#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE -#include <chrono> -#include <thread> -#include <atomic> -#include <testsuite_hooks.h> - -void test01() -{ - using namespace std::chrono_literals; - std::__platform_semaphore s(2); - s._M_acquire(); - - auto const dur = 250ms; - { - auto const t0 = std::chrono::steady_clock::now(); - VERIFY( s._M_try_acquire_for(dur) ); - auto const diff = std::chrono::steady_clock::now() - t0; - VERIFY( diff < dur ); - } - - { - auto const t0 = std::chrono::steady_clock::now(); - VERIFY( !s._M_try_acquire_for(dur) ); - auto const diff = std::chrono::steady_clock::now() - t0; - VERIFY( diff >= dur ); - } -} - -void test02() -{ - using namespace std::chrono_literals; - std::__platform_semaphore s(1); - std::atomic<int> a(0), b(0); - std::thread t([&] { - a.wait(0); - auto const dur = 250ms; - VERIFY( !s._M_try_acquire_for(dur) ); - b++; - b.notify_one(); - - a.wait(1); - VERIFY( s._M_try_acquire_for(dur) ); - b++; - b.notify_one(); - }); - t.detach(); - - s._M_acquire(); - a++; - a.notify_one(); - b.wait(0); - s._M_release(1); - a++; - a.notify_one(); - - b.wait(1); -} - -void test03() -{ - using namespace std::chrono_literals; - std::__platform_semaphore s(2); - s._M_acquire(); - - auto const dur = 250ms; - { - auto const at = std::chrono::system_clock::now() + dur; - auto const t0 = std::chrono::steady_clock::now(); - VERIFY( s._M_try_acquire_until(at) ); - auto const diff = std::chrono::steady_clock::now() - t0; - VERIFY( diff < dur ); - } - - { - auto const at = std::chrono::system_clock::now() + dur; - auto const t0 = std::chrono::steady_clock::now(); - VERIFY( !s._M_try_acquire_until(at) ); - auto const diff = std::chrono::steady_clock::now() - t0; - VERIFY( diff >= dur ); - } -} - -void test04() -{ - using namespace std::chrono_literals; - std::__platform_semaphore s(1); - std::atomic<int> a(0), b(0); - std::thread t([&] { - a.wait(0); - auto const dur = 250ms; - { - auto const at = std::chrono::system_clock::now() + dur; - VERIFY( !s._M_try_acquire_until(at) ); - - b++; - b.notify_one(); - } - - a.wait(1); - { - auto const at = std::chrono::system_clock::now() + dur; - VERIFY( s._M_try_acquire_until(at) ); - } - b++; - b.notify_one(); - }); - t.detach(); - - s._M_acquire(); - a++; - a.notify_one(); - b.wait(0); - s._M_release(1); - a++; - a.notify_one(); - - b.wait(1); -} -#endif - -int main() -{ -#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE - test01(); - test02(); - test03(); - test04(); -#endif - return 0; -} diff --git a/libstdc++-v3/testsuite/30_threads/thread/id/output.cc b/libstdc++-v3/testsuite/30_threads/thread/id/output.cc index 94a6ff0..3d1dd38 100644 --- a/libstdc++-v3/testsuite/30_threads/thread/id/output.cc +++ b/libstdc++-v3/testsuite/30_threads/thread/id/output.cc @@ -118,8 +118,38 @@ test02() VERIFY( ws1.length() == len ); #endif + out.str(""); + out << i; + s1 = out.str(); + len = s1.size(); + out.str(""); + + // with width + s2 = std::format("{0:{1}}", i, len + 2); + VERIFY( s2 == (" " + s1) ); + // with align + width + s2 = std::format("{0:>{1}}", i, len + 2); + VERIFY( s2 == (" " + s1) ); + s2 = std::format("{0:<{1}}", i, len + 2); + VERIFY( s2 == (s1 + " ") ); + // with fill-and-align + width + s2 = std::format("{0:x^{1}}", i, len + 5); + VERIFY( s2 == ("xx" + s1 + "xxx") ); + +#ifdef _GLIBCXX_USE_WCHAR_T + static_assert( std::is_default_constructible_v<std::formatter<std::thread::id, wchar_t>> ); + ws1 = std::format(L"{}", i); + VERIFY( ws1.length() == len ); +#endif + t1.join(); t2.join(); + + static_assert( std::formattable<std::thread::id, char> ); + static_assert( std::formattable<std::thread::id, wchar_t> ); + static_assert( !std::formattable<std::thread::id, char16_t> ); + static_assert( !std::formattable<std::thread::id, int> ); + #elif __cplusplus >= 202302L # error "Feature-test macro for formatters has wrong value in <thread>" #endif diff --git a/libstdc++-v3/testsuite/experimental/filesystem/path/concat/120029.cc b/libstdc++-v3/testsuite/experimental/filesystem/path/concat/120029.cc new file mode 100644 index 0000000..209d968 --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/filesystem/path/concat/120029.cc @@ -0,0 +1,74 @@ +// { dg-options "-DUSE_FILESYSTEM_TS -lstdc++fs" } +// { dg-do run { target c++11 } } +// { dg-require-filesystem-ts "" } + +// Bug libstdc++/120029 +// Dangling iterator usage in path::operator+=(const path& p) when this == p + +#include <experimental/filesystem> +#include <testsuite_hooks.h> + +namespace fs = std::experimental::filesystem; + +void +test_root_dir() +{ + fs::path p = "/"; + p += p; + p += p; + VERIFY( p == "////" ); + p += p.filename(); + VERIFY( p == "////////" ); + p += *std::prev(p.end()); + VERIFY( p == "////////////////" ); +} + +void +test_root_name() +{ + fs::path p = "C:/"; + p += p; + p += p; + VERIFY( p == "C:/C:/C:/C:/" ); + p += p.filename(); // For Filesystem TS the filename is "." + VERIFY( p == "C:/C:/C:/C:/." ); + p += *std::prev(p.end()); + VERIFY( p == "C:/C:/C:/C:/.." ); +} + +void +test_filename() +{ + fs::path p = "file"; + p += p; + p += p; + VERIFY( p == "filefilefilefile" ); + p += p.filename(); + VERIFY( p == "filefilefilefilefilefilefilefile" ); + p += *std::prev(p.end()); + VERIFY( p == "filefilefilefilefilefilefilefilefilefilefilefilefilefilefilefile" ); +} + +void +test_multi() +{ + fs::path p = "/home/username/Documents/mu"; + p += p; + p += p; + VERIFY( p == "/home/username/Documents/mu/home/username/Documents/mu/home/username/Documents/mu/home/username/Documents/mu" ); + p += p.filename(); + VERIFY( p == "/home/username/Documents/mu/home/username/Documents/mu/home/username/Documents/mu/home/username/Documents/mumu" ); + p += *std::prev(p.end()); + VERIFY( p == "/home/username/Documents/mu/home/username/Documents/mu/home/username/Documents/mu/home/username/Documents/mumumumu" ); + auto n = std::distance(p.begin(), p.end()); + for (int i = 0; i < n; ++i) + p += *std::next(p.begin(), i); +} + +int main() +{ + test_root_dir(); + test_root_name(); + test_filename(); + test_multi(); +} diff --git a/libstdc++-v3/testsuite/experimental/names.cc b/libstdc++-v3/testsuite/experimental/names.cc index e0a7d4f..94ae76f 100644 --- a/libstdc++-v3/testsuite/experimental/names.cc +++ b/libstdc++-v3/testsuite/experimental/names.cc @@ -22,6 +22,12 @@ // naming variables, parameters etc. in the library. #include "../17_intro/names.cc" + +#ifdef _AIX +// <netdb.h> declares endnetgrent_r with ptr parameter. +# undef ptr +#endif + // Filesystem #if __has_include(<experimental/filesystem>) # include <experimental/filesystem> diff --git a/libstdc++-v3/testsuite/experimental/net/buffer/arithmetic.cc b/libstdc++-v3/testsuite/experimental/net/buffer/arithmetic.cc index 04b3c93..483d01f 100644 --- a/libstdc++-v3/testsuite/experimental/net/buffer/arithmetic.cc +++ b/libstdc++-v3/testsuite/experimental/net/buffer/arithmetic.cc @@ -26,7 +26,6 @@ using std::experimental::net::const_buffer; void test01() { - bool test __attribute__((unused)) = false; char c[4]; mutable_buffer mb; @@ -64,7 +63,6 @@ test01() void test02() { - bool test __attribute__((unused)) = false; char c[4]; const_buffer cb; diff --git a/libstdc++-v3/testsuite/experimental/net/buffer/const.cc b/libstdc++-v3/testsuite/experimental/net/buffer/const.cc index c6adae6..4310c28 100644 --- a/libstdc++-v3/testsuite/experimental/net/buffer/const.cc +++ b/libstdc++-v3/testsuite/experimental/net/buffer/const.cc @@ -50,7 +50,6 @@ test01() void test02() { - bool test __attribute__((unused)) = false; char c[4]; const_buffer b; diff --git a/libstdc++-v3/testsuite/experimental/net/buffer/mutable.cc b/libstdc++-v3/testsuite/experimental/net/buffer/mutable.cc index 9f0d7d4..06a848c 100644 --- a/libstdc++-v3/testsuite/experimental/net/buffer/mutable.cc +++ b/libstdc++-v3/testsuite/experimental/net/buffer/mutable.cc @@ -47,7 +47,6 @@ test01() void test02() { - bool test __attribute__((unused)) = false; char c[4]; mutable_buffer b; diff --git a/libstdc++-v3/testsuite/experimental/net/buffer/size.cc b/libstdc++-v3/testsuite/experimental/net/buffer/size.cc index 4592a19..7d5f339 100644 --- a/libstdc++-v3/testsuite/experimental/net/buffer/size.cc +++ b/libstdc++-v3/testsuite/experimental/net/buffer/size.cc @@ -26,7 +26,6 @@ using std::experimental::net::mutable_buffer; void test01() { - bool test __attribute__((unused)) = false; char c[4]; mutable_buffer mb; @@ -44,7 +43,6 @@ test01() void test02() { - bool test __attribute__((unused)) = false; char c[32]; std::vector<mutable_buffer> mv{ {c, 0}, {c, 32}, {c, 16}, {c, 3}, {c, 0} }; diff --git a/libstdc++-v3/testsuite/experimental/net/timer/waitable/cons.cc b/libstdc++-v3/testsuite/experimental/net/timer/waitable/cons.cc index 6da7528..e394ec8 100644 --- a/libstdc++-v3/testsuite/experimental/net/timer/waitable/cons.cc +++ b/libstdc++-v3/testsuite/experimental/net/timer/waitable/cons.cc @@ -27,8 +27,6 @@ using std::experimental::net::io_context; void test01() { - bool test __attribute__((unused)) = false; - io_context ctx1, ctx2; system_timer timer1(ctx1); @@ -54,8 +52,6 @@ test01() void test02() { - bool test __attribute__((unused)) = false; - io_context ctx1, ctx2; auto t1 = system_timer::clock_type::now(); auto t2 = t1 + system_timer::duration(10); @@ -83,8 +79,6 @@ test02() void test03() { - bool test __attribute__((unused)) = false; - io_context ctx1, ctx2; auto now = system_timer::clock_type::now(); auto d1 = system_timer::duration(10); diff --git a/libstdc++-v3/testsuite/experimental/net/timer/waitable/dest.cc b/libstdc++-v3/testsuite/experimental/net/timer/waitable/dest.cc index d384a67..ef458bd 100644 --- a/libstdc++-v3/testsuite/experimental/net/timer/waitable/dest.cc +++ b/libstdc++-v3/testsuite/experimental/net/timer/waitable/dest.cc @@ -28,8 +28,6 @@ using std::experimental::net::io_context; void test01() { - bool test __attribute__((unused)) = false; - std::error_code ec; io_context ctx; diff --git a/libstdc++-v3/testsuite/experimental/net/timer/waitable/ops.cc b/libstdc++-v3/testsuite/experimental/net/timer/waitable/ops.cc index 82c05c0..ff0b800 100644 --- a/libstdc++-v3/testsuite/experimental/net/timer/waitable/ops.cc +++ b/libstdc++-v3/testsuite/experimental/net/timer/waitable/ops.cc @@ -29,8 +29,6 @@ using std::error_code; void test01() { - bool test __attribute__((unused)) = false; - io_context ctx; error_code ec; bool complete = false; @@ -57,8 +55,6 @@ test01() void test02() { - bool test __attribute__((unused)) = false; - io_context ctx; error_code ec1, ec2; diff --git a/libstdc++-v3/testsuite/ext/special_functions/airy_ai/check_value.cc b/libstdc++-v3/testsuite/ext/special_functions/airy_ai/check_value.cc index 7ff005b..6e8e36b 100644 --- a/libstdc++-v3/testsuite/ext/special_functions/airy_ai/check_value.cc +++ b/libstdc++-v3/testsuite/ext/special_functions/airy_ai/check_value.cc @@ -96,7 +96,6 @@ template<typename Ret, unsigned int Num> void test(const testcase_airy_ai<Ret> (&data)[Num], Ret toler) { - bool test __attribute__((unused)) = true; const Ret eps = std::numeric_limits<Ret>::epsilon(); Ret max_abs_diff = -Ret(1); Ret max_abs_frac = -Ret(1); diff --git a/libstdc++-v3/testsuite/ext/special_functions/airy_bi/check_value.cc b/libstdc++-v3/testsuite/ext/special_functions/airy_bi/check_value.cc index 0afefdd..6fcad83 100644 --- a/libstdc++-v3/testsuite/ext/special_functions/airy_bi/check_value.cc +++ b/libstdc++-v3/testsuite/ext/special_functions/airy_bi/check_value.cc @@ -96,7 +96,6 @@ template<typename Ret, unsigned int Num> void test(const testcase_airy_bi<Ret> (&data)[Num], Ret toler) { - bool test __attribute__((unused)) = true; const Ret eps = std::numeric_limits<Ret>::epsilon(); Ret max_abs_diff = -Ret(1); Ret max_abs_frac = -Ret(1); diff --git a/libstdc++-v3/testsuite/ext/special_functions/conf_hyperg/check_value.cc b/libstdc++-v3/testsuite/ext/special_functions/conf_hyperg/check_value.cc index 1227361..a050f62 100644 --- a/libstdc++-v3/testsuite/ext/special_functions/conf_hyperg/check_value.cc +++ b/libstdc++-v3/testsuite/ext/special_functions/conf_hyperg/check_value.cc @@ -3820,7 +3820,6 @@ template<typename Ret, unsigned int Num> void test(const testcase_conf_hyperg<Ret> (&data)[Num], Ret toler) { - bool test __attribute__((unused)) = true; const Ret eps = std::numeric_limits<Ret>::epsilon(); Ret max_abs_diff = -Ret(1); Ret max_abs_frac = -Ret(1); diff --git a/libstdc++-v3/testsuite/ext/special_functions/hyperg/check_value.cc b/libstdc++-v3/testsuite/ext/special_functions/hyperg/check_value.cc index 8e0c57f..b658684 100644 --- a/libstdc++-v3/testsuite/ext/special_functions/hyperg/check_value.cc +++ b/libstdc++-v3/testsuite/ext/special_functions/hyperg/check_value.cc @@ -12293,7 +12293,6 @@ template<typename Ret, unsigned int Num> void test(const testcase_hyperg<Ret> (&data)[Num], Ret toler) { - bool test __attribute__((unused)) = true; const Ret eps = std::numeric_limits<Ret>::epsilon(); Ret max_abs_diff = -Ret(1); Ret max_abs_frac = -Ret(1); diff --git a/libstdc++-v3/testsuite/lib/libstdc++.exp b/libstdc++-v3/testsuite/lib/libstdc++.exp index 3c34d18..9f2dd8a 100644 --- a/libstdc++-v3/testsuite/lib/libstdc++.exp +++ b/libstdc++-v3/testsuite/lib/libstdc++.exp @@ -586,6 +586,7 @@ proc v3_target_compile { source dest type options } { global tool lappend options "additional_flags=-fdiagnostics-plain-output" + lappend options "additional_flags=-Wabi=20"; if { [target_info needs_status_wrapper] != "" && [info exists gluefile] } { lappend options "libs=${gluefile}" @@ -648,6 +649,11 @@ proc v3_target_compile { source dest type options } { set v3_additional_files {} set comp_output [target_compile $source $dest $type $options] + + # Strip versioned namespace from the compiler output, + # so that dg-error and dg-warning patterns can ignore it: + regsub -all "std::__8::" $comp_output "std::" comp_output + if { $type == "executable" && $file_to_delete != "" } { file delete $file_to_delete if { [istarget *-*-darwin*] && [file exists $file_to_delete.dSYM] } { @@ -1013,8 +1019,8 @@ proc check_v3_target_time { } { }] } -proc check_v3_target_namedlocale { args } { - set key "et_namedlocale $args" +proc check_v3_target_namedlocale { locale } { + set key "et_namedlocale $locale" return [check_v3_target_prop_cached $key { global tool # Set up, compile, and execute a C++ test program that tries to use @@ -1029,7 +1035,7 @@ proc check_v3_target_namedlocale { args } { puts $f "using namespace std;" puts $f "char *transform_locale(const char *name)" puts $f "{" - puts $f " char *result = new char\[50\];" + puts $f " char *result = new char\[strlen(name)+6\];" puts $f " strcpy(result, name);" puts $f "#if defined __FreeBSD__ || defined __DragonFly__ || defined __NetBSD__" puts $f " /* fall-through */" @@ -1040,14 +1046,9 @@ proc check_v3_target_namedlocale { args } { puts $f "#endif" puts $f " return result;" puts $f "}" - puts $f "int main (int argc, char** argv)" + puts $f "int main ()" puts $f "{" - puts $f " if (argc < 2)" - puts $f " {" - puts $f " printf(\"locale support test not supported\\n\");" - puts $f " return 1;" - puts $f " }" - puts $f " const char *namedloc = transform_locale(*(argv + 1));" + puts $f " const char *namedloc = transform_locale(\"$locale\");" puts $f " try" puts $f " {" puts $f " locale((const char*)namedloc);" @@ -1071,10 +1072,10 @@ proc check_v3_target_namedlocale { args } { return 0 } - set result [${tool}_load "./$exe" "$args" ""] + set result [${tool}_load "./$exe" "" ""] set status [lindex $result 0] - verbose "check_v3_target_namedlocale <$args>: status is <$status>" 2 + verbose "check_v3_target_namedlocale <$locale>: status is <$status>" 2 if { $status == "pass" } { return 1 diff --git a/libstdc++-v3/testsuite/lib/prune.exp b/libstdc++-v3/testsuite/lib/prune.exp index 416e851..a9a2993 100644 --- a/libstdc++-v3/testsuite/lib/prune.exp +++ b/libstdc++-v3/testsuite/lib/prune.exp @@ -77,6 +77,9 @@ proc libstdc++-dg-prune { system text } { # Ignore harmless warnings from Xcode 4+. regsub -all "(^|\n)\[^\n\]*ld: warning: could not create compact unwind for\[^\n\]*" $text "" text + # Ignore duplicate path warnings from Xcode 16+. + regsub -all "(^|\n)\[^\n\]*ld: warning: duplicate -rpath\[^\n\]*" $text "" text + # Ignore dsymutil warning (tool bug is actually in the linker) regsub -all "(^|\n)\[^\n\]*could not find object file symbol for symbol\[^\n\]*" $text "" text diff --git a/libstdc++-v3/testsuite/special_functions/01_assoc_laguerre/check_value.cc b/libstdc++-v3/testsuite/special_functions/01_assoc_laguerre/check_value.cc index 4e40f0f..90d7d36 100644 --- a/libstdc++-v3/testsuite/special_functions/01_assoc_laguerre/check_value.cc +++ b/libstdc++-v3/testsuite/special_functions/01_assoc_laguerre/check_value.cc @@ -2217,7 +2217,6 @@ template<typename Ret, unsigned int Num> void test(const testcase_assoc_laguerre<Ret> (&data)[Num], Ret toler) { - bool test __attribute__((unused)) = true; const Ret eps = std::numeric_limits<Ret>::epsilon(); Ret max_abs_diff = -Ret(1); Ret max_abs_frac = -Ret(1); diff --git a/libstdc++-v3/testsuite/special_functions/02_assoc_legendre/check_value.cc b/libstdc++-v3/testsuite/special_functions/02_assoc_legendre/check_value.cc index b54e59e..54ae51d 100644 --- a/libstdc++-v3/testsuite/special_functions/02_assoc_legendre/check_value.cc +++ b/libstdc++-v3/testsuite/special_functions/02_assoc_legendre/check_value.cc @@ -1985,7 +1985,6 @@ template<typename Ret, unsigned int Num> void test(const testcase_assoc_legendre<Ret> (&data)[Num], Ret toler) { - bool test __attribute__((unused)) = true; const Ret eps = std::numeric_limits<Ret>::epsilon(); Ret max_abs_diff = -Ret(1); Ret max_abs_frac = -Ret(1); diff --git a/libstdc++-v3/testsuite/special_functions/02_assoc_legendre/pr86655.cc b/libstdc++-v3/testsuite/special_functions/02_assoc_legendre/pr86655.cc index 9d6507a..cbd7c51 100644 --- a/libstdc++-v3/testsuite/special_functions/02_assoc_legendre/pr86655.cc +++ b/libstdc++-v3/testsuite/special_functions/02_assoc_legendre/pr86655.cc @@ -37,7 +37,6 @@ template<typename _Tp> void test_m_gt_l() { - bool test __attribute__((unused)) = true; for (auto l : {0u, 1u, 2u, 5u}) for (auto m : {l + 1u, l + 2u}) for (auto i : {-2, -1, 0, 1, 2}) diff --git a/libstdc++-v3/testsuite/special_functions/03_beta/check_value.cc b/libstdc++-v3/testsuite/special_functions/03_beta/check_value.cc index 24f5033..e5e85a5 100644 --- a/libstdc++-v3/testsuite/special_functions/03_beta/check_value.cc +++ b/libstdc++-v3/testsuite/special_functions/03_beta/check_value.cc @@ -261,7 +261,6 @@ template<typename Ret, unsigned int Num> void test(const testcase_beta<Ret> (&data)[Num], Ret toler) { - bool test __attribute__((unused)) = true; const Ret eps = std::numeric_limits<Ret>::epsilon(); Ret max_abs_diff = -Ret(1); Ret max_abs_frac = -Ret(1); diff --git a/libstdc++-v3/testsuite/special_functions/04_comp_ellint_1/check_value.cc b/libstdc++-v3/testsuite/special_functions/04_comp_ellint_1/check_value.cc index efa7d5a..c109410 100644 --- a/libstdc++-v3/testsuite/special_functions/04_comp_ellint_1/check_value.cc +++ b/libstdc++-v3/testsuite/special_functions/04_comp_ellint_1/check_value.cc @@ -73,7 +73,6 @@ template<typename Ret, unsigned int Num> void test(const testcase_comp_ellint_1<Ret> (&data)[Num], Ret toler) { - bool test __attribute__((unused)) = true; const Ret eps = std::numeric_limits<Ret>::epsilon(); Ret max_abs_diff = -Ret(1); Ret max_abs_frac = -Ret(1); diff --git a/libstdc++-v3/testsuite/special_functions/05_comp_ellint_2/check_value.cc b/libstdc++-v3/testsuite/special_functions/05_comp_ellint_2/check_value.cc index 8c77daf..6a5d14d 100644 --- a/libstdc++-v3/testsuite/special_functions/05_comp_ellint_2/check_value.cc +++ b/libstdc++-v3/testsuite/special_functions/05_comp_ellint_2/check_value.cc @@ -73,7 +73,6 @@ template<typename Ret, unsigned int Num> void test(const testcase_comp_ellint_2<Ret> (&data)[Num], Ret toler) { - bool test __attribute__((unused)) = true; const Ret eps = std::numeric_limits<Ret>::epsilon(); Ret max_abs_diff = -Ret(1); Ret max_abs_frac = -Ret(1); diff --git a/libstdc++-v3/testsuite/special_functions/06_comp_ellint_3/check_value.cc b/libstdc++-v3/testsuite/special_functions/06_comp_ellint_3/check_value.cc index 8a74415..df544b5 100644 --- a/libstdc++-v3/testsuite/special_functions/06_comp_ellint_3/check_value.cc +++ b/libstdc++-v3/testsuite/special_functions/06_comp_ellint_3/check_value.cc @@ -459,7 +459,6 @@ template<typename Ret, unsigned int Num> void test(const testcase_comp_ellint_3<Ret> (&data)[Num], Ret toler) { - bool test __attribute__((unused)) = true; const Ret eps = std::numeric_limits<Ret>::epsilon(); Ret max_abs_diff = -Ret(1); Ret max_abs_frac = -Ret(1); diff --git a/libstdc++-v3/testsuite/special_functions/07_cyl_bessel_i/check_value.cc b/libstdc++-v3/testsuite/special_functions/07_cyl_bessel_i/check_value.cc index ab182c1..a379bed 100644 --- a/libstdc++-v3/testsuite/special_functions/07_cyl_bessel_i/check_value.cc +++ b/libstdc++-v3/testsuite/special_functions/07_cyl_bessel_i/check_value.cc @@ -702,7 +702,6 @@ template<typename Ret, unsigned int Num> void test(const testcase_cyl_bessel_i<Ret> (&data)[Num], Ret toler) { - bool test __attribute__((unused)) = true; const Ret eps = std::numeric_limits<Ret>::epsilon(); Ret max_abs_diff = -Ret(1); Ret max_abs_frac = -Ret(1); diff --git a/libstdc++-v3/testsuite/special_functions/08_cyl_bessel_j/check_value.cc b/libstdc++-v3/testsuite/special_functions/08_cyl_bessel_j/check_value.cc index a99e1e7..e09ae3d 100644 --- a/libstdc++-v3/testsuite/special_functions/08_cyl_bessel_j/check_value.cc +++ b/libstdc++-v3/testsuite/special_functions/08_cyl_bessel_j/check_value.cc @@ -735,7 +735,6 @@ template<typename Ret, unsigned int Num> void test(const testcase_cyl_bessel_j<Ret> (&data)[Num], Ret toler) { - bool test __attribute__((unused)) = true; const Ret eps = std::numeric_limits<Ret>::epsilon(); Ret max_abs_diff = -Ret(1); Ret max_abs_frac = -Ret(1); diff --git a/libstdc++-v3/testsuite/special_functions/09_cyl_bessel_k/check_value.cc b/libstdc++-v3/testsuite/special_functions/09_cyl_bessel_k/check_value.cc index 5e6804e..ce5abcc 100644 --- a/libstdc++-v3/testsuite/special_functions/09_cyl_bessel_k/check_value.cc +++ b/libstdc++-v3/testsuite/special_functions/09_cyl_bessel_k/check_value.cc @@ -746,7 +746,6 @@ template<typename Ret, unsigned int Num> void test(const testcase_cyl_bessel_k<Ret> (&data)[Num], Ret toler) { - bool test __attribute__((unused)) = true; const Ret eps = std::numeric_limits<Ret>::epsilon(); Ret max_abs_diff = -Ret(1); Ret max_abs_frac = -Ret(1); diff --git a/libstdc++-v3/testsuite/special_functions/10_cyl_neumann/check_value.cc b/libstdc++-v3/testsuite/special_functions/10_cyl_neumann/check_value.cc index 30c8a34..d934377 100644 --- a/libstdc++-v3/testsuite/special_functions/10_cyl_neumann/check_value.cc +++ b/libstdc++-v3/testsuite/special_functions/10_cyl_neumann/check_value.cc @@ -779,7 +779,6 @@ template<typename Ret, unsigned int Num> void test(const testcase_cyl_neumann<Ret> (&data)[Num], Ret toler) { - bool test __attribute__((unused)) = true; const Ret eps = std::numeric_limits<Ret>::epsilon(); Ret max_abs_diff = -Ret(1); Ret max_abs_frac = -Ret(1); diff --git a/libstdc++-v3/testsuite/special_functions/11_ellint_1/check_value.cc b/libstdc++-v3/testsuite/special_functions/11_ellint_1/check_value.cc index c8bad36..2d6a3c5 100644 --- a/libstdc++-v3/testsuite/special_functions/11_ellint_1/check_value.cc +++ b/libstdc++-v3/testsuite/special_functions/11_ellint_1/check_value.cc @@ -459,7 +459,6 @@ template<typename Ret, unsigned int Num> void test(const testcase_ellint_1<Ret> (&data)[Num], Ret toler) { - bool test __attribute__((unused)) = true; const Ret eps = std::numeric_limits<Ret>::epsilon(); Ret max_abs_diff = -Ret(1); Ret max_abs_frac = -Ret(1); diff --git a/libstdc++-v3/testsuite/special_functions/12_ellint_2/check_value.cc b/libstdc++-v3/testsuite/special_functions/12_ellint_2/check_value.cc index fc971e6..0bbd7bb 100644 --- a/libstdc++-v3/testsuite/special_functions/12_ellint_2/check_value.cc +++ b/libstdc++-v3/testsuite/special_functions/12_ellint_2/check_value.cc @@ -459,7 +459,6 @@ template<typename Ret, unsigned int Num> void test(const testcase_ellint_2<Ret> (&data)[Num], Ret toler) { - bool test __attribute__((unused)) = true; const Ret eps = std::numeric_limits<Ret>::epsilon(); Ret max_abs_diff = -Ret(1); Ret max_abs_frac = -Ret(1); diff --git a/libstdc++-v3/testsuite/special_functions/13_ellint_3/check_value.cc b/libstdc++-v3/testsuite/special_functions/13_ellint_3/check_value.cc index f46d8a5..bb1b4c1 100644 --- a/libstdc++-v3/testsuite/special_functions/13_ellint_3/check_value.cc +++ b/libstdc++-v3/testsuite/special_functions/13_ellint_3/check_value.cc @@ -6121,7 +6121,6 @@ template<typename Ret, unsigned int Num> void test(const testcase_ellint_3<Ret> (&data)[Num], Ret toler) { - bool test __attribute__((unused)) = true; const Ret eps = std::numeric_limits<Ret>::epsilon(); Ret max_abs_diff = -Ret(1); Ret max_abs_frac = -Ret(1); diff --git a/libstdc++-v3/testsuite/special_functions/14_expint/check_value.cc b/libstdc++-v3/testsuite/special_functions/14_expint/check_value.cc index 6bf060a..92e9714 100644 --- a/libstdc++-v3/testsuite/special_functions/14_expint/check_value.cc +++ b/libstdc++-v3/testsuite/special_functions/14_expint/check_value.cc @@ -168,7 +168,6 @@ template<typename Ret, unsigned int Num> void test(const testcase_expint<Ret> (&data)[Num], Ret toler) { - bool test __attribute__((unused)) = true; const Ret eps = std::numeric_limits<Ret>::epsilon(); Ret max_abs_diff = -Ret(1); Ret max_abs_frac = -Ret(1); diff --git a/libstdc++-v3/testsuite/special_functions/15_hermite/check_value.cc b/libstdc++-v3/testsuite/special_functions/15_hermite/check_value.cc index a16073a..419fcb0 100644 --- a/libstdc++-v3/testsuite/special_functions/15_hermite/check_value.cc +++ b/libstdc++-v3/testsuite/special_functions/15_hermite/check_value.cc @@ -1904,7 +1904,6 @@ template<typename Ret, unsigned int Num> void test(const testcase_hermite<Ret> (&data)[Num], Ret toler) { - bool test __attribute__((unused)) = true; const Ret eps = std::numeric_limits<Ret>::epsilon(); Ret max_abs_diff = -Ret(1); Ret max_abs_frac = -Ret(1); diff --git a/libstdc++-v3/testsuite/special_functions/16_laguerre/check_value.cc b/libstdc++-v3/testsuite/special_functions/16_laguerre/check_value.cc index 89b9c94..03c6496 100644 --- a/libstdc++-v3/testsuite/special_functions/16_laguerre/check_value.cc +++ b/libstdc++-v3/testsuite/special_functions/16_laguerre/check_value.cc @@ -305,7 +305,6 @@ template<typename Ret, unsigned int Num> void test(const testcase_laguerre<Ret> (&data)[Num], Ret toler) { - bool test __attribute__((unused)) = true; const Ret eps = std::numeric_limits<Ret>::epsilon(); Ret max_abs_diff = -Ret(1); Ret max_abs_frac = -Ret(1); diff --git a/libstdc++-v3/testsuite/special_functions/17_legendre/check_value.cc b/libstdc++-v3/testsuite/special_functions/17_legendre/check_value.cc index b2c0077..7bfb98c 100644 --- a/libstdc++-v3/testsuite/special_functions/17_legendre/check_value.cc +++ b/libstdc++-v3/testsuite/special_functions/17_legendre/check_value.cc @@ -305,7 +305,6 @@ template<typename Ret, unsigned int Num> void test(const testcase_legendre<Ret> (&data)[Num], Ret toler) { - bool test __attribute__((unused)) = true; const Ret eps = std::numeric_limits<Ret>::epsilon(); Ret max_abs_diff = -Ret(1); Ret max_abs_frac = -Ret(1); diff --git a/libstdc++-v3/testsuite/special_functions/18_riemann_zeta/check_value.cc b/libstdc++-v3/testsuite/special_functions/18_riemann_zeta/check_value.cc index 1967bf7..c8589ff 100644 --- a/libstdc++-v3/testsuite/special_functions/18_riemann_zeta/check_value.cc +++ b/libstdc++-v3/testsuite/special_functions/18_riemann_zeta/check_value.cc @@ -273,7 +273,6 @@ template<typename Ret, unsigned int Num> void test(const testcase_riemann_zeta<Ret> (&data)[Num], Ret toler) { - bool test __attribute__((unused)) = true; const Ret eps = std::numeric_limits<Ret>::epsilon(); Ret max_abs_diff = -Ret(1); Ret max_abs_frac = -Ret(1); diff --git a/libstdc++-v3/testsuite/special_functions/19_sph_bessel/check_value.cc b/libstdc++-v3/testsuite/special_functions/19_sph_bessel/check_value.cc index 8116ac4..658a13b 100644 --- a/libstdc++-v3/testsuite/special_functions/19_sph_bessel/check_value.cc +++ b/libstdc++-v3/testsuite/special_functions/19_sph_bessel/check_value.cc @@ -504,7 +504,6 @@ template<typename Ret, unsigned int Num> void test(const testcase_sph_bessel<Ret> (&data)[Num], Ret toler) { - bool test __attribute__((unused)) = true; const Ret eps = std::numeric_limits<Ret>::epsilon(); Ret max_abs_diff = -Ret(1); Ret max_abs_frac = -Ret(1); diff --git a/libstdc++-v3/testsuite/special_functions/20_sph_legendre/check_value.cc b/libstdc++-v3/testsuite/special_functions/20_sph_legendre/check_value.cc index df417e6..5783ca9 100644 --- a/libstdc++-v3/testsuite/special_functions/20_sph_legendre/check_value.cc +++ b/libstdc++-v3/testsuite/special_functions/20_sph_legendre/check_value.cc @@ -1985,7 +1985,6 @@ template<typename Ret, unsigned int Num> void test(const testcase_sph_legendre<Ret> (&data)[Num], Ret toler) { - bool test __attribute__((unused)) = true; const Ret eps = std::numeric_limits<Ret>::epsilon(); Ret max_abs_diff = -Ret(1); Ret max_abs_frac = -Ret(1); diff --git a/libstdc++-v3/testsuite/special_functions/20_sph_legendre/pr86655.cc b/libstdc++-v3/testsuite/special_functions/20_sph_legendre/pr86655.cc index e397371..80809ee 100644 --- a/libstdc++-v3/testsuite/special_functions/20_sph_legendre/pr86655.cc +++ b/libstdc++-v3/testsuite/special_functions/20_sph_legendre/pr86655.cc @@ -37,7 +37,6 @@ template<typename _Tp> void test_m_gt_l() { - bool test __attribute__((unused)) = true; for (auto l : {0u, 1u, 2u, 5u}) for (auto m : {l + 1u, l + 2u}) for (auto i : {-2, -1, 0, 1, 2}) diff --git a/libstdc++-v3/testsuite/special_functions/21_sph_neumann/check_value.cc b/libstdc++-v3/testsuite/special_functions/21_sph_neumann/check_value.cc index 372ca39..c9873b6 100644 --- a/libstdc++-v3/testsuite/special_functions/21_sph_neumann/check_value.cc +++ b/libstdc++-v3/testsuite/special_functions/21_sph_neumann/check_value.cc @@ -554,7 +554,6 @@ template<typename Ret, unsigned int Num> void test(const testcase_sph_neumann<Ret> (&data)[Num], Ret toler) { - bool test __attribute__((unused)) = true; const Ret eps = std::numeric_limits<Ret>::epsilon(); Ret max_abs_diff = -Ret(1); Ret max_abs_frac = -Ret(1); diff --git a/libstdc++-v3/testsuite/std/format/arguments/args.cc b/libstdc++-v3/testsuite/std/format/arguments/args.cc index 4c50bc7..6029675 100644 --- a/libstdc++-v3/testsuite/std/format/arguments/args.cc +++ b/libstdc++-v3/testsuite/std/format/arguments/args.cc @@ -164,24 +164,6 @@ void test_visited_as_handle() #endif } -template<typename E, typename S> -void test_visited_as() -{ - auto v = static_cast<S>(1.0); - auto store = std::make_format_args(v); - std::format_args args = store; - - auto is_expected_val = [v](auto arg) { - if constexpr (std::is_same_v<decltype(arg), E>) - return arg == static_cast<E>(v); - return false; - }; - VERIFY( std::visit_format_arg(is_expected_val, args.get(0)) ); -#if __cpp_lib_format >= 202306L // C++26 adds std::basic_format_arg::visit - VERIFY( args.get(0).visit(is_expected_val) ); -#endif -} - template<typename T> concept can_format = std::is_default_constructible_v<std::formatter<T, char>>; @@ -195,30 +177,31 @@ int main() test_visited_as_handle<__int128>(); test_visited_as_handle<unsigned __int128>(); #endif -// TODO: This should be visited as handle. -#ifdef __STDCPP_FLOAT16_T__ - if constexpr (can_format<_Float16>) - test_visited_as<float, _Float16>(); -#endif -#ifdef __STDCPP_BFLOAT16_T__ +#ifdef __BFLT16_DIG__ if constexpr (can_format<__gnu_cxx::__bfloat16_t>) - test_visited_as<float, __gnu_cxx::__bfloat16_t>(); + test_visited_as_handle<__gnu_cxx::__bfloat16_t>(); +#endif +#ifdef __FLT16_DIG__ + if constexpr (can_format<_Float16>) + test_visited_as_handle<_Float16>(); #endif #ifdef __FLT32_DIG__ if constexpr (can_format<_Float32>) - test_visited_as<float, _Float32>(); + test_visited_as_handle<_Float32>(); #endif #ifdef __FLT64_DIG__ if constexpr (can_format<_Float64>) - test_visited_as<double, _Float64>(); + test_visited_as_handle<_Float64>(); #endif #ifdef __FLT128_DIG__ if constexpr (can_format<_Float128>) -# ifdef _GLIBCXX_LDOUBLE_IS_IEEE_BINARY128 - test_visited_as<long double, _Float128>(); -# else test_visited_as_handle<_Float128>(); -# endif +#endif +#ifdef __SIZEOF_FLOAT128__ + // __ieee128 is same type as __float128, and may be long double + if constexpr (!std::is_same_v<__float128, long double>) + if constexpr (can_format<__float128>) + test_visited_as_handle<__float128>(); #endif #ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT if constexpr (!std::is_same_v<__ieee128, long double>) diff --git a/libstdc++-v3/testsuite/std/format/debug.cc b/libstdc++-v3/testsuite/std/format/debug.cc new file mode 100644 index 0000000..43e930c --- /dev/null +++ b/libstdc++-v3/testsuite/std/format/debug.cc @@ -0,0 +1,843 @@ +// { dg-options "-fexec-charset=UTF-8 -fwide-exec-charset=UTF-32LE -DUNICODE_ENC" { target le } } +// { dg-options "-fexec-charset=UTF-8 -fwide-exec-charset=UTF-32BE -DUNICODE_ENC" { target be } } +// { dg-do run { target c++23 } } +// { dg-require-effective-target 4byte_wchar_t } +// { dg-add-options no_pch } +// { dg-timeout-factor 2 } + +#include <format> +#include <testsuite_hooks.h> + +std::string +fdebug(char t) +{ return std::format("{:?}", t); } + +std::wstring +fdebug(wchar_t t) +{ return std::format(L"{:?}", t); } + +std::string +fdebug(std::string_view t) +{ return std::format("{:?}", t); } + +std::wstring +fdebug(std::wstring_view t) +{ return std::format(L"{:?}", t); } + + +#define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S) +#define WIDEN(S) WIDEN_(CharT, S) + +template<typename CharT> +void +test_basic_escapes() +{ + std::basic_string<CharT> res; + + const auto tab = WIDEN("\t"); + res = fdebug(tab); + VERIFY( res == WIDEN(R"("\t")") ); + res = fdebug(tab[0]); + VERIFY( res == WIDEN(R"('\t')") ); + + const auto nline = WIDEN("\n"); + res = fdebug(nline); + VERIFY( res == WIDEN(R"("\n")") ); + res = fdebug(nline[0]); + VERIFY( res == WIDEN(R"('\n')") ); + + const auto carret = WIDEN("\r"); + res = fdebug(carret); + VERIFY( res == WIDEN(R"("\r")") ); + res = fdebug(carret[0]); + VERIFY( res == WIDEN(R"('\r')") ); + + const auto bslash = WIDEN("\\"); + res = fdebug(bslash); + VERIFY( res == WIDEN(R"("\\")") ); + res = fdebug(bslash[0]); + VERIFY( res == WIDEN(R"('\\')") ); + + const auto quote = WIDEN("\""); + res = fdebug(quote); + VERIFY( res == WIDEN(R"("\"")") ); + res = fdebug(quote[0]); + VERIFY( res == WIDEN(R"('"')") ); + + const auto apos = WIDEN("\'"); + res = fdebug(apos); + VERIFY( res == WIDEN(R"("'")") ); + res = fdebug(apos[0]); + VERIFY( res == WIDEN(R"('\'')") ); +} + +template<typename CharT> +void +test_ascii_escapes() +{ + std::basic_string<CharT> res; + + const auto in = WIDEN("\x10 abcde\x7f\t0123"); + res = fdebug(in); + VERIFY( res == WIDEN(R"("\u{10} abcde\u{7f}\t0123")") ); + res = fdebug(in[0]); + VERIFY( res == WIDEN(R"('\u{10}')") ); + res = fdebug(in[1]); + VERIFY( res == WIDEN(R"(' ')") ); + res = fdebug(in[2]); + VERIFY( res == WIDEN(R"('a')") ); +} + +template<typename CharT> +void +test_extended_ascii() +{ + std::basic_string<CharT> res; + + const auto in = WIDEN("Åëÿ"); + res = fdebug(in); + VERIFY( res == WIDEN(R"("Åëÿ")") ); + + static constexpr bool __test_characters +#if UNICODE_ENC + = sizeof(CharT) >= 2; +#else // ISO8859-1 + = true; +#endif // UNICODE_ENC + + if constexpr (__test_characters) + { + res = fdebug(in[0]); + VERIFY( res == WIDEN(R"('Å')") ); + res = fdebug(in[1]); + VERIFY( res == WIDEN(R"('ë')") ); + res = fdebug(in[2]); + VERIFY( res == WIDEN(R"('ÿ')") ); + } +} + +template<typename CharT> +void +test_unicode_escapes() +{ +#if UNICODE_ENC + std::basic_string<CharT> res; + + const auto in = WIDEN( + "\u008a" // Cc, Control, Line Tabulation Set, + "\u00ad" // Cf, Format, Soft Hyphen + "\u1d3d" // Lm, Modifier letter, Modifier Letter Capital Ou + "\u00a0" // Zs, Space Separator, No-Break Space (NBSP) + "\u2029" // Zp, Paragraph Separator, Paragraph Separator + "\U0001f984" // So, Other Symbol, Unicorn Face + ); + const auto out = WIDEN("\"" + R"(\u{8a})" + R"(\u{ad})" + "\u1d3d" + R"(\u{a0})" + R"(\u{2029})" + "\U0001f984" + "\""); + + res = fdebug(in); + VERIFY( res == out ); + + if constexpr (sizeof(CharT) >= 2) + { + res = fdebug(in[0]); + VERIFY( res == WIDEN(R"('\u{8a}')") ); + res = fdebug(in[1]); + VERIFY( res == WIDEN(R"('\u{ad}')") ); + res = fdebug(in[2]); + VERIFY( res == WIDEN("'\u1d3d'") ); + res = fdebug(in[3]); + VERIFY( res == WIDEN(R"('\u{a0}')") ); + res = fdebug(in[4]); + VERIFY( res == WIDEN(R"('\u{2029}')") ); + } + + if constexpr (sizeof(CharT) >= 4) + { + res = fdebug(in[5]); + VERIFY( res == WIDEN("'\U0001f984'") ); + } +#endif // UNICODE_ENC +} + +template<typename CharT> +void +test_grapheme_extend() +{ +#if UNICODE_ENC + std::basic_string<CharT> res; + + const auto vin = WIDEN("o\u0302\u0323"); + res = fdebug(vin); + VERIFY( res == WIDEN("\"o\u0302\u0323\"") ); + + std::basic_string_view<CharT> in = WIDEN("\t\u0302\u0323"); + res = fdebug(in); + VERIFY( res == WIDEN(R"("\t\u{302}\u{323}")") ); + + res = fdebug(in.substr(1)); + VERIFY( res == WIDEN(R"("\u{302}\u{323}")") ); + + if constexpr (sizeof(CharT) >= 2) + { + res = fdebug(in[1]); + VERIFY( res == WIDEN(R"('\u{302}')") ); + } +#endif // UNICODE_ENC +} + +template<typename CharT> +void +test_replacement_char() +{ +#if UNICODE_ENC + std::basic_string<CharT> repl = WIDEN("\uFFFD"); + std::basic_string<CharT> res = fdebug(repl); + VERIFY( res == WIDEN("\"\uFFFD\"") ); + + repl = WIDEN("\uFFFD\uFFFD"); + res = fdebug(repl); + VERIFY( res == WIDEN("\"\uFFFD\uFFFD\"") ); +#endif // UNICODE_ENC +} + +void +test_ill_formed_utf8_seq() +{ +#if UNICODE_ENC + std::string_view seq = "\xf0\x9f\xa6\x84"; // \U0001F984 + std::string res; + + res = fdebug(seq); + VERIFY( res == "\"\U0001F984\"" ); + + res = fdebug(seq.substr(1)); + VERIFY( res == R"("\x{9f}\x{a6}\x{84}")" ); + + res = fdebug(seq.substr(2)); + VERIFY( res == R"("\x{a6}\x{84}")" ); + + res = fdebug(seq[0]); + VERIFY( res == R"('\x{f0}')" ); + res = fdebug(seq.substr(0, 1)); + VERIFY( res == R"("\x{f0}")" ); + + res = fdebug(seq[1]); + VERIFY( res == R"('\x{9f}')" ); + res = fdebug(seq.substr(1, 1)); + VERIFY( res == R"("\x{9f}")" ); + + res = fdebug(seq[2]); + VERIFY( res == R"('\x{a6}')" ); + res = fdebug(seq.substr(2, 1)); + VERIFY( res == R"("\x{a6}")" ); + + res = fdebug(seq[3]); + VERIFY( res == R"('\x{84}')" ); + res = fdebug(seq.substr(3, 1)); + VERIFY( res == R"("\x{84}")" ); +#endif // UNICODE_ENC +} + +void +test_ill_formed_utf32() +{ +#if UNICODE_ENC + std::wstring res; + + wchar_t ic1 = static_cast<wchar_t>(0xff'ffff); + res = fdebug(ic1); + VERIFY( res == LR"('\x{ffffff}')" ); + + std::wstring is1(1, ic1); + res = fdebug(is1); + VERIFY( res == LR"("\x{ffffff}")" ); + + wchar_t ic2 = static_cast<wchar_t>(0xffff'ffff); + res = fdebug(ic2); + VERIFY( res == LR"('\x{ffffffff}')" ); + + std::wstring is2(1, ic2); + res = fdebug(is2); + VERIFY( res == LR"("\x{ffffffff}")" ); +#endif // UNICODE_ENC +} + +template<typename CharT> +void +test_fill() +{ + std::basic_string<CharT> res; + + std::basic_string_view<CharT> in = WIDEN("a\t\x10\u00ad"); + res = std::format(WIDEN("{:10?}"), in.substr(0, 1)); + VERIFY( res == WIDEN(R"("a" )") ); + + res = std::format(WIDEN("{:->10?}"), in.substr(1, 1)); + VERIFY( res == WIDEN(R"(------"\t")") ); + + res = std::format(WIDEN("{:+<10?}"), in.substr(2, 1)); + VERIFY( res == WIDEN(R"("\u{10}"++)") ); + + + res = std::format(WIDEN("{:10?}"), in[0]); + VERIFY( res == WIDEN(R"('a' )") ); + + res = std::format(WIDEN("{:->10?}"), in[1]); + VERIFY( res == WIDEN(R"(------'\t')") ); + + res = std::format(WIDEN("{:+<10?}"), in[2]); + VERIFY( res == WIDEN(R"('\u{10}'++)") ); + +#if UNICODE_ENC + res = std::format(WIDEN("{:=^10?}"), in.substr(3)); + VERIFY( res == WIDEN(R"(="\u{ad}"=)") ); + + // width is 2 + std::basic_string_view<CharT> in2 = WIDEN("\u1100"); + res = std::format(WIDEN("{:*^10?}"), in2); + VERIFY( res == WIDEN("***\"\u1100\"***") ); + + if constexpr (sizeof(CharT) >= 2) + { + res = std::format(WIDEN("{:=^10?}"), in[3]); + VERIFY( res == WIDEN(R"(='\u{ad}'=)") ); + + res = std::format(WIDEN("{:*^10?}"), in2[0]); + VERIFY( res == WIDEN("***'\u1100'***") ); + } +#endif // UNICODE_ENC +} + +template<typename CharT> +void +test_prec() +{ + std::basic_string<CharT> res; + // with ? escpaed presentation is copied to ouput, same as source + + std::basic_string_view<CharT> in = WIDEN("a\t\x10\u00ad"); + res = std::format(WIDEN("{:.2?}"), in.substr(0, 1)); + VERIFY( res == WIDEN(R"("a)") ); + + res = std::format(WIDEN("{:.4?}"), in.substr(1, 1)); + VERIFY( res == WIDEN(R"("\t")") ); + + res = std::format(WIDEN("{:.5?}"), in.substr(2, 1)); + VERIFY( res == WIDEN(R"("\u{1)") ); + +#if UNICODE_ENC + res = std::format(WIDEN("{:.10?}"), in.substr(3)); + VERIFY( res == WIDEN(R"("\u{ad}")") ); + + std::basic_string_view<CharT> in2 = WIDEN("\u1100"); + res = std::format(WIDEN("{:.3?}"), in2); + VERIFY( res == WIDEN("\"\u1100") ); +#endif // UNICODE_ENC +} + +bool strip_quote(std::string_view& v) +{ + if (!v.starts_with('"')) + return false; + v.remove_prefix(1); + return true; +} + +bool strip_quotes(std::string_view& v) +{ + if (!v.starts_with('"') || !v.ends_with('"')) + return false; + v.remove_prefix(1); + v.remove_suffix(1); + return true; +} + +bool strip_prefix(std::string_view& v, size_t n, char c) +{ + size_t pos = v.find_first_not_of(c); + if (pos == std::string_view::npos) + pos = v.size(); + if (pos != n) + return false; + v.remove_prefix(n); + return true; +} + +void test_padding() +{ + std::string res; + std::string_view resv; + + // width and size are 26 + std::string in = "abcdefghijklmnopqrstuvwxyz"; + in += in; // width and size are 52 + in += in; // width and size are 104 + in += in; // width and size are 208 + in += in; // width and size are 416 + std::string_view inv = in; + + resv = res = std::format("{}", in); + VERIFY( resv == inv ); + + resv = res = std::format("{:.500}", in); + VERIFY( resv == inv ); + + resv = res = std::format("{:.400}", in); + VERIFY( resv == inv.substr(0, 400) ); + + resv = res = std::format("{:.200}", in); + VERIFY( resv == inv.substr(0, 200) ); + + resv = res = std::format("{:.10}", in); + VERIFY( resv == inv.substr(0, 10) ); + + resv = res = std::format("{:.0}", in); + VERIFY( resv == "" ); + + resv = res = std::format("{:*>20}", in); + VERIFY( resv == inv ); + + resv = res = std::format("{:*>20.500}", in); + VERIFY( resv == inv ); + + resv = res = std::format("{:*>20.400}", in); + VERIFY( resv == inv.substr(0, 400) ); + + resv = res = std::format("{:*>20.200}", in); + VERIFY( resv == inv.substr(0, 200) ); + + resv = res = std::format("{:*>20.10}", in); + VERIFY( strip_prefix(resv, 10, '*') ); + VERIFY( resv == inv.substr(0, 10) ); + + resv = res = std::format("{:*>20.0}", in); + VERIFY( strip_prefix(resv, 20, '*') ); + VERIFY( resv == "" ); + + resv = res = std::format("{:*>450}", in); + VERIFY( strip_prefix(resv, 34, '*') ); + VERIFY( resv == inv ); + + resv = res = std::format("{:*>450.500}", in); + VERIFY( strip_prefix(resv, 34, '*') ); + VERIFY( resv == inv ); + + resv = res = std::format("{:*>450.420}", in); + VERIFY( strip_prefix(resv, 34, '*') ); + VERIFY( resv == inv ); + + resv = res = std::format("{:*>450.400}", in); + VERIFY( strip_prefix(resv, 50, '*') ); + VERIFY( resv == inv.substr(0, 400) ); + + resv = res = std::format("{:*>450.200}", in); + VERIFY( strip_prefix(resv, 250, '*') ); + VERIFY( resv == inv.substr(0, 200) ); + + resv = res = std::format("{:*>450.10}", in); + VERIFY( strip_prefix(resv, 440, '*') ); + VERIFY( resv == inv.substr(0, 10) ); + + resv = res = std::format("{:*>450.0}", in); + VERIFY( strip_prefix(resv, 450, '*') ); + VERIFY( resv == "" ); + + resv = res = std::format("{:?}", in); + VERIFY( strip_quotes(resv) ); + VERIFY( resv == inv ); + + resv = res = std::format("{:.500?}", in); + VERIFY( strip_quotes(resv) ); + VERIFY( resv == inv ); + + resv = res = std::format("{:.400?}", in); + VERIFY( strip_quote(resv) ); + VERIFY( resv == inv.substr(0, 399) ); + + resv = res = std::format("{:.200?}", in); + VERIFY( strip_quote(resv) ); + VERIFY( resv == inv.substr(0, 199) ); + + resv = res = std::format("{:.10?}", in); + VERIFY( strip_quote(resv) ); + VERIFY( resv == inv.substr(0, 9) ); + + resv = res = std::format("{:.1?}", in); + VERIFY( strip_quote(resv) ); + VERIFY( resv == "" ); + + resv = res = std::format("{:.0?}", in); + VERIFY( resv == "" ); + + resv = res = std::format("{:*>20?}", in); + VERIFY( strip_quotes(resv) ); + VERIFY( resv == inv ); + + resv = res = std::format("{:*>20.500?}", in); + VERIFY( strip_quotes(resv) ); + VERIFY( resv == inv ); + + resv = res = std::format("{:*>20.400?}", in); + VERIFY( strip_quote(resv) ); + VERIFY( resv == inv.substr(0, 399) ); + + resv = res = std::format("{:*>20.200?}", in); + VERIFY( strip_quote(resv) ); + VERIFY( resv == inv.substr(0, 199) ); + + resv = res = std::format("{:*>20.10?}", in); + VERIFY( strip_prefix(resv, 10, '*') ); + VERIFY( strip_quote(resv) ); + VERIFY( resv == inv.substr(0, 9) ); + + resv = res = std::format("{:*>20.1?}", in); + VERIFY( strip_prefix(resv, 19, '*') ); + VERIFY( strip_quote(resv) ); + VERIFY( resv == "" ); + + resv = res = std::format("{:*>20.0?}", in); + VERIFY( strip_prefix(resv, 20, '*') ); + VERIFY( resv == "" ); + + resv = res = std::format("{:*>450?}", in); + VERIFY( strip_prefix(resv, 32, '*') ); + VERIFY( strip_quotes(resv) ); + VERIFY( resv == inv ); + + resv = res = std::format("{:*>450.500?}", in); + VERIFY( strip_prefix(resv, 32, '*') ); + VERIFY( strip_quotes(resv) ); + VERIFY( resv == inv ); + + resv = res = std::format("{:*>450.420?}", in); + VERIFY( strip_prefix(resv, 32, '*') ); + VERIFY( strip_quotes(resv) ); + VERIFY( resv == inv ); + + resv = res = std::format("{:*>450.400?}", in); + VERIFY( strip_prefix(resv, 50, '*') ); + VERIFY( strip_quote(resv) ); + VERIFY( resv == inv.substr(0, 399) ); + + resv = res = std::format("{:*>450.200?}", in); + VERIFY( strip_prefix(resv, 250, '*') ); + VERIFY( strip_quote(resv) ); + VERIFY( resv == inv.substr(0, 199) ); + + resv = res = std::format("{:*>450.10?}", in); + VERIFY( strip_prefix(resv, 440, '*') ); + VERIFY( strip_quote(resv) ); + VERIFY( resv == inv.substr(0, 9) ); + + resv = res = std::format("{:*>450.1?}", in); + VERIFY( strip_prefix(resv, 449, '*') ); + VERIFY( strip_quote(resv) ); + VERIFY( resv == "" ); + + resv = res = std::format("{:*>450.0?}", in); + VERIFY( strip_prefix(resv, 450, '*') ); + VERIFY( resv == "" ); + +#if UNICODE_ENC + // width is 3, size is 15 + in = "o\u0302\u0323i\u0302\u0323u\u0302\u0323"; + in += in; // width is 6, size is 30 + in += in; // width is 12, size is 60 + in += in; // width is 24, size is 120 + in += in; // width is 48, size is 240 + in += in; // width is 96, size is 480 + in += in; // width is 192, size is 960 + inv = in; + + resv = res = std::format("{:}", in); + VERIFY( resv == inv ); + + resv = res = std::format("{:.200}", in); + VERIFY( resv == inv ); + + resv = res = std::format("{:.96}", in); + VERIFY( resv == inv.substr(0, 480) ); + + resv = res = std::format("{:.12}", in); + VERIFY( resv == inv.substr(0, 60) ); + + resv = res = std::format("{:.3}", in); + VERIFY( resv == inv.substr(0, 15) ); + + resv = res = std::format("{:.0}", in); + VERIFY( resv == "" ); + + resv = res = std::format("{:*>10}", in); + VERIFY( resv == inv ); + + resv = res = std::format("{:*>10.200}", in); + VERIFY( resv == inv ); + + resv = res = std::format("{:*>10.96}", in); + VERIFY( resv == inv.substr(0, 480) ); + + resv = res = std::format("{:*>10.12}", in); + VERIFY( resv == inv.substr(0, 60) ); + + resv = res = std::format("{:*>10.3}", in); + VERIFY( strip_prefix(resv, 7, '*') ); + VERIFY( resv == inv.substr(0, 15) ); + + resv = res = std::format("{:*>10.0}", in); + VERIFY( strip_prefix(resv, 10, '*') ); + VERIFY( resv == "" ); + + resv = res = std::format("{:*>240s}", in); + VERIFY( strip_prefix(resv, 48, '*') ); + VERIFY( resv == inv ); + + resv = res = std::format("{:*>300.200s}", in); + VERIFY( strip_prefix(resv, 108, '*') ); + VERIFY( resv == inv ); + + resv = res = std::format("{:*>240.200s}", in); + VERIFY( strip_prefix(resv, 48, '*') ); + VERIFY( resv == inv ); + + resv = res = std::format("{:*>240.96s}", in); + VERIFY( strip_prefix(resv, 144, '*') ); + VERIFY( resv == inv.substr(0, 480) ); + + resv = res = std::format("{:*>240.12}", in); + VERIFY( strip_prefix(resv, 228, '*') ); + VERIFY( resv == inv.substr(0, 60) ); + + resv = res = std::format("{:*>240.3s}", in); + VERIFY( strip_prefix(resv, 237, '*') ); + VERIFY( resv == inv.substr(0, 15) ); + + resv = res = std::format("{:*>240.0s}", in); + VERIFY( strip_prefix(resv, 240, '*') ); + VERIFY( resv == "" ); + + resv = res = std::format("{:?}", in); + VERIFY( strip_quotes(resv) ); + VERIFY( resv == inv ); + + resv = res = std::format("{:.200?}", in); + VERIFY( strip_quotes(resv) ); + VERIFY( resv == inv ); + + resv = res = std::format("{:.97?}", in); + VERIFY( strip_quote(resv) ); + VERIFY( resv == inv.substr(0, 480) ); + + resv = res = std::format("{:.13?}", in); + VERIFY( strip_quote(resv) ); + VERIFY( resv == inv.substr(0, 60) ); + + resv = res = std::format("{:.4?}", in); + VERIFY( strip_quote(resv) ); + VERIFY( resv == inv.substr(0, 15) ); + + resv = res = std::format("{:.1?}", in); + VERIFY( strip_quote(resv) ); + VERIFY( resv == "" ); + + resv = res = std::format("{:.0?}", in); + VERIFY( resv == "" ); + + resv = res = std::format("{:*>10?}", in); + VERIFY( strip_quotes(resv) ); + VERIFY( resv == inv ); + + resv = res = std::format("{:*>10.200?}", in); + VERIFY( strip_quotes(resv) ); + VERIFY( resv == inv ); + + resv = res = std::format("{:*>10.97?}", in); + VERIFY( strip_quote(resv) ); + VERIFY( resv == inv.substr(0, 480) ); + + resv = res = std::format("{:*>10.13?}", in); + VERIFY( strip_quote(resv) ); + VERIFY( resv == inv.substr(0, 60) ); + + resv = res = std::format("{:*>10.4?}", in); + VERIFY( strip_prefix(resv, 6, '*') ); + VERIFY( strip_quote(resv) ); + VERIFY( resv == inv.substr(0, 15) ); + + resv = res = std::format("{:*>10.1?}", in); + VERIFY( strip_prefix(resv, 9, '*') ); + VERIFY( strip_quote(resv) ); + VERIFY( resv == "" ); + + resv = res = std::format("{:*>10.0?}", in); + VERIFY( strip_prefix(resv, 10, '*') ); + VERIFY( resv == "" ); + + resv = res = std::format("{:*>240?}", in); + VERIFY( strip_prefix(resv, 46, '*') ); + VERIFY( strip_quotes(resv) ); + VERIFY( resv == inv ); + + resv = res = std::format("{:*>300.200?}", in); + VERIFY( strip_prefix(resv, 106, '*') ); + VERIFY( strip_quotes(resv) ); + VERIFY( resv == inv ); + + resv = res = std::format("{:*>240.200?}", in); + VERIFY( strip_prefix(resv, 46, '*') ); + VERIFY( strip_quotes(resv) ); + VERIFY( resv == inv ); + + resv = res = std::format("{:*>240.97?}", in); + VERIFY( strip_prefix(resv, 143, '*') ); + VERIFY( strip_quote(resv) ); + VERIFY( resv == inv.substr(0, 480) ); + + resv = res = std::format("{:*>240.13?}", in); + VERIFY( strip_prefix(resv, 227, '*') ); + VERIFY( strip_quote(resv) ); + VERIFY( resv == inv.substr(0, 60) ); + + resv = res = std::format("{:*>240.4?}", in); + VERIFY( strip_prefix(resv, 236, '*') ); + VERIFY( strip_quote(resv) ); + VERIFY( resv == inv.substr(0, 15) ); + + resv = res = std::format("{:*>240.1?}", in); + VERIFY( strip_prefix(resv, 239, '*') ); + VERIFY( strip_quote(resv) ); + VERIFY( resv == "" ); + + resv = res = std::format("{:*>240.0?}", in); + VERIFY( strip_prefix(resv, 240, '*') ); + VERIFY( resv == "" ); +#endif // UNICODE_ENC +} + +void test_char_as_wchar() +{ + std::wstring res; + + res = std::format(L"{:?}", 'a'); + VERIFY( res == LR"('a')" ); + + res = std::format(L"{:?}", '\t'); + VERIFY( res == LR"('\t')" ); + + res = std::format(L"{:+<10?}", '\x10'); + VERIFY( res == LR"('\u{10}'++)" ); +} + +template<typename T> +struct DebugWrapper +{ + T val; +}; + +template<typename T, typename CharT> +struct std::formatter<DebugWrapper<T>, CharT> +{ + constexpr std::basic_format_parse_context<CharT>::iterator + parse(std::basic_format_parse_context<CharT>& pc) + { + auto out = under.parse(pc); + under.set_debug_format(); + return out; + } + + template<typename Out> + Out format(DebugWrapper<T> const& t, + std::basic_format_context<Out, CharT>& fc) const + { return under.format(t.val, fc); } + +private: + std::formatter<T, CharT> under; +}; + +template<typename CharT, typename StrT> +void +test_formatter_str() +{ + CharT buf[]{ 'a', 'b', 'c', 0 }; + DebugWrapper<StrT> in{ buf }; + std::basic_string<CharT> res = std::format(WIDEN("{:?}"), in ); + VERIFY( res == WIDEN(R"("abc")") ); +} + +template<typename CharT> +void +test_formatter_arr() +{ + std::basic_string<CharT> res; + + DebugWrapper<CharT[3]> in3{ 'a', 'b', 'c' }; + res = std::format(WIDEN("{:?}"), in3 ); + VERIFY( res == WIDEN(R"("abc")") ); + + // We print all characters, including null-terminator + DebugWrapper<CharT[4]> in4{ 'a', 'b', 'c', 0 }; + res = std::format(WIDEN("{:?}"), in4 ); + VERIFY( res == WIDEN(R"("abc\u{0}")") ); +} + +template<typename CharT, typename SrcT> +void +test_formatter_char() +{ + DebugWrapper<SrcT> in{ 'a' }; + std::basic_string<CharT> res = std::format(WIDEN("{:?}"), in); + VERIFY( res == WIDEN(R"('a')") ); +} + +template<typename CharT> +void +test_formatters() +{ + test_formatter_char<CharT, CharT>(); + test_formatter_str<CharT, CharT*>(); + test_formatter_str<CharT, const CharT*>(); + test_formatter_str<CharT, std::basic_string<CharT>>(); + test_formatter_str<CharT, std::basic_string_view<CharT>>(); + test_formatter_arr<CharT>(); +} + +void +test_formatters_c() +{ + test_formatters<char>(); + test_formatters<wchar_t>(); + test_formatter_char<wchar_t, char>(); +} + +int main() +{ + test_basic_escapes<char>(); + test_basic_escapes<wchar_t>(); + test_ascii_escapes<char>(); + test_ascii_escapes<wchar_t>(); + test_extended_ascii<char>(); + test_extended_ascii<wchar_t>(); + + test_unicode_escapes<char>(); + test_unicode_escapes<wchar_t>(); + test_grapheme_extend<char>(); + test_grapheme_extend<wchar_t>(); + test_replacement_char<char>(); + test_replacement_char<wchar_t>(); + test_ill_formed_utf8_seq(); + test_ill_formed_utf32(); + + test_fill<char>(); + test_fill<wchar_t>(); + test_prec<char>(); + test_prec<wchar_t>(); + + test_padding(); + + test_formatters_c(); +} diff --git a/libstdc++-v3/testsuite/std/format/debug_nonunicode.cc b/libstdc++-v3/testsuite/std/format/debug_nonunicode.cc new file mode 100644 index 0000000..2ac7e75 --- /dev/null +++ b/libstdc++-v3/testsuite/std/format/debug_nonunicode.cc @@ -0,0 +1,5 @@ +// { dg-options "-fexec-charset=ISO8859-1" } +// { dg-do run { target c++23 } } +// { dg-add-options no_pch } + +#include "debug.cc" diff --git a/libstdc++-v3/testsuite/std/format/formatter/120625.cc b/libstdc++-v3/testsuite/std/format/formatter/120625.cc new file mode 100644 index 0000000..6b03af9 --- /dev/null +++ b/libstdc++-v3/testsuite/std/format/formatter/120625.cc @@ -0,0 +1,19 @@ +// { dg-do compile { target c++20 } } + +// Bug libstdc++/120625 +// std::formatter<__disabled> specializations cause errors in user code + +#include <format> + +enum X { }; + +// A concept that cannot be used with incomplete types: +template<typename T> +concept is_X = !std::is_empty_v<T> && std::is_same_v<X, T>; + +// A valid program-defined specialization: +template<typename T, typename C> requires is_X<T> +struct std::formatter<T, C> : std::formatter<int, C> { }; + +// Instantiate the program-defined formatter specialization: +auto s = sizeof(std::formatter<X, char>); diff --git a/libstdc++-v3/testsuite/std/format/formatter/lwg3944.cc b/libstdc++-v3/testsuite/std/format/formatter/lwg3944.cc index ff5f075..07e63af 100644 --- a/libstdc++-v3/testsuite/std/format/formatter/lwg3944.cc +++ b/libstdc++-v3/testsuite/std/format/formatter/lwg3944.cc @@ -4,6 +4,7 @@ // LWG 3944. Formatters converting sequences of char to sequences of wchar_t #include <format> +#include <vector> void test_lwg3944() { @@ -14,7 +15,6 @@ void test_lwg3944() std::format(L"{}",cstr); // { dg-error "here" } // Ill-formed in C++20 - // In C++23 they give L"['h', 'e', 'l', 'l', 'o']" std::format(L"{}", "hello"); // { dg-error "here" } std::format(L"{}", std::string_view("hello")); // { dg-error "here" } std::format(L"{}", std::string("hello")); // { dg-error "here" } diff --git a/libstdc++-v3/testsuite/std/format/formatter/requirements.cc b/libstdc++-v3/testsuite/std/format/formatter/requirements.cc index 416b9a8..1c9a0a5 100644 --- a/libstdc++-v3/testsuite/std/format/formatter/requirements.cc +++ b/libstdc++-v3/testsuite/std/format/formatter/requirements.cc @@ -70,12 +70,14 @@ test_specializations() // [format.formatter.spec] // LWG 3833. Remove specialization // template<size_t N> struct formatter<const charT[N], charT> - using Farr = std::format_context::formatter_type<const char[1]>; - static_assert( ! std::is_default_constructible_v<Farr> ); - static_assert( ! std::is_copy_constructible_v<Farr> ); - static_assert( ! std::is_move_constructible_v<Farr> ); - static_assert( ! std::is_copy_assignable_v<Farr> ); - static_assert( ! std::is_move_assignable_v<Farr> ); + // Formatter is only expected to be instantiated with only cv-unqual types + // and attempting to instantiate this specialization is ill-formed + // using Farr = std::format_context::formatter_type<const char[1]>; + // static_assert( ! std::is_default_constructible_v<Farr> ); + // static_assert( ! std::is_copy_constructible_v<Farr> ); + // static_assert( ! std::is_move_constructible_v<Farr> ); + // static_assert( ! std::is_copy_assignable_v<Farr> ); + // static_assert( ! std::is_move_assignable_v<Farr> ); } int main() diff --git a/libstdc++-v3/testsuite/std/format/functions/format.cc b/libstdc++-v3/testsuite/std/format/functions/format.cc index 7fc4201..d342114 100644 --- a/libstdc++-v3/testsuite/std/format/functions/format.cc +++ b/libstdc++-v3/testsuite/std/format/functions/format.cc @@ -1,6 +1,7 @@ // { dg-options "-fexec-charset=UTF-8" } // { dg-do run { target c++20 } } // { dg-add-options no_pch } +// { dg-additional-options "-DUNICODE" { target 4byte_wchar_t } } #include <format> @@ -260,6 +261,16 @@ test_locale() s = std::format(eloc, "{0:Le} {0:Lf} {0:Lg}", -nan); VERIFY( s == "-nan -nan -nan" ); + // PR libstdc++/120548 format confuses a negative sign for a thousands digit + s = std::format(bloc, "{:L}", -123.45); + VERIFY( s == "-123.45" ); + s = std::format(bloc, "{:-L}", -876543.21); + VERIFY( s == "-876,543.21" ); + s = std::format(bloc, "{:+L}", 333.22); + VERIFY( s == "+333.22" ); + s = std::format(bloc, "{: L}", 999.44); + VERIFY( s == " 999.44" ); + // Restore std::locale::global(cloc); } @@ -370,6 +381,18 @@ test_wchar() // P2909R4 Fix formatting of code units as integers (Dude, where’s my char?) s = std::format(L"{:d} {:d}", wchar_t(-1), char(-1)); VERIFY( s.find('-') == std::wstring::npos ); + + auto ws = std::format(L"{:L}", 0.5); + VERIFY( ws == L"0.5" ); + // The default C locale. + std::locale cloc = std::locale::classic(); + // PR libstdc++/119671 use-after-free formatting floating-point to wstring + ws = std::format(cloc, L"{:L}", 0.5); + VERIFY( ws == L"0.5" ); + // A locale with no name, but with the same facets as the C locale. + std::locale locx(cloc, &std::use_facet<std::ctype<char>>(cloc)); + ws = std::format(locx, L"{:L}", 0.5); + VERIFY( ws == L"0.5" ); } void @@ -499,11 +522,17 @@ test_bool() void test_unicode() { +#ifdef UNICODE // Similar to sC example in test_std_examples, but not from the standard. // Verify that the character "🤡" has estimated field width 2, - // rather than estimated field width equal to strlen("🤡"), which would be 4. + // rather than estimated field width equal to strlen("🤡"), which would be 4, + // or just width 1 for single character. std::string sC = std::format("{:*<3}", "🤡"); VERIFY( sC == "🤡*" ); + std::wstring wsC = std::format(L"{:*<3}", L"🤡"); + VERIFY( wsC == L"🤡*" ); + wsC = std::format(L"{:*<3}", L'🤡'); + VERIFY( wsC == L"🤡*" ); // Verify that "£" has estimated field width 1, not strlen("£") == 2. std::string sL = std::format("{:*<3}", "£"); @@ -547,6 +576,7 @@ test_unicode() std::string sA = std::format("{:>5}", input[0]); VERIFY( sA == input[1] ); } +#endif } int main() diff --git a/libstdc++-v3/testsuite/std/format/parse_ctx.cc b/libstdc++-v3/testsuite/std/format/parse_ctx.cc index b5dd7cd..6294dcf 100644 --- a/libstdc++-v3/testsuite/std/format/parse_ctx.cc +++ b/libstdc++-v3/testsuite/std/format/parse_ctx.cc @@ -443,6 +443,8 @@ test_custom() } #if __cpp_lib_format >= 202305 +#include <stdfloat> + struct X { }; template<> @@ -458,13 +460,20 @@ struct std::formatter<X, char> if (spec == "int") { pc.check_dynamic_spec_integral(pc.next_arg_id()); - integer = true; + type = Type::integral; } else if (spec == "str") { pc.check_dynamic_spec_string(pc.next_arg_id()); - integer = false; + type = Type::string; + } + else if (spec == "float") + { + pc.check_dynamic_spec<float, double, long double>(pc.next_arg_id()); + type = Type::floating; } + else if (spec == "other") + type = Type::other; else throw std::format_error("invalid format-spec"); return pc.begin() + spec.size(); @@ -474,13 +483,44 @@ struct std::formatter<X, char> format(X, std::format_context& c) const { std::visit_format_arg([this]<typename T>(T) { // { dg-warning "deprecated" "" { target c++26 } } - if (is_integral_v<T> != this->integer) - throw std::format_error("invalid argument type"); + constexpr bool is_handle + = std::is_same_v<std::basic_format_arg<std::format_context>::handle, T>; + constexpr bool is_integral + = std::is_same_v<int, T> || std::is_same_v<unsigned int, T> + || is_same_v<long long, T> || std::is_same_v<unsigned long long, T>; + constexpr bool is_string + = std::is_same_v<const char*, T> || std::is_same_v<std::string_view, T>; + constexpr bool is_floating + = std::is_same_v<float, T> || std::is_same_v<double, T> + || std::is_same_v<long double, T>; + switch (this->type) + { + case Type::other: + if (is_handle) return; + break; + case Type::integral: + if (is_integral) return; + break; + case Type::string: + if (is_string) return; + break; + case Type::floating: + if (is_floating) return; + break; + } + throw std::format_error("invalid argument type"); }, c.arg(1)); return c.out(); } private: - bool integer = false; + enum class Type + { + other, + integral, + string, + floating, + }; + Type type = Type::other; }; #endif @@ -497,6 +537,28 @@ test_dynamic_type_check() (void) std::format("{:int}", X{}, 42L); (void) std::format("{:str}", X{}, "H2G2"); + (void) std::format("{:float}", X{}, 10.0); + +#ifdef __STDCPP_BFLOAT16_T__ + if constexpr (std::formattable<std::bfloat16_t, char>) + (void) std::format("{:other}", X{}, 10.0bf16); +#endif +#ifdef __STDCPP_FLOAT16_T__ + if constexpr (std::formattable<std::float16_t, char>) + (void) std::format("{:other}", X{}, 10.0f16); +#endif +#ifdef __STDCPP_FLOAT32_T__ + if constexpr (std::formattable<std::float32_t, char>) + (void) std::format("{:other}", X{}, 10.0f32); +#endif +#ifdef __STDCPP_FLOAT64_T__ + if constexpr (std::formattable<std::float64_t, char>) + (void) std::format("{:other}", X{}, 10.0f64); +#endif +#ifdef __STDCPP_FLOAT128_T__ + if constexpr (std::formattable<std::float128_t, char>) + (void) std::format("{:other}", X{}, 10.0f128); +#endif #endif } diff --git a/libstdc++-v3/testsuite/std/format/ranges/adaptors.cc b/libstdc++-v3/testsuite/std/format/ranges/adaptors.cc new file mode 100644 index 0000000..a4e2dfb --- /dev/null +++ b/libstdc++-v3/testsuite/std/format/ranges/adaptors.cc @@ -0,0 +1,156 @@ +// { dg-do run { target c++23 } } +// { dg-timeout-factor 2 } + +#include <format> +#include <queue> +#include <stack> +#include <testsuite_hooks.h> + +template<typename... Args> +bool +is_format_string_for(const char* str, Args&&... args) +{ + try { + (void) std::vformat(str, std::make_format_args(args...)); + return true; + } catch (const std::format_error&) { + return false; + } +} + +#define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S) +#define WIDEN(S) WIDEN_(CharT, S) + +template<template<typename Tp> class Adaptor> +void +test_format_string() +{ + Adaptor<int> q; + VERIFY( !is_format_string_for("{:?}", q) ); + VERIFY( !is_format_string_for("{:P}", q) ); + + // width needs to be integer type + VERIFY( !is_format_string_for("{:{}}", q, 1.0f) ); +} + +struct NoFormat +{ + friend auto operator<=>(NoFormat, NoFormat) = default; +}; + +struct MutFormat +{ + MutFormat() = default; + MutFormat(int p) : x(p) {} + + int x; + friend auto operator<=>(MutFormat, MutFormat) = default; +}; + +template<typename CharT> +struct std::formatter<MutFormat, CharT> + : std::formatter<int, CharT> +{ + template<typename Out> + Out format(MutFormat& mf, basic_format_context<Out, CharT>& ctx) const + { return std::formatter<int, CharT>::format(mf.x, ctx); } +}; + +template<typename T> +struct NotFormattableCont : std::vector<T> +{ + using std::vector<T>::vector; +}; + +template<typename T> +constexpr auto std::format_kind<NotFormattableCont<T>> + = std::range_format::disabled; + +template<typename CharT, + template<typename Tp, typename Cont = std::vector<Tp>> class Adaptor> +void +test_output() +{ + const std::vector<int> v{3, 2, 1}; + std::basic_string<CharT> res; + Adaptor<int, std::vector<int>> q(std::from_range, v); + + res = std::format(WIDEN("{}"), q); + VERIFY( res == WIDEN("[3, 2, 1]") ); + + res = std::format(WIDEN("{}"), std::as_const(q)); + VERIFY( res == WIDEN("[3, 2, 1]") ); + + res = std::format(WIDEN("{:n:#x}"), q); + VERIFY( res == WIDEN("0x3, 0x2, 0x1") ); + + res = std::format(WIDEN("{:=^23:#04x}"), q); + VERIFY( res == WIDEN("==[0x03, 0x02, 0x01]===") ); + + // Sequence output is always used + Adaptor<CharT, std::basic_string<CharT>> qs( + std::from_range, + std::basic_string_view<CharT>(WIDEN("321"))); + + res = std::format(WIDEN("{}"), qs); + VERIFY( res == WIDEN("['3', '2', '1']") ); + + res = std::format(WIDEN("{::}"), std::as_const(qs)); + VERIFY( res == WIDEN("[3, 2, 1]") ); + + res = std::format(WIDEN("{:?s}"), qs); + VERIFY( res == WIDEN(R"("321")") ); + + Adaptor<int, std::deque<int>> qd(std::from_range, v); + + res = std::format(WIDEN("{}"), qd); + VERIFY( res == WIDEN("[3, 2, 1]") ); + + res = std::format(WIDEN("{}"), std::as_const(qd)); + VERIFY( res == WIDEN("[3, 2, 1]") ); + + Adaptor<MutFormat> mq(std::from_range, v); + + res = std::format(WIDEN("{}"), mq); + VERIFY( res == WIDEN("[3, 2, 1]") ); + + static_assert(!std::formattable<const Adaptor<MutFormat>, CharT>); + + static_assert(!std::formattable<Adaptor<NoFormat>, CharT>); + static_assert(!std::formattable<const Adaptor<NoFormat>, CharT>); + + // Formatter check if container is formattable, not container elements. + static_assert(!std::formattable<Adaptor<int, NotFormattableCont<int>>, CharT>); +} + +template<template<typename Tp, typename Cont = std::vector<Tp>> class Adaptor> +void +test_adaptor() +{ + test_format_string<Adaptor>(); + test_output<char, Adaptor>(); + test_output<wchar_t, Adaptor>(); + + static_assert(!std::formattable<Adaptor<int>, int>); + static_assert(!std::formattable<Adaptor<int>, char32_t>); +} + +template<typename CharT> +void +test_compare() +{ + const std::vector<int> v{3, 2, 1}; + std::basic_string<CharT> res; + std::priority_queue<int, std::vector<int>, std::greater<>> q( + std::from_range, v); + + res = std::format(WIDEN("{}"), q); + VERIFY( res == WIDEN("[1, 2, 3]") ); +} + +int main() +{ + test_adaptor<std::queue>(); + test_adaptor<std::priority_queue>(); + test_compare<char>(); +} diff --git a/libstdc++-v3/testsuite/std/format/ranges/feature_test.cc b/libstdc++-v3/testsuite/std/format/ranges/feature_test.cc new file mode 100644 index 0000000..80d2cea --- /dev/null +++ b/libstdc++-v3/testsuite/std/format/ranges/feature_test.cc @@ -0,0 +1,9 @@ +// { dg-do preprocess { target c++23 } } + +#include <format> + +#ifndef __cpp_lib_format_ranges +# error "Feature-test macro __cpp_lib_format_ranges missing in <format>" +#elif __cpp_lib_format_ranges != 202207L +# error "Feature-test macro __cpp_lib_format_ranges has wrong value in <format>" +#endif diff --git a/libstdc++-v3/testsuite/std/format/ranges/format_kind.cc b/libstdc++-v3/testsuite/std/format/ranges/format_kind.cc new file mode 100644 index 0000000..14b9ff2 --- /dev/null +++ b/libstdc++-v3/testsuite/std/format/ranges/format_kind.cc @@ -0,0 +1,94 @@ +// { dg-do run { target c++23 } } + +#include <deque> +#include <flat_map> +#include <flat_set> +#include <format> +#include <list> +#include <map> +#include <set> +#include <testsuite_hooks.h> +#include <unordered_map> +#include <unordered_set> +#include <vector> + +static_assert( std::format_kind<std::vector<int>> == std::range_format::sequence ); +static_assert( std::format_kind<std::deque<int>> == std::range_format::sequence ); +static_assert( std::format_kind<std::list<int>> == std::range_format::sequence ); + +static_assert( std::format_kind<std::set<int>> == std::range_format::set ); +static_assert( std::format_kind<std::multiset<int>> == std::range_format::set ); +static_assert( std::format_kind<std::unordered_set<int>> == std::range_format::set ); +static_assert( std::format_kind<std::unordered_multiset<int>> == std::range_format::set ); +static_assert( std::format_kind<std::flat_set<int>> == std::range_format::set ); +static_assert( std::format_kind<std::flat_multiset<int>> == std::range_format::set ); + +static_assert( std::format_kind<std::map<int, int>> == std::range_format::map ); +static_assert( std::format_kind<std::multimap<int, int>> == std::range_format::map ); +static_assert( std::format_kind<std::unordered_map<int, int>> == std::range_format::map ); +static_assert( std::format_kind<std::unordered_multimap<int, int>> == std::range_format::map ); +static_assert( std::format_kind<std::flat_map<int, int>> == std::range_format::map ); +static_assert( std::format_kind<std::flat_multimap<int, int>> == std::range_format::map ); + +template<typename T> +struct MyVec : std::vector<T> +{}; + +static_assert( std::format_kind<MyVec<int>> == std::range_format::sequence ); + +template<typename T> +struct MySet : std::vector<T> +{ + using key_type = T; +}; + +static_assert( std::format_kind<MySet<int>> == std::range_format::set ); + +template<typename T> +struct MyMap : std::vector<T> +{ + using key_type = T; + using mapped_type = int; +}; + +static_assert( std::format_kind<MyMap<std::pair<int, int>>> == std::range_format::map ); +static_assert( std::format_kind<MyMap<std::tuple<int, int>>> == std::range_format::map ); +static_assert( std::format_kind<MyMap<int>> == std::range_format::set ); + +template<typename T, std::range_format rf> +struct CustFormat : std::vector<T> +{ + using std::vector<T>::vector; +}; + +template<typename T, std::range_format rf> +constexpr auto std::format_kind<CustFormat<T, rf>> = rf; + +void test_override() +{ + CustFormat<int, std::range_format::disabled> disabledf; + static_assert( !std::formattable<decltype(disabledf), char> ); + + CustFormat<int, std::range_format::sequence> seqf{1, 2, 3}; + VERIFY( std::format("{}", seqf) == "[1, 2, 3]" ); + + CustFormat<int, std::range_format::set> setf{1, 2, 3}; + VERIFY( std::format("{}", setf) == "{1, 2, 3}" ); + + // TODO test map once formatter for pair is implenented + + CustFormat<char, std::range_format::string> stringf{'a', 'b', 'c', 'd'}; + VERIFY( std::format("{}", stringf) == "abcd" ); + // Support precision as string do + VERIFY( std::format("{:.2}", stringf) == "ab" ); + + CustFormat<char, std::range_format::debug_string> debugf{'a', 'b', 'c', 'd'}; + VERIFY( std::format("{}", debugf) == R"("abcd")" ); + // Support precision as string do + VERIFY( std::format("{:.3}", debugf) == R"("ab)" ); +} + +int main() +{ + test_override(); +} diff --git a/libstdc++-v3/testsuite/std/format/ranges/format_kind_neg.cc b/libstdc++-v3/testsuite/std/format/ranges/format_kind_neg.cc new file mode 100644 index 0000000..0d761ae --- /dev/null +++ b/libstdc++-v3/testsuite/std/format/ranges/format_kind_neg.cc @@ -0,0 +1,18 @@ +// { dg-do compile { target c++23 } } + +// C++23 22.14.7.1 [format.range.fmtkind] p1: A program that instantiates +// the primary template of format_kind is ill-formed. + +#include <format> + +void test() +{ + (void) std::format_kind<void>; // { dg-error "here" } + (void) std::format_kind<const void>; // { dg-error "here" } + (void) std::format_kind<int>; // { dg-error "here" } + (void) std::format_kind<int&>; // { dg-error "here" } + (void) std::format_kind<const int(&)[10]>; // { dg-error "here" } + (void) std::format_kind<void()>; // { dg-error "here" } +} + +// { dg-error "cannot use primary template of 'std::format_kind'" "" { target *-*-* } 0 } diff --git a/libstdc++-v3/testsuite/std/format/ranges/formatter.cc b/libstdc++-v3/testsuite/std/format/ranges/formatter.cc new file mode 100644 index 0000000..d3e0897 --- /dev/null +++ b/libstdc++-v3/testsuite/std/format/ranges/formatter.cc @@ -0,0 +1,170 @@ +// { dg-do run { target c++23 } } + +#include <flat_map> +#include <format> +#include <testsuite_hooks.h> +#include <vector> + +#define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S) +#define WIDEN(S) WIDEN_(CharT, S) + +template<typename T, + template<typename, typename> class Formatter = std::range_formatter> +struct MyVector : std::vector<T> +{ + using std::vector<T>::vector; +}; + +template<typename T, + template<typename, typename> class Formatter, + typename CharT> +struct std::formatter<MyVector<T, Formatter>, CharT> +{ + constexpr formatter() noexcept + { + _formatter.set_brackets(WIDEN("<"), WIDEN(">")); + _formatter.set_separator(WIDEN("; ")); + } + + constexpr std::basic_format_parse_context<CharT>::iterator + parse(std::basic_format_parse_context<CharT>& pc) + { return _formatter.parse(pc); } + + template<typename Out> + typename std::basic_format_context<Out, CharT>::iterator + format(const MyVector<T, Formatter>& mv, + std::basic_format_context<Out, CharT>& fc) const + { return _formatter.format(mv, fc); } + +private: + Formatter<T, CharT> _formatter; +}; + +template<typename CharT, template<typename, typename> class Formatter> +void +test_default() +{ + MyVector<int, Formatter> vec{1, 2, 3}; + std::basic_string<CharT> res; + + res = std::format(WIDEN("{}"), vec); + VERIFY( res == WIDEN("<1; 2; 3>") ); + res = std::format(WIDEN("{:}"), vec); + VERIFY( res == WIDEN("<1; 2; 3>") ); + res = std::format(WIDEN("{:n}"), vec); + VERIFY( res == WIDEN("1; 2; 3") ); + + res = std::format(WIDEN("{:3}"), vec); + VERIFY( res == WIDEN("<1; 2; 3>") ); + + res = std::format(WIDEN("{:10}"), vec); + VERIFY( res == WIDEN("<1; 2; 3> ") ); + + res = std::format(WIDEN("{:{}}"), vec, 10); + VERIFY( res == WIDEN("<1; 2; 3> ") ); + + res = std::format(WIDEN("{1:{0}}"), 10, vec); + VERIFY( res == WIDEN("<1; 2; 3> ") ); + + res = std::format(WIDEN("{:10n}"), vec); + VERIFY( res == WIDEN("1; 2; 3 ") ); + + res = std::format(WIDEN("{:*<11}"), vec); + VERIFY( res == WIDEN("<1; 2; 3>**") ); + + res = std::format(WIDEN("{:->12}"), vec); + VERIFY( res == WIDEN("---<1; 2; 3>") ); + + res = std::format(WIDEN("{:=^13}"), vec); + VERIFY( res == WIDEN("==<1; 2; 3>==") ); + + res = std::format(WIDEN("{:=^13n}"), vec); + VERIFY( res == WIDEN("===1; 2; 3===") ); + + res = std::format(WIDEN("{::#x}"), vec); + VERIFY( res == WIDEN("<0x1; 0x2; 0x3>") ); + + res = std::format(WIDEN("{:|^25n:#05x}"), vec); + VERIFY( res == WIDEN("|||0x001; 0x002; 0x003|||") ); + + // ':' is start of the format string for element + res = std::format(WIDEN("{::^+4}"), vec); + VERIFY( res == WIDEN("< +1 ; +2 ; +3 >") ); +} + +template<typename CharT, template<typename, typename> class Formatter> +void +test_override() +{ + MyVector<CharT, Formatter> vc{'a', 'b', 'c', 'd'}; + MyVector<std::pair<int, int>, Formatter> vp{{1, 11}, {2, 21}}; + std::basic_string<CharT> res; + + res = std::format(WIDEN("{:s}"), vc); + VERIFY( res == WIDEN("abcd") ); + res = std::format(WIDEN("{:?s}"), vc); + VERIFY( res == WIDEN("\"abcd\"") ); + res = std::format(WIDEN("{:+^6s}"), vc); + VERIFY( res == WIDEN("+abcd+") ); + + res = std::format(WIDEN("{:m}"), vp); + VERIFY( res == WIDEN("{1: 11, 2: 21}") ); + res = std::format(WIDEN("{:=^20m}"), vp); + VERIFY( res == WIDEN("==={1: 11, 2: 21}===") ); +} + +template<template<typename, typename> class Formatter> +void test_outputs() +{ + test_default<char, Formatter>(); + test_default<wchar_t, Formatter>(); + test_override<char, Formatter>(); + test_override<wchar_t, Formatter>(); +} + +void +test_nested() +{ + MyVector<MyVector<int>> v + { + {1, 2}, + {11, 12} + }; + + std::string res = std::format("{}", v); + VERIFY( res == "<<1; 2>; <11; 12>>" ); + + res = std::format("{:+^18:n:02}", v); + VERIFY( res == "+<01; 02; 11; 12>+" ); +} + +struct MyFlatMap : std::flat_map<int, int> +{ + using std::flat_map<int, int>::flat_map; +}; + +template<typename CharT> +struct std::formatter<MyFlatMap, CharT> + // This cannot apply format BitVector const&, because formatted type would + // be std::pair<int const&, int const&>, and formatter for + // pair<int const&, int> cannot format it. + : std::range_formatter<MyFlatMap::reference> +{}; + +void test_const_ref_type_mismatch() +{ + MyFlatMap m{{1, 11}, {2, 22}}; + std::string res = std::format("{:m}", m); + VERIFY( res == "{1: 11, 2: 22}" ); +} + +template<typename T, typename CharT> +using VectorFormatter = std::formatter<std::vector<T>, CharT>; + +int main() +{ + test_outputs<std::range_formatter>(); + test_outputs<VectorFormatter>(); + test_nested(); + test_const_ref_type_mismatch(); +} diff --git a/libstdc++-v3/testsuite/std/format/ranges/map.cc b/libstdc++-v3/testsuite/std/format/ranges/map.cc new file mode 100644 index 0000000..5e1b98f --- /dev/null +++ b/libstdc++-v3/testsuite/std/format/ranges/map.cc @@ -0,0 +1,210 @@ +// { dg-do run { target c++23 } } +// { dg-timeout-factor 2 } + +#include <flat_map> +#include <format> +#include <list> +#include <map> +#include <span> +#include <testsuite_hooks.h> +#include <testsuite_iterators.h> +#include <vector> + +struct NotFormattable +{ + friend auto operator<=>(NotFormattable, NotFormattable) = default; +}; + +static_assert( !std::formattable<std::map<int, NotFormattable>, char> ); +static_assert( !std::formattable<std::map<NotFormattable, int>, wchar_t> ); + +template<typename... Args> +bool +is_format_string_for(const char* str, Args&&... args) +{ + try { + (void) std::vformat(str, std::make_format_args(args...)); + return true; + } catch (const std::format_error&) { + return false; + } +} + +template<typename... Args> +bool +is_format_string_for(const wchar_t* str, Args&&... args) +{ + try { + (void) std::vformat(str, std::make_wformat_args(args...)); + return true; + } catch (const std::format_error&) { + return false; + } +} + +template<typename Rg, typename CharT> +bool is_range_formatter_spec_for(CharT const* spec, Rg&& rg) +{ + using V = std::remove_cvref_t<std::ranges::range_reference_t<Rg>>; + std::range_formatter<V, CharT> fmt; + std::basic_format_parse_context<CharT> pc(spec); + try { + (void)fmt.parse(pc); + return true; + } catch (const std::format_error&) { + return false; + } +} + +#define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S) +#define WIDEN(S) WIDEN_(CharT, S) + +void +test_format_string() +{ + // only pair<T, U> amd tuple<T, U> value types are supported + VERIFY( !is_range_formatter_spec_for("m", std::vector<int>()) ); + VERIFY( !is_format_string_for("{:m}", std::vector<int>()) ); + VERIFY( !is_range_formatter_spec_for("m", std::vector<std::tuple<int, int, int>>()) ); + VERIFY( !is_format_string_for("{:m}", std::vector<std::tuple<int, int, int>>()) ); + + // invalid format stringss + VERIFY( !is_range_formatter_spec_for("?m", std::vector<std::pair<int, int>>()) ); + VERIFY( !is_format_string_for("{:?m}", std::vector<std::pair<int, int>>()) ); + VERIFY( !is_range_formatter_spec_for("m:", std::vector<std::pair<int, int>>()) ); + VERIFY( !is_format_string_for("{:m:}", std::vector<std::pair<int, int>>()) ); + + // precision is not supported + VERIFY( !is_range_formatter_spec_for(".10m", std::vector<std::pair<int, int>>()) ); + VERIFY( !is_format_string_for("{:.10m}", std::vector<std::pair<int, int>>()) ); + VERIFY( !is_format_string_for("{:.{}m}", std::vector<std::pair<int, int>>(), 10) ); + + // width needs to be integer type + VERIFY( !is_format_string_for("{:{}m}", std::vector<std::pair<int, int>>(), 1.0f) ); +} + +template<typename CharT, typename Range> +void test_output(bool mapIsDefault) +{ + using Sv = std::basic_string_view<CharT>; + using Pt = std::ranges::range_value_t<Range>; + using Ft = std::remove_cvref_t<std::tuple_element_t<0, Pt>>; + using St = std::remove_cvref_t<std::tuple_element_t<1, Pt>>; + auto makeRange = [](std::span<Pt> s) { + return Range(s.data(), s.data() + s.size()); + }; + + std::basic_string<CharT> res; + size_t size = 0; + + Ft f1[]{1, 2, 3}; + St s1[]{11, 22, 33}; + Pt v1[]{{f1[0], s1[0]}, {f1[1], s1[1]}, {f1[2], s1[2]}}; + + res = std::format(WIDEN("{}"), makeRange(v1)); + if (mapIsDefault) + VERIFY( res == WIDEN("{1: 11, 2: 22, 3: 33}") ); + else + VERIFY( res == WIDEN("[(1, 11), (2, 22), (3, 33)]") ); + + res = std::format(WIDEN("{:m}"), makeRange(v1)); + VERIFY( res == WIDEN("{1: 11, 2: 22, 3: 33}") ); + res = std::format(WIDEN("{:nm}"), makeRange(v1)); + VERIFY( res == WIDEN("1: 11, 2: 22, 3: 33") ); + + res = std::format(WIDEN("{:3m}"), makeRange(v1)); + VERIFY( res == WIDEN("{1: 11, 2: 22, 3: 33}") ); + + res = std::format(WIDEN("{:25m}"), makeRange(v1)); + VERIFY( res == WIDEN("{1: 11, 2: 22, 3: 33} ") ); + + res = std::format(WIDEN("{:{}m}"), makeRange(v1), 25); + VERIFY( res == WIDEN("{1: 11, 2: 22, 3: 33} ") ); + + res = std::format(WIDEN("{1:{0}m}"), 25, makeRange(v1)); + VERIFY( res == WIDEN("{1: 11, 2: 22, 3: 33} ") ); + + res = std::format(WIDEN("{:25nm}"), makeRange(v1)); + VERIFY( res == WIDEN("1: 11, 2: 22, 3: 33 ") ); + + res = std::format(WIDEN("{:*<23m}"), makeRange(v1)); + VERIFY( res == WIDEN("{1: 11, 2: 22, 3: 33}**") ); + + res = std::format(WIDEN("{:->24m}"), makeRange(v1)); + VERIFY( res == WIDEN("---{1: 11, 2: 22, 3: 33}") ); + + res = std::format(WIDEN("{:=^25m}"), makeRange(v1)); + VERIFY( res == WIDEN("=={1: 11, 2: 22, 3: 33}==") ); + + res = std::format(WIDEN("{:=^25nm}"), makeRange(v1)); + VERIFY( res == WIDEN("===1: 11, 2: 22, 3: 33===") ); + + size = std::formatted_size(WIDEN("{:m}"), makeRange(v1)); + VERIFY( size == Sv(WIDEN("{1: 11, 2: 22, 3: 33}")).size() ); + + size = std::formatted_size(WIDEN("{:3m}"), makeRange(v1)); + VERIFY( size == Sv(WIDEN("{1: 11, 2: 22, 3: 33}")).size() ); + + size = std::formatted_size(WIDEN("{:25m}"), makeRange(v1)); + VERIFY( size == 25 ); +} + +template<class Range> +void test_output_c(bool mapIsDefault = false) +{ + test_output<char, Range>(mapIsDefault); + test_output<wchar_t, Range>(mapIsDefault); +} + +template<template<typename> class RangeT> +void test_output_pc() +{ + test_output_c<RangeT<std::pair<int, int>>>(); + test_output_c<RangeT<std::pair<const int, int>>>(); + test_output_c<RangeT<std::tuple<const int&, int&>>>(); +} + +void +test_outputs() +{ + using namespace __gnu_test; + test_output_c<std::map<int, int>>(true); + test_output_c<std::flat_map<int, int>>(true); + + test_output_pc<std::vector>(); + test_output_pc<std::list>(); + test_output_pc<std::span>(); + + test_output_pc<test_forward_range>(); + test_output_pc<test_input_range>(); + test_output_pc<test_input_range_nocopy>(); +} + +void +test_nested() +{ + std::vector<std::map<int, std::string>> vm{ + {{1, "one"}, {2, "two"}}, + {{1, "jeden"}, {2, "dwa"}}, + }; + std::string res; + + res = std::format("{}", vm); + VERIFY( res == R"([{1: "one", 2: "two"}, {1: "jeden", 2: "dwa"}])" ); + res = std::format("{:n:n}", vm); + VERIFY( res == R"(1: "one", 2: "two", 1: "jeden", 2: "dwa")" ); + + std::map<std::string, std::vector<std::string>> mv{ + {"english", {"zero", "one", "two"}}, + {"polish", {"zero", "jeden", "dwa"}}, + }; + res = std::format("{}", mv); + VERIFY( res == R"({"english": ["zero", "one", "two"], "polish": ["zero", "jeden", "dwa"]})" ); +} + +int main() +{ + test_format_string(); + test_outputs(); + test_nested(); +} diff --git a/libstdc++-v3/testsuite/std/format/ranges/sequence.cc b/libstdc++-v3/testsuite/std/format/ranges/sequence.cc new file mode 100644 index 0000000..7fb65f9 --- /dev/null +++ b/libstdc++-v3/testsuite/std/format/ranges/sequence.cc @@ -0,0 +1,332 @@ +// { dg-do run { target c++23 } } +// { dg-options "-fexec-charset=UTF-8" } +// { dg-timeout-factor 2 } + +#include <array> +#include <format> +#include <list> +#include <ranges> +#include <span> +#include <string> +#include <testsuite_hooks.h> +#include <testsuite_iterators.h> +#include <vector> + +struct NotFormattable +{}; + +static_assert(!std::formattable<std::vector<NotFormattable>, char>); +static_assert(!std::formattable<std::span<NotFormattable>, wchar_t>); + +template<typename... Args> +bool +is_format_string_for(const char* str, Args&&... args) +{ + try { + (void) std::vformat(str, std::make_format_args(args...)); + return true; + } catch (const std::format_error&) { + return false; + } +} + +template<typename... Args> +bool +is_format_string_for(const wchar_t* str, Args&&... args) +{ + try { + (void) std::vformat(str, std::make_wformat_args(args...)); + return true; + } catch (const std::format_error&) { + return false; + } +} + +template<typename Rg, typename CharT> +bool is_range_formatter_spec_for(CharT const* spec, Rg&& rg) +{ + using V = std::remove_cvref_t<std::ranges::range_reference_t<Rg>>; + std::range_formatter<V, CharT> fmt; + std::basic_format_parse_context<CharT> pc(spec); + try { + (void)fmt.parse(pc); + return true; + } catch (const std::format_error&) { + return false; + } +} + +void +test_format_string() +{ + // invalid format spec 'p' + VERIFY( !is_range_formatter_spec_for("p", std::vector<int>()) ); + VERIFY( !is_format_string_for("{:p}", std::vector<int>()) ); + VERIFY( !is_range_formatter_spec_for("np", std::vector<int>()) ); + VERIFY( !is_format_string_for("{:np}", std::vector<int>()) ); + + // width needs to be integer type + VERIFY( !is_format_string_for("{:{}}", std::vector<int>(), 1.0f) ); + + // element format needs to be valid + VERIFY( !is_range_formatter_spec_for(":p", std::vector<int>()) ); + VERIFY( !is_format_string_for("{::p}", std::vector<int>()) ); + VERIFY( !is_range_formatter_spec_for("n:p", std::vector<int>()) ); + VERIFY( !is_format_string_for("{:n:p}", std::vector<int>()) ); +} + +#define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S) +#define WIDEN(S) WIDEN_(CharT, S) + +template<typename CharT, typename Range, typename Storage> +void test_output() +{ + using Sv = std::basic_string_view<CharT>; + using T = std::ranges::range_value_t<Range>; + auto makeRange = [](Storage& s) -> Range { + if constexpr (std::is_same_v<std::remove_cvref_t<Range>, Storage>) + return s; + else + return Range(std::ranges::data(s), + std::ranges::data(s) + std::ranges::size(s)); + }; + + std::basic_string<CharT> res; + size_t size = 0; + + Storage v1{1, 2, 3}; + res = std::format(WIDEN("{}"), makeRange(v1)); + VERIFY( res == WIDEN("[1, 2, 3]") ); + res = std::format(WIDEN("{:}"), makeRange(v1)); + VERIFY( res == WIDEN("[1, 2, 3]") ); + res = std::format(WIDEN("{:n}"), makeRange(v1)); + VERIFY( res == WIDEN("1, 2, 3") ); + + res = std::format(WIDEN("{:3}"), makeRange(v1)); + VERIFY( res == WIDEN("[1, 2, 3]") ); + + res = std::format(WIDEN("{:10}"), makeRange(v1)); + VERIFY( res == WIDEN("[1, 2, 3] ") ); + + res = std::format(WIDEN("{:{}}"), makeRange(v1), 10); + VERIFY( res == WIDEN("[1, 2, 3] ") ); + + res = std::format(WIDEN("{1:{0}}"), 10, makeRange(v1)); + VERIFY( res == WIDEN("[1, 2, 3] ") ); + + res = std::format(WIDEN("{:10n}"), makeRange(v1)); + VERIFY( res == WIDEN("1, 2, 3 ") ); + + res = std::format(WIDEN("{:*<11}"), makeRange(v1)); + VERIFY( res == WIDEN("[1, 2, 3]**") ); + + res = std::format(WIDEN("{:->12}"), makeRange(v1)); + VERIFY( res == WIDEN("---[1, 2, 3]") ); + + res = std::format(WIDEN("{:=^13}"), makeRange(v1)); + VERIFY( res == WIDEN("==[1, 2, 3]==") ); + + res = std::format(WIDEN("{:=^13n}"), makeRange(v1)); + VERIFY( res == WIDEN("===1, 2, 3===") ); + + res = std::format(WIDEN("{::#x}"), makeRange(v1)); + VERIFY( res == WIDEN("[0x1, 0x2, 0x3]") ); + + res = std::format(WIDEN("{:|^25n:#05x}"), makeRange(v1)); + VERIFY( res == WIDEN("|||0x001, 0x002, 0x003|||") ); + + // ':' is start of the format string for element + res = std::format(WIDEN("{::^+04}"), makeRange(v1)); + VERIFY( res == WIDEN("[ +1 , +2 , +3 ]") ); + + size = std::formatted_size(WIDEN("{:}"), makeRange(v1)); + VERIFY( size == Sv(WIDEN("[1, 2, 3]")).size() ); + + size = std::formatted_size(WIDEN("{:3}"), makeRange(v1)); + VERIFY( size == Sv(WIDEN("[1, 2, 3]")).size() ); + + size = std::formatted_size(WIDEN("{:10}"), makeRange(v1)); + VERIFY( size == 10 ); + + size = std::formatted_size(WIDEN("{:|^25n:#05x}"), makeRange(v1)); + VERIFY( size == 25 ); +} + +template<typename Cont> +void test_output_cont() +{ + test_output<char, Cont&, Cont>(); + test_output<wchar_t, Cont const&, Cont>(); +} + +template<typename View> +void test_output_view() +{ + test_output<char, View, int[3]>(); + test_output<wchar_t, View, int[3]>(); +} + +void +test_outputs() +{ + using namespace __gnu_test; + test_output_cont<std::vector<int>>(); + test_output_cont<std::list<int>>(); + test_output_cont<std::array<int, 3>>(); + + test_output_view<std::span<int>>(); + test_output_view<std::ranges::subrange<int*>>(); + test_output_view<test_forward_range<int>>(); + test_output_view<test_input_range<int>>(); + test_output_view<test_input_range_nocopy<int>>(); + + test_output_view<std::span<const int>>(); + test_output_view<std::ranges::subrange<const int*>>(); + test_output_view<test_forward_range<const int>>(); +} + +void +test_nested() +{ + std::vector<std::vector<int>> v + { + {1, 2}, + {11, 12} + }; + + std::string res = std::format("{}", v); + VERIFY( res == "[[1, 2], [11, 12]]" ); + + res = std::format("{:+^18:n:02}", v); + VERIFY( res == "+[01, 02, 11, 12]+" ); +} + +bool strip_quote(std::string_view& v) +{ + if (!v.starts_with('"')) + return false; + v.remove_prefix(1); + return true; +} + +bool strip_prefix(std::string_view& v, std::string_view expected, bool quoted = false) +{ + if (quoted && !strip_quote(v)) + return false; + if (!v.starts_with(expected)) + return false; + v.remove_prefix(expected.size()); + if (quoted && !strip_quote(v)) + return false; + return true; +} + +bool strip_squares(std::string_view& v) +{ + if (!v.starts_with('[') || !v.ends_with(']')) + return false; + v.remove_prefix(1); + v.remove_suffix(1); + return true; +} + +bool strip_prefix(std::string_view& v, size_t n, char c) +{ + size_t pos = v.find_first_not_of(c); + if (pos == std::string_view::npos) + pos = v.size(); + if (pos != n) + return false; + v.remove_prefix(n); + return true; +} + +void test_padding() +{ + std::string res; + std::string_view resv; + + // width is 3, size is 15 + std::string in = "o\u0302\u0323i\u0302\u0323u\u0302\u0323"; + in += in; // width is 6, size is 30 + in += in; // width is 12, size is 60 + in += in; // width is 24, size is 120 + in += in; // width is 48, size is 240 + // width is 192, size is 960 + std::vector<std::string> const vs{in, in, in, in}; + + auto const check_elems = [=](std::string_view& v, bool quoted) + { + VERIFY( strip_prefix(v, in, quoted) ); + VERIFY( strip_prefix(v, ", ", false) ); + VERIFY( strip_prefix(v, in, quoted) ); + VERIFY( strip_prefix(v, ", ", false) ); + VERIFY( strip_prefix(v, in, quoted) ); + VERIFY( strip_prefix(v, ", ", false) ); + VERIFY( strip_prefix(v, in, quoted) ); + return v.empty(); + }; + + resv = res = std::format("{}", vs); + VERIFY( strip_squares(resv) ); + VERIFY( check_elems(resv, true) ); + + resv = res = std::format("{:n}", vs); + VERIFY( check_elems(resv, true) ); + + resv = res = std::format("{::}", vs); + VERIFY( strip_squares(resv) ); + VERIFY( check_elems(resv, false) ); + + resv = res = std::format("{:n:}", vs); + VERIFY( check_elems(resv, false) ); + + resv = res = std::format("{:*>10}", vs); + VERIFY( strip_squares(resv) ); + VERIFY( check_elems(resv, true) ); + + resv = res = std::format("{:*>10n}", vs); + VERIFY( check_elems(resv, true) ); + + resv = res = std::format("{:*>10:}", vs); + VERIFY( strip_squares(resv) ); + VERIFY( check_elems(resv, false) ); + + resv = res = std::format("{:*>10n:}", vs); + VERIFY( check_elems(resv, false) ); + + resv = res = std::format("{:*>256}", vs); + VERIFY( strip_prefix(resv, 48, '*') ); + VERIFY( strip_squares(resv) ); + VERIFY( check_elems(resv, true) ); + + resv = res = std::format("{:*>256n}", vs); + VERIFY( strip_prefix(resv, 50, '*') ); + VERIFY( check_elems(resv, true) ); + + resv = res = std::format("{:*>240}", vs); + VERIFY( strip_prefix(resv, 32, '*') ); + VERIFY( strip_squares(resv) ); + VERIFY( check_elems(resv, true) ); + + resv = res = std::format("{:*>240n}", vs); + VERIFY( strip_prefix(resv, 34, '*') ); + VERIFY( check_elems(resv, true) ); + + resv = res = std::format("{:*>240:}", vs); + VERIFY( strip_prefix(resv, 40, '*') ); + VERIFY( strip_squares(resv) ); + VERIFY( check_elems(resv, false) ); + + resv = res = std::format("{:*>240n:}", vs); + VERIFY( strip_prefix(resv, 42, '*') ); + VERIFY( check_elems(resv, false) ); +} + +int main() +{ + test_format_string(); + test_outputs(); + test_nested(); + test_padding(); +} diff --git a/libstdc++-v3/testsuite/std/format/ranges/string.cc b/libstdc++-v3/testsuite/std/format/ranges/string.cc new file mode 100644 index 0000000..99e5eaf --- /dev/null +++ b/libstdc++-v3/testsuite/std/format/ranges/string.cc @@ -0,0 +1,290 @@ +// { dg-do run { target c++23 } } +// { dg-options "-fexec-charset=UTF-8" } +// { dg-timeout-factor 2 } + +#include <format> +#include <forward_list> +#include <span> +#include <testsuite_hooks.h> +#include <testsuite_iterators.h> +#include <vector> + +template<typename... Args> +bool +is_format_string_for(const char* str, Args&&... args) +{ + try { + (void) std::vformat(str, std::make_format_args(args...)); + return true; + } catch (const std::format_error&) { + return false; + } +} + +template<typename... Args> +bool +is_format_string_for(const wchar_t* str, Args&&... args) +{ + try { + (void) std::vformat(str, std::make_wformat_args(args...)); + return true; + } catch (const std::format_error&) { + return false; + } +} + +template<typename Rg, typename CharT> +bool is_range_formatter_spec_for(CharT const* spec, Rg&& rg) +{ + using V = std::remove_cvref_t<std::ranges::range_reference_t<Rg>>; + std::range_formatter<V, CharT> fmt; + std::basic_format_parse_context<CharT> pc(spec); + try { + (void)fmt.parse(pc); + return true; + } catch (const std::format_error&) { + return false; + } +} + +#define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S) +#define WIDEN(S) WIDEN_(CharT, S) + +void +test_format_string() +{ + // only CharT value types are supported + VERIFY( !is_range_formatter_spec_for(L"s", std::vector<char>()) ); + VERIFY( !is_format_string_for(L"{:s}", std::vector<char>()) ); + VERIFY( !is_range_formatter_spec_for(L"s", std::vector<char>()) ); + VERIFY( !is_format_string_for(L"{:s}", std::vector<char>()) ); + VERIFY( !is_range_formatter_spec_for("s", std::vector<int>()) ); + VERIFY( !is_format_string_for("{:s}", std::vector<int>()) ); + + // invalid format stringss + VERIFY( !is_range_formatter_spec_for("?", std::vector<char>()) ); + VERIFY( !is_format_string_for("{:?}", std::vector<char>()) ); + VERIFY( !is_range_formatter_spec_for("ns", std::vector<char>()) ); + VERIFY( !is_format_string_for("{:ns}", std::vector<char>()) ); + VERIFY( !is_range_formatter_spec_for("s:", std::vector<char>()) ); + VERIFY( !is_format_string_for("{:s:}", std::vector<char>()) ); + + // precision is not supported, even for s + VERIFY( !is_range_formatter_spec_for(".10s", std::vector<char>()) ); + VERIFY( !is_format_string_for("{:.10s}", std::vector<char>()) ); + VERIFY( !is_format_string_for("{:.{}s}", std::vector<char>(), 10) ); + + // width needs to be integer type + VERIFY( !is_format_string_for("{:{}s}", std::vector<char>(), 1.0f) ); +} + +template<typename Range> +void test_output() +{ + using CharT = std::ranges::range_value_t<Range>; + auto makeRange = [](std::basic_string<CharT>& s) { + return Range(s.data(), s.data() + s.size()); + }; + std::basic_string<CharT> res; + size_t size = 0; + + std::basic_string<CharT> s1 = WIDEN("abcd"); + res = std::format(WIDEN("{}"), makeRange(s1)); + VERIFY( res == WIDEN("['a', 'b', 'c', 'd']") ); + + res = std::format(WIDEN("{::}"), makeRange(s1)); + VERIFY( res == WIDEN("[a, b, c, d]") ); + + res = std::format(WIDEN("{:s}"), makeRange(s1)); + VERIFY( res == WIDEN("abcd") ); + + res = std::format(WIDEN("{:?s}"), makeRange(s1)); + VERIFY( res == WIDEN(R"("abcd")") ); + + res = std::format(WIDEN("{:3s}"), makeRange(s1)); + VERIFY( res == WIDEN("abcd") ); + + res = std::format(WIDEN("{:7s}"), makeRange(s1)); + VERIFY( res == WIDEN("abcd ") ); + + res = std::format(WIDEN("{:{}s}"), makeRange(s1), 7); + VERIFY( res == WIDEN("abcd ") ); + + res = std::format(WIDEN("{1:{0}s}"), 7, makeRange(s1)); + VERIFY( res == WIDEN("abcd ") ); + + res = std::format(WIDEN("{:*>6s}"), makeRange(s1)); + VERIFY( res == WIDEN("**abcd") ); + + res = std::format(WIDEN("{:-<5s}"), makeRange(s1)); + VERIFY( res == WIDEN("abcd-") ); + + res = std::format(WIDEN("{:=^8s}"), makeRange(s1)); + VERIFY( res == WIDEN("==abcd==") ); + + std::basic_string<CharT> s2(512, static_cast<CharT>('a')); + res = std::format(WIDEN("{:=^8s}"), makeRange(s2)); + VERIFY( res == s2 ); + + size = std::formatted_size(WIDEN("{:s}"), makeRange(s1)); + VERIFY( size == 4 ); + + size = std::formatted_size(WIDEN("{:3s}"), makeRange(s1)); + VERIFY( size == 4 ); + + size = std::formatted_size(WIDEN("{:7s}"), makeRange(s1)); + VERIFY( size == 7 ); + + size = std::formatted_size(WIDEN("{:s}"), makeRange(s2)); + VERIFY( size == 512 ); +} + +template<typename CharT> +struct cstr_view +{ + cstr_view() = default; + explicit cstr_view(CharT* f, CharT* l) + : ptr(f) + { VERIFY(!*l); } + + struct sentinel + { + friend constexpr + bool operator==(CharT const* ptr, sentinel) noexcept + { return !*ptr; } + }; + + constexpr + CharT* begin() const noexcept + { return ptr; }; + static constexpr + sentinel end() noexcept + { return {}; } + +private: + CharT* ptr = ""; +}; + +template<typename CharT> +void +test_outputs() +{ + using namespace __gnu_test; + test_output<std::vector<CharT>>(); + test_output<std::span<CharT>>(); + test_output<cstr_view<CharT>>(); + + test_output<test_forward_range<CharT>>(); + test_output<test_forward_sized_range<CharT>>(); + + test_output<test_input_range<CharT>>(); + test_output<test_input_sized_range<CharT>>(); + + test_output<test_range_nocopy<CharT, input_iterator_wrapper_nocopy>>(); + test_output<test_sized_range<CharT, input_iterator_wrapper_nocopy>>(); + + test_output<std::span<const CharT>>(); + test_output<cstr_view<const CharT>>(); + test_output<test_forward_range<const CharT>>(); + + static_assert(!std::formattable<std::span<volatile CharT>, CharT>); + static_assert(!std::formattable<std::span<const volatile CharT>, CharT>); +} + +void +test_nested() +{ + std::string_view s1 = "str1"; + std::string_view s2 = "str2"; + + std::vector<std::string> vs; + vs.emplace_back(s1); + vs.emplace_back(s2); + + VERIFY( std::format("{}", vs) == R"(["str1", "str2"])" ); + VERIFY( std::format("{:}", vs) == R"(["str1", "str2"])" ); + VERIFY( std::format("{::?}", vs) == R"(["str1", "str2"])" ); + VERIFY( std::format("{::}", vs) == R"([str1, str2])" ); + + std::vector<std::vector<char>> vv; + vv.emplace_back(s1.begin(), s1.end()); + vv.emplace_back(s2.begin(), s2.end()); + std::string_view escaped = R"([['s', 't', 'r', '1'], ['s', 't', 'r', '2']])"; + + VERIFY( std::format("{}", vv) == escaped ); + VERIFY( std::format("{:}", vv) == escaped ); + VERIFY( std::format("{::}", vv) == escaped ); + VERIFY( std::format("{:::?}", vv) == escaped ); + VERIFY( std::format("{:::}", vv) == R"([[s, t, r, 1], [s, t, r, 2]])" ); + VERIFY( std::format("{::s}", vv) == R"([str1, str2])" ); + VERIFY( std::format("{::?s}", vv) == R"(["str1", "str2"])" ); +} + +bool strip_quotes(std::string_view& v) +{ + if (!v.starts_with('"') || !v.ends_with('"')) + return false; + v.remove_prefix(1); + v.remove_suffix(1); + return true; +} + +bool strip_prefix(std::string_view& v, size_t n, char c) +{ + size_t pos = v.find_first_not_of(c); + if (pos == std::string_view::npos) + pos = v.size(); + if (pos != n) + return false; + v.remove_prefix(n); + return true; +} + + +void test_padding() +{ + std::string res; + std::string_view resv; + + // width is 3, size is 15 + std::string in = "o\u0302\u0323i\u0302\u0323u\u0302\u0323"; + in += in; // width is 6, size is 30 + in += in; // width is 12, size is 60 + in += in; // width is 24, size is 120 + in += in; // width is 48, size is 240 + in += in; // width is 96, size is 480 + in += in; // width is 192, size is 960 + + std::forward_list<char> lc(std::from_range, in); + + resv = res = std::format("{:s}", lc); + VERIFY( resv == in ); + + resv = res = std::format("{:*>10s}", lc); + VERIFY( resv == in ); + + resv = res = std::format("{:*>240s}", lc); + VERIFY( strip_prefix(resv, 48, '*') ); + VERIFY( resv == in ); + + resv = res = std::format("{:?s}", lc); + VERIFY( strip_quotes(resv) ); + VERIFY( resv == in ); + + resv = res = std::format("{:*>10?s}", lc); + VERIFY( strip_quotes(resv) ); + VERIFY( resv == in ); + + resv = res = std::format("{:*>240?s}", lc); + VERIFY( strip_prefix(resv, 46, '*') ); + VERIFY( strip_quotes(resv) ); + VERIFY( resv == in ); +} + +int main() +{ + test_format_string(); + test_outputs<char>(); + test_outputs<wchar_t>(); + test_nested(); +} diff --git a/libstdc++-v3/testsuite/std/format/tuple.cc b/libstdc++-v3/testsuite/std/format/tuple.cc new file mode 100644 index 0000000..ba6dae8 --- /dev/null +++ b/libstdc++-v3/testsuite/std/format/tuple.cc @@ -0,0 +1,351 @@ +// { dg-do run { target c++23 } } +// { dg-options "-fexec-charset=UTF-8" } +// { dg-timeout-factor 2 } + +#include <format> +#include <string> +#include <testsuite_hooks.h> +#include <tuple> +#include <utility> + +struct NotFormattable +{}; + +static_assert( !std::formattable<std::pair<int, NotFormattable>, char> ); +static_assert( !std::formattable<std::tuple<int, NotFormattable, int>, wchar_t> ); + +template<typename... Args> +bool +is_format_string_for(const char* str, Args&&... args) +{ + try { + (void) std::vformat(str, std::make_format_args(args...)); + return true; + } catch (const std::format_error&) { + return false; + } +} + +template<typename... Args> +bool +is_format_string_for(const wchar_t* str, Args&&... args) +{ + try { + (void) std::vformat(str, std::make_wformat_args(args...)); + return true; + } catch (const std::format_error&) { + return false; + } +} + +#define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S) +#define WIDEN(S) WIDEN_(CharT, S) + +void +test_format_string() +{ + // invalid format stringss + VERIFY( !is_format_string_for("{:p}", std::tuple<>()) ); + VERIFY( !is_format_string_for("{:nm}", std::tuple<>()) ); + + // 'm' is only valid for 2 elemenst + VERIFY( !is_format_string_for("{:m}", std::tuple<>()) ); + VERIFY( !is_format_string_for("{:m}", std::tuple<int, int, int>()) ); + + // element specifier is not supported + VERIFY( !is_format_string_for("{::}", std::tuple<>()) ); + + // precision is not supported + VERIFY( !is_format_string_for("{:.10}", std::tuple<>()) ); + + // width needs to be integer type + VERIFY( !is_format_string_for("{:{}}", std::tuple<>(), 1.0f) ); +} + +template<typename CharT> +void test_multi() +{ + using Sv = std::basic_string_view<CharT>; + using Str = std::basic_string<CharT>; + + std::basic_string<CharT> res; + std::size_t size = 0; + std::tuple<int, Str, float> t1(1, WIDEN("test"), 2.1); + + res = std::format(WIDEN("{}"), t1); + VERIFY( res == WIDEN(R"((1, "test", 2.1))") ); + res = std::format(WIDEN("{:}"), t1); + VERIFY( res == WIDEN(R"((1, "test", 2.1))") ); + res = std::format(WIDEN("{:n}"), t1); + VERIFY( res == WIDEN(R"(1, "test", 2.1)") ); + + res = std::format(WIDEN("{:3}"), t1); + VERIFY( res == WIDEN(R"((1, "test", 2.1))") ); + + res = std::format(WIDEN("{:20}"), t1); + VERIFY( res == WIDEN(R"((1, "test", 2.1) )") ); + + res = std::format(WIDEN("{:{}}"), t1, 20); + VERIFY( res == WIDEN(R"((1, "test", 2.1) )") ); + + res = std::format(WIDEN("{1:{0}}"), 20, t1); + VERIFY( res == WIDEN(R"((1, "test", 2.1) )") ); + + res = std::format(WIDEN("{:^>17}"), t1); + VERIFY( res == WIDEN(R"(^(1, "test", 2.1))") ); + + res = std::format(WIDEN("{:$<18}"), t1); + VERIFY( res == WIDEN(R"((1, "test", 2.1)$$)") ); + + res = std::format(WIDEN("{:+^19}"), t1); + VERIFY( res == WIDEN(R"(+(1, "test", 2.1)++)") ); + + res = std::format(WIDEN("{:|^19n}"), t1); + VERIFY( res == WIDEN(R"(||1, "test", 2.1|||)") ); + + size = std::formatted_size(WIDEN("{}"), t1); + VERIFY( size == Sv(WIDEN(R"((1, "test", 2.1))")).size() ); + + size = std::formatted_size(WIDEN("{:3}"), t1); + VERIFY( size == Sv(WIDEN(R"((1, "test", 2.1))")).size() ); + + size = std::formatted_size(WIDEN("{:20}"), t1); + VERIFY( size == 20 ); + + std::tuple<int&, Str&, float&> t2 = t1; + res = std::format(WIDEN("{}"), t2); + VERIFY( res == WIDEN(R"((1, "test", 2.1))") ); + + std::tuple<int, int, int, int> t3(1, 2, 3, 4); + res = std::format(WIDEN("{}"), t3); + VERIFY( res == WIDEN(R"((1, 2, 3, 4))") ); + +} + +template<typename CharT, typename Tuple> +void test_empty() +{ + std::basic_string<CharT> res; + + Tuple e1; + res = std::format(WIDEN("{}"), e1); + VERIFY( res == WIDEN(R"(())") ); + + res = std::format(WIDEN("{:}"), e1); + VERIFY( res == WIDEN(R"(())") ); + + res = std::format(WIDEN("{:n}"), e1); + VERIFY( res == WIDEN(R"()") ); + + res = std::format(WIDEN("{:^>6}"), e1); + VERIFY( res == WIDEN(R"(^^^^())") ); +} + +template<typename CharT, typename Pair> +void test_pair() +{ + using Ft = std::remove_cvref_t<std::tuple_element_t<0, Pair>>; + using St = std::remove_cvref_t<std::tuple_element_t<1, Pair>>; + + std::basic_string<CharT> res; + + Ft f1 = 1; + St s1 = WIDEN("abc"); + Pair p1(f1, s1); + + res = std::format(WIDEN("{}"), p1); + VERIFY( res == WIDEN(R"((1, "abc"))") ); + + res = std::format(WIDEN("{:}"), p1); + VERIFY( res == WIDEN(R"((1, "abc"))") ); + + res = std::format(WIDEN("{:m}"), p1); + VERIFY( res == WIDEN(R"(1: "abc")") ); + + res = std::format(WIDEN("{:|^12m}"), p1); + VERIFY( res == WIDEN(R"(||1: "abc"||)") ); +} + +template<typename CharT, template<typename, typename> class PairT> +void test_pair_e() +{ + test_pair<CharT, PairT<int, std::basic_string<CharT>>>(); + test_pair<CharT, PairT<int, const CharT*>>(); + test_pair<CharT, PairT<const int, std::basic_string<CharT>>>(); + test_pair<CharT, PairT<int&, std::basic_string<CharT>&>>(); + test_pair<CharT, PairT<const int&, const std::basic_string<CharT>&>>(); +} + +template<typename Pair> +struct MyPair : Pair +{ + using Pair::Pair; +}; + +template<typename Pair, typename CharT> +struct std::formatter<MyPair<Pair>, CharT> +{ + constexpr formatter() noexcept + { + _formatter.set_brackets(WIDEN("<"), WIDEN(">")); + _formatter.set_separator(WIDEN("; ")); + } + + constexpr std::basic_format_parse_context<CharT>::iterator + parse(std::basic_format_parse_context<CharT>& pc) + { return _formatter.parse(pc); } + + template<typename Out> + typename std::basic_format_context<Out, CharT>::iterator + format(const MyPair<Pair>& mp, + std::basic_format_context<Out, CharT>& fc) const + { return _formatter.format(mp, fc); } + +private: + std::formatter<Pair, CharT> _formatter; +}; + +template<typename CharT, template<typename, typename> class PairT> +void test_custom() +{ + std::basic_string<CharT> res; + MyPair<PairT<int, const CharT*>> c1(1, WIDEN("abc")); + + res = std::format(WIDEN("{}"), c1); + VERIFY( res == WIDEN(R"(<1; "abc">)") ); + + res = std::format(WIDEN("{:}"), c1); + VERIFY( res == WIDEN(R"(<1; "abc">)") ); + + res = std::format(WIDEN("{:n}"), c1); + VERIFY( res == WIDEN(R"(1; "abc")") ); + + res = std::format(WIDEN("{:m}"), c1); + VERIFY( res == WIDEN(R"(1: "abc")") ); + + res = std::format(WIDEN("{:|^14}"), c1); + VERIFY( res == WIDEN(R"(||<1; "abc">||)") ); +} + +template<typename CharT> +void test_outputs() +{ + test_multi<CharT>(); + test_empty<CharT, std::tuple<>>(); + test_pair_e<CharT, std::pair>(); + test_pair_e<CharT, std::tuple>(); + test_custom<CharT, std::pair>(); + test_custom<CharT, std::tuple>(); +} + +void test_nested() +{ + std::string res; + std::tuple<std::tuple<>, std::pair<int, std::string>> tt{{}, {1, "abc"}}; + + res = std::format("{}", tt); + VERIFY( res == R"(((), (1, "abc")))" ); + res = std::format("{:n}", tt); + VERIFY( res == R"((), (1, "abc"))" ); + res = std::format("{:m}", tt); + VERIFY( res == R"((): (1, "abc"))" ); +} + +bool strip_quote(std::string_view& v) +{ + if (!v.starts_with('"')) + return false; + v.remove_prefix(1); + return true; +} + +bool strip_prefix(std::string_view& v, std::string_view expected, bool quoted = false) +{ + if (quoted && !strip_quote(v)) + return false; + if (!v.starts_with(expected)) + return false; + v.remove_prefix(expected.size()); + if (quoted && !strip_quote(v)) + return false; + return true; +} + +bool strip_parens(std::string_view& v) +{ + if (!v.starts_with('(') || !v.ends_with(')')) + return false; + v.remove_prefix(1); + v.remove_suffix(1); + return true; +} + +bool strip_prefix(std::string_view& v, size_t n, char c) +{ + size_t pos = v.find_first_not_of(c); + if (pos == std::string_view::npos) + pos = v.size(); + if (pos != n) + return false; + v.remove_prefix(n); + return true; +} + +void test_padding() +{ + std::string res; + std::string_view resv; + + // width is 3, size is 15 + std::string in = "o\u0302\u0323i\u0302\u0323u\u0302\u0323"; + in += in; // width is 6, size is 30 + in += in; // width is 12, size is 60 + in += in; // width is 24, size is 120 + in += in; // width is 48, size is 240 + // width is 192, size is 960 + auto const ts = std::make_tuple(in, in, in, in); + + auto const check_elems = [=](std::string_view& v) + { + VERIFY( strip_prefix(v, in, true) ); + VERIFY( strip_prefix(v, ", ", false) ); + VERIFY( strip_prefix(v, in, true) ); + VERIFY( strip_prefix(v, ", ", false) ); + VERIFY( strip_prefix(v, in, true) ); + VERIFY( strip_prefix(v, ", ", false) ); + VERIFY( strip_prefix(v, in, true) ); + return v.empty(); + }; + + resv = res = std::format("{}", ts); + VERIFY( strip_parens(resv) ); + VERIFY( check_elems(resv) ); + + resv = res = std::format("{:n}", ts); + VERIFY( check_elems(resv) ); + + resv = res = std::format("{:*>10}", ts); + VERIFY( strip_parens(resv) ); + VERIFY( check_elems(resv) ); + + resv = res = std::format("{:*>10n}", ts); + VERIFY( check_elems(resv) ); + + resv = res = std::format("{:*>240}", ts); + VERIFY( strip_prefix(resv, 32, '*') ); + VERIFY( strip_parens(resv) ); + VERIFY( check_elems(resv) ); + + resv = res = std::format("{:*>240n}", ts); + VERIFY( strip_prefix(resv, 34, '*') ); + VERIFY( check_elems(resv) ); +} + +int main() +{ + test_format_string(); + test_outputs<char>(); + test_outputs<wchar_t>(); + test_nested(); + test_padding(); +} diff --git a/libstdc++-v3/testsuite/std/memory/indirect/copy.cc b/libstdc++-v3/testsuite/std/memory/indirect/copy.cc new file mode 100644 index 0000000..0ac6e92 --- /dev/null +++ b/libstdc++-v3/testsuite/std/memory/indirect/copy.cc @@ -0,0 +1,121 @@ +// { dg-do run { target c++26 } } + +#include <memory> +#include <scoped_allocator> +#include <utility> +#include <vector> + +#include <testsuite_hooks.h> +#include <testsuite_allocator.h> + +using __gnu_test::tracker_allocator; +using Counter = __gnu_test::tracker_allocator_counter; +using Vector = std::vector<int>; +using Indirect = std::indirect<Vector, tracker_allocator<Vector>>; +const Indirect src(std::in_place, {1, 2, 3}); + +constexpr void +test_ctor() +{ + Counter::reset(); + Indirect i1(src); + VERIFY( *i1 == *src ); + VERIFY( &*i1 != &*src ); + VERIFY( Counter::get_allocation_count() == sizeof(Vector) ); + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 1 ); + VERIFY( Counter::get_destruct_count() == 0 ); + + Counter::reset(); + Indirect i2(std::allocator_arg, {}, src); + VERIFY( *i2 == *src ); + VERIFY( &*i2 != &*src ); + VERIFY( Counter::get_allocation_count() == sizeof(Vector) ); + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 1 ); + VERIFY( Counter::get_destruct_count() == 0 ); +} + +constexpr void +test_assign() +{ + Indirect i1; + Counter::reset(); + + i1 = src; + VERIFY( *i1 == *src ); + VERIFY( &*i1 != &*src ); + VERIFY( Counter::get_allocation_count() == 0 ); + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 0 ); + VERIFY( Counter::get_destruct_count() == 0 ); + + auto(std::move(i1)); + Counter::reset(); + + i1 = src; + VERIFY( *i1 == *src ); + VERIFY( &*i1 != &*src ); + VERIFY( Counter::get_allocation_count() == sizeof(Vector) ); + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 1 ); + VERIFY( Counter::get_destruct_count() == 0 ); +} + +constexpr void +test_valueless() +{ + Indirect e; + auto(std::move(e)); + VERIFY( e.valueless_after_move() ); + + Counter::reset(); + Indirect i1(e); + VERIFY( i1.valueless_after_move() ); + VERIFY( Counter::get_allocation_count() == 0 ); + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 0 ); + VERIFY( Counter::get_destruct_count() == 0 ); + + Indirect i2(std::allocator_arg, {}, e); + VERIFY( i2.valueless_after_move() ); + VERIFY( Counter::get_allocation_count() == 0 ); + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 0 ); + VERIFY( Counter::get_destruct_count() == 0 ); + + Indirect i3(src); + Counter::reset(); + i3 = e; + VERIFY( i3.valueless_after_move() ); + VERIFY( Counter::get_allocation_count() == 0 ); + VERIFY( Counter::get_deallocation_count() == sizeof(Vector) ); + VERIFY( Counter::get_construct_count() == 0 ); + VERIFY( Counter::get_destruct_count() == 1 ); + + Counter::reset(); + i3 = e; + VERIFY( i3.valueless_after_move() ); + VERIFY( Counter::get_allocation_count() == 0 ); + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 0 ); + VERIFY( Counter::get_destruct_count() == 0 ); +} + +constexpr void +test_all() +{ + test_ctor(); + test_assign(); + test_valueless(); +} + +int main() +{ + test_all(); + + static_assert([] { + test_all(); + return true; + }); +} diff --git a/libstdc++-v3/testsuite/std/memory/indirect/copy_alloc.cc b/libstdc++-v3/testsuite/std/memory/indirect/copy_alloc.cc new file mode 100644 index 0000000..d5865b9 --- /dev/null +++ b/libstdc++-v3/testsuite/std/memory/indirect/copy_alloc.cc @@ -0,0 +1,228 @@ +// { dg-do run { target c++26 } } + +#include <memory> +#include <scoped_allocator> +#include <utility> +#include <vector> + +#include <testsuite_hooks.h> +#include <testsuite_allocator.h> + +using __gnu_test::propagating_allocator; +using __gnu_test::tracker_allocator; +using Counter = __gnu_test::tracker_allocator_counter; + +template<bool Propagate> +constexpr void +test_ctor() +{ + using PropAlloc = propagating_allocator<int, Propagate>; + using Vector = std::vector<int, PropAlloc>; + using ScopedAlloc = std::scoped_allocator_adaptor< + propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>, + PropAlloc>; + using Indirect = std::indirect<Vector, ScopedAlloc>; + + const Indirect src(std::allocator_arg, ScopedAlloc{11, 22}, + std::in_place, {1, 2, 3}); + + Counter::reset(); + Indirect i1(src); + VERIFY( *i1 == *src ); + VERIFY( &*i1 != &*src ); + if (Propagate) + { + VERIFY( i1->get_allocator().get_personality() == 22 ); + VERIFY( i1.get_allocator().get_personality() == 11 ); + } + else + { + VERIFY( i1->get_allocator().get_personality() == 0 ); + VERIFY( i1.get_allocator().get_personality() == 0 ); + } + VERIFY( Counter::get_allocation_count() == sizeof(Vector) ); + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 1 ); + VERIFY( Counter::get_destruct_count() == 0 ); + + + Counter::reset(); + Indirect i2(std::allocator_arg, ScopedAlloc{33, 44}, src); + VERIFY( *i2 == *src ); + VERIFY( &*i2 != &*src ); + VERIFY( i2->get_allocator().get_personality() == 44 ); + VERIFY( i2.get_allocator().get_personality() == 33 ); + VERIFY( Counter::get_allocation_count() == sizeof(Vector) ); + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 1 ); + VERIFY( Counter::get_destruct_count() == 0 ); +} + +template<bool Propagate> +constexpr void +test_assign() +{ + using PropAlloc = propagating_allocator<int, Propagate>; + using Vector = std::vector<int, PropAlloc>; + using ScopedAlloc = std::scoped_allocator_adaptor< + propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>, + PropAlloc>; + using Indirect = std::indirect<Vector, ScopedAlloc>; + + const Indirect src(std::allocator_arg, ScopedAlloc{11, 22}, + std::in_place, {1, 2, 3}); + + Indirect i1(std::allocator_arg, ScopedAlloc{11, 22}); + Counter::reset(); + + i1 = src; + VERIFY( *i1 == *src ); + VERIFY( &*i1 != &*src ); + VERIFY( i1->get_allocator().get_personality() == 22 ); + VERIFY( i1.get_allocator().get_personality() == 11 ); + VERIFY( Counter::get_allocation_count() == 0 ); + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 0 ); + VERIFY( Counter::get_destruct_count() == 0 ); + + Indirect i2(std::allocator_arg, ScopedAlloc{33, 44}); + Counter::reset(); + + i2 = src; + VERIFY( *i2 == *src ); + VERIFY( &*i2 != &*src ); + if (Propagate) + { + VERIFY( i2->get_allocator().get_personality() == 22 ); + VERIFY( i2.get_allocator().get_personality() == 11 ); + } + else + { + VERIFY( i2->get_allocator().get_personality() == 44 ); + VERIFY( i2.get_allocator().get_personality() == 33 ); + } + VERIFY( Counter::get_allocation_count() == sizeof(Vector) ); + VERIFY( Counter::get_deallocation_count() == sizeof(Vector) ); + VERIFY( Counter::get_construct_count() == 1 ); + VERIFY( Counter::get_destruct_count() == 1 ); + + Indirect i3(std::allocator_arg, ScopedAlloc{11, 22}); + auto(std::move(i3)); + Counter::reset(); + + i3 = src; + VERIFY( *i3 == *src ); + VERIFY( &*i3 != &*src ); + VERIFY( i3->get_allocator().get_personality() == 22 ); + VERIFY( i3.get_allocator().get_personality() == 11 ); + VERIFY( Counter::get_allocation_count() == sizeof(Vector) ); + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 1 ); + VERIFY( Counter::get_destruct_count() == 0 ); + + Indirect i4(std::allocator_arg, ScopedAlloc{33, 44}); + auto(std::move(i4)); + Counter::reset(); + + i4 = src; + VERIFY( *i4 == *src ); + VERIFY( &*i4 != &*src ); + if (Propagate) + { + VERIFY( i4->get_allocator().get_personality() == 22 ); + VERIFY( i4.get_allocator().get_personality() == 11 ); + } + else + { + VERIFY( i4->get_allocator().get_personality() == 44 ); + VERIFY( i4.get_allocator().get_personality() == 33 ); + } + VERIFY( Counter::get_allocation_count() == sizeof(Vector) ); + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 1 ); + VERIFY( Counter::get_destruct_count() == 0 ); +} + +template<bool Propagate> +constexpr void +test_valueless() +{ + using PropAlloc = propagating_allocator<int, Propagate>; + using Vector = std::vector<int, PropAlloc>; + using ScopedAlloc = std::scoped_allocator_adaptor< + propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>, + PropAlloc>; + using Indirect = std::indirect<Vector, ScopedAlloc>; + + Indirect e(std::allocator_arg, ScopedAlloc{11, 22}); + auto(std::move(e)); + VERIFY( e.valueless_after_move() ); + + Counter::reset(); + Indirect i1(e); + VERIFY( i1.valueless_after_move() ); + if (Propagate) + VERIFY( i1.get_allocator().get_personality() == 11 ); + else + VERIFY( i1.get_allocator().get_personality() == 0 ); + VERIFY( Counter::get_allocation_count() == 0 ); + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 0 ); + VERIFY( Counter::get_destruct_count() == 0 ); + + Counter::reset(); + Indirect i2(std::allocator_arg, ScopedAlloc{33, 44}, e); + VERIFY( i2.valueless_after_move() ); + VERIFY( i2.get_allocator().get_personality() == 33 ); + VERIFY( Counter::get_allocation_count() == 0 ); + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 0 ); + VERIFY( Counter::get_destruct_count() == 0 ); + + Indirect i3(std::allocator_arg, ScopedAlloc{33, 44}); + Counter::reset(); + + i3 = e; + VERIFY( i3.valueless_after_move() ); + if (Propagate) + VERIFY( i3.get_allocator().get_personality() == 11 ); + else + VERIFY( i3.get_allocator().get_personality() == 33 ); + VERIFY( Counter::get_allocation_count() == 0 ); + VERIFY( Counter::get_deallocation_count() == sizeof(Vector) ); + VERIFY( Counter::get_construct_count() == 0 ); + VERIFY( Counter::get_destruct_count() == 1 ); + + Counter::reset(); + i2 = e; + VERIFY( i2.valueless_after_move() ); + if (Propagate) + VERIFY( i2.get_allocator().get_personality() == 11 ); + else + VERIFY( i2.get_allocator().get_personality() == 33 ); + VERIFY( Counter::get_allocation_count() == 0 ); + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 0 ); + VERIFY( Counter::get_destruct_count() == 0 ); +} + +template<bool Propagate> +constexpr void +test_all() +{ + test_ctor<Propagate>(); + test_assign<Propagate>(); + test_valueless<Propagate>(); +} + +int main() +{ + test_all<true>(); + test_all<false>(); + + static_assert([] { + test_all<true>(); + test_all<false>(); + return true; + }); +} diff --git a/libstdc++-v3/testsuite/std/memory/indirect/ctor.cc b/libstdc++-v3/testsuite/std/memory/indirect/ctor.cc new file mode 100644 index 0000000..124874d --- /dev/null +++ b/libstdc++-v3/testsuite/std/memory/indirect/ctor.cc @@ -0,0 +1,204 @@ +// { dg-do run { target c++26 } } + +#include <memory> +#include <scoped_allocator> +#include <utility> +#include <vector> + +#ifndef __cpp_lib_indirect +# error __cpp_lib_indirect feature test macro missing in <memory> +#elif __cpp_lib_indirect != 202502 +# error __cpp_lib_indirect feature test macro has wrong value in <memory> +#endif + +#include <testsuite_hooks.h> +#include <testsuite_allocator.h> + +using __gnu_test::uneq_allocator; +using UneqAlloc = uneq_allocator<int>; +using ScopedAlloc = std::scoped_allocator_adaptor< + uneq_allocator<std::vector<int, UneqAlloc>>, + UneqAlloc>; + +struct Obj +{ + int i; + char c[2]; +}; + +constexpr void +test_deduction_guides() +{ + const Obj o{}; + std::indirect i1(o); + static_assert(std::is_same_v<decltype(i1), std::indirect<Obj>>); + + using Alloc = __gnu_test::SimpleAllocator<Obj>; + Alloc a; + std::indirect i2(std::allocator_arg, a, o); + static_assert(std::is_same_v<decltype(i2), std::indirect<Obj, Alloc>>); +} + +constexpr void +test_default_ctor() +{ + using __gnu_test::default_init_allocator; + + std::indirect<Obj, default_init_allocator<Obj>> i1; + default_init_allocator<int> a{}; + + // The contained object and the allocator should be value-initialized. + VERIFY( i1->i == 0 ); + VERIFY( i1->c[0] == 0 ); + VERIFY( i1->c[1] == 0 ); + VERIFY( i1.get_allocator() == a ); + + a.state = 5; + // Allocator-extended default constructor: + std::indirect<Obj, default_init_allocator<Obj>> i2(std::allocator_arg, a); + VERIFY( i2.get_allocator() == a ); + + // Object is constructed using allocator-aware constructor. + std::indirect<std::vector<int, UneqAlloc>, ScopedAlloc> + i3(std::allocator_arg, ScopedAlloc(11, 22)); + VERIFY( i3->empty() ); + VERIFY( i3->get_allocator().get_personality() == 22 ); + VERIFY( i3.get_allocator().get_personality() == 11 ); +} + +constexpr void +test_forwarding_ctor() +{ + Obj obj{1, {'2', '3'}}; + auto verify = [](std::indirect<Obj> const& i) + { + VERIFY( i->i == 1 ); + VERIFY( i->c[0] == '2' ); + VERIFY( i->c[1] == '3' ); + }; + + std::indirect<Obj> i1(std::as_const(obj)); + verify(i1); + std::indirect<Obj> i2(std::move(std::as_const(obj))); + verify(i2); + std::indirect<Obj> i3(obj); + verify(i3); + std::indirect<Obj> i4(std::move(obj)); + verify(i4); + + std::indirect<Obj> i5({1, {'2', '3'}}); + verify(i5); + + // Aggregate parens init + std::indirect<Obj> i6(7); + VERIFY( i6->i == 7 ); + + std::vector<int, UneqAlloc> v{1, 2, 3, 4, 5}; + // Object is constructed using allocator-aware constructor. + std::indirect<std::vector<int, UneqAlloc>, ScopedAlloc> + i7(std::allocator_arg, ScopedAlloc(11, 22), v); + VERIFY( i7->size() == 5 ); + VERIFY( v.size() == 5 ); + VERIFY( i7->get_allocator().get_personality() == 22 ); + VERIFY( i7.get_allocator().get_personality() == 11 ); + + std::indirect<std::vector<int, UneqAlloc>, ScopedAlloc> + i8(std::allocator_arg, ScopedAlloc(11, 22), std::move(v)); + VERIFY( i8->size() == 5 ); + VERIFY( v.size() == 0 ); + VERIFY( i8->get_allocator().get_personality() == 22 ); + VERIFY( i8.get_allocator().get_personality() == 11 ); +} + +constexpr void +test_inplace_ctor() +{ + std::indirect<Obj> i1(std::in_place); + VERIFY( i1->i == 0 ); + VERIFY( i1->c[0] == 0 ); + VERIFY( i1->c[1] == 0 ); + + std::indirect<Obj> i2(std::in_place, 10); + VERIFY( i2->i == 10 ); + VERIFY( i2->c[0] == 0 ); + VERIFY( i2->c[1] == 0 ); + + std::indirect<Obj, uneq_allocator<Obj>> + i3(std::allocator_arg, 42, std::in_place); + VERIFY( i3->i == 0 ); + VERIFY( i3->c[0] == 0 ); + VERIFY( i3->c[1] == 0 ); + VERIFY( i3.get_allocator().get_personality() == 42 ); + + std::indirect<Obj, uneq_allocator<Obj>> + i4(std::allocator_arg, 42, std::in_place, 10); + VERIFY( i4->i == 10 ); + VERIFY( i4->c[0] == 0 ); + VERIFY( i4->c[1] == 0 ); + VERIFY( i4.get_allocator().get_personality() == 42 ); + + std::indirect<std::vector<int>> i5(std::in_place); + VERIFY( i5->size() == 0 ); + + std::indirect<std::vector<int>> i6(std::in_place, 5, 13); + VERIFY( i6->size() == 5 ); + VERIFY( i6->at(0) == 13 ); + + std::indirect<std::vector<int>> i7(std::in_place, {1, 2, 3, 4}); + VERIFY( i7->size() == 4 ); + VERIFY( i7->at(2) == 3 ); + + std::indirect<std::vector<int, UneqAlloc>> + i8(std::in_place, UneqAlloc{42}); + VERIFY( i8->size() == 0 ); + VERIFY( i8->get_allocator().get_personality() == 42 ); + + std::indirect<std::vector<int, UneqAlloc>> + i9(std::in_place, 5, 13, UneqAlloc{42}); + VERIFY( i9->size() == 5 ); + VERIFY( i9->at(0) == 13 ); + VERIFY( i9->get_allocator().get_personality() == 42 ); + + std::indirect<std::vector<int, UneqAlloc>> + i10(std::in_place, {1, 2, 3, 4}, UneqAlloc{42}); + VERIFY( i10->size() == 4 ); + VERIFY( i10->at(2) == 3 ); + VERIFY( i10->get_allocator().get_personality() == 42 ); + + std::indirect<std::vector<int, UneqAlloc>, ScopedAlloc> + i14(std::allocator_arg, ScopedAlloc(11, 22), + std::in_place); + VERIFY( i14->size() == 0 ); + VERIFY( i14->get_allocator().get_personality() == 22 ); + VERIFY( i14.get_allocator().get_personality() == 11 ); + + std::indirect<std::vector<int, UneqAlloc>, ScopedAlloc> + i15(std::allocator_arg, ScopedAlloc(11, 22), + std::in_place, 5, 13); + VERIFY( i15->size() == 5 ); + VERIFY( i15->at(0) == 13 ); + VERIFY( i15->get_allocator().get_personality() == 22 ); + VERIFY( i15.get_allocator().get_personality() == 11 ); + + std::indirect<std::vector<int, UneqAlloc>, ScopedAlloc> + i16(std::allocator_arg, ScopedAlloc(11, 22), + std::in_place, {1, 2, 3, 4}); + VERIFY( i16->size() == 4 ); + VERIFY( i16->at(2) == 3 ); + VERIFY( i16->get_allocator().get_personality() == 22 ); + VERIFY( i16.get_allocator().get_personality() == 11 ); +} + +int main() +{ + test_default_ctor(); + test_forwarding_ctor(); + test_inplace_ctor(); + + static_assert([] { + test_default_ctor(); + test_forwarding_ctor(); + test_inplace_ctor(); + return true; + }); +} diff --git a/libstdc++-v3/testsuite/std/memory/indirect/incomplete.cc b/libstdc++-v3/testsuite/std/memory/indirect/incomplete.cc new file mode 100644 index 0000000..1faf13d --- /dev/null +++ b/libstdc++-v3/testsuite/std/memory/indirect/incomplete.cc @@ -0,0 +1,38 @@ +// { dg-do compile { target c++26 } } + +#include <memory> + +struct Incomplete; +bool operator==(const Incomplete&, const Incomplete&); +std::strong_ordering operator<=>(const Incomplete&, const Incomplete&); + +template<> +struct std::hash<Incomplete> +{ + static std::size_t operator()(const Incomplete& c); +}; + +std::indirect<Incomplete>* +test_move(std::indirect<Incomplete>& i1, std::indirect<Incomplete>& i2) +{ + i2.swap(i2); + return new std::indirect<Incomplete>(std::move(i1)); +} + +void +test_relops(std::indirect<Incomplete> const& i1, Incomplete const& o) +{ + void(i1 == i1); + void(i1 < i1); + void(i1 >= i1); + + void(i1 != o); + void(i1 < o); +} + +void +test_hash(std::indirect<Incomplete> const& i1) +{ + std::hash<std::indirect<Incomplete>> h; + h(i1); +} diff --git a/libstdc++-v3/testsuite/std/memory/indirect/invalid_neg.cc b/libstdc++-v3/testsuite/std/memory/indirect/invalid_neg.cc new file mode 100644 index 0000000..82e7e84 --- /dev/null +++ b/libstdc++-v3/testsuite/std/memory/indirect/invalid_neg.cc @@ -0,0 +1,28 @@ +// { dg-do compile { target c++26 } } + +#include <memory> + +// In every specialization indirect<T, Allocator>, if the type +// allocator_traits<Allocator>::value_type is not the same type as T, +// the program is ill-formed. +using T1 = std::indirect<int, std::allocator<long>>::value_type; // { dg-error "here" } + +// A program that instantiates the definition of the template +// indirect<T, Allocator> with a type for the T parameter that is +// a non-object type, an array type, in_place_t, +// a specialization of in_place_type_t, or a cv-qualified type is ill-formed. + +using T2 = std::indirect<int&>::value_type; // { dg-error "here" } + +using T3 = std::indirect<int[1]>::value_type; // { dg-error "here" } + +using T4 = std::indirect<std::in_place_t>::value_type; // { dg-error "here" } + +using T5 = std::indirect<std::in_place_type_t<int>>::value_type; // { dg-error "here" } + +using T6 = std::indirect<const int>::value_type; // { dg-error "here" } + +using T7 = std::indirect<volatile int>::value_type; // { dg-error "here" } + +// { dg-error "static assertion failed" "" { target *-*-* } 0 } +// { dg-prune-output "forming pointer to reference" } diff --git a/libstdc++-v3/testsuite/std/memory/indirect/move.cc b/libstdc++-v3/testsuite/std/memory/indirect/move.cc new file mode 100644 index 0000000..6e87c60 --- /dev/null +++ b/libstdc++-v3/testsuite/std/memory/indirect/move.cc @@ -0,0 +1,144 @@ +// { dg-do run { target c++26 } } + +#include <memory> +#include <scoped_allocator> +#include <utility> +#include <vector> +#include <optional> + +#include <testsuite_hooks.h> +#include <testsuite_allocator.h> + +using __gnu_test::tracker_allocator; +using Counter = __gnu_test::tracker_allocator_counter; +using Vector = std::vector<int>; +using Indirect = std::indirect<Vector, tracker_allocator<Vector>>; +const Indirect val(std::in_place, {1, 2, 3}); + +constexpr void +verifyNoAllocations() +{ + VERIFY( Counter::get_allocation_count() == 0 ); + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 0 ); + VERIFY( Counter::get_destruct_count() == 0 ); +} + +constexpr void +test_ctor() +{ + std::optional<Indirect> src; + auto make = [&src] -> Indirect&& { + src.emplace(val); + Counter::reset(); + return std::move(*src); + }; + + Indirect i1(make()); + VERIFY( src->valueless_after_move() ); + VERIFY( *i1 == *val ); + verifyNoAllocations(); + + Indirect i2(std::allocator_arg, {}, make()); + VERIFY( src->valueless_after_move() ); + VERIFY( *i2 == *val ); + verifyNoAllocations(); +} + +constexpr void +test_assign() +{ + std::optional<Indirect> src; + auto make = [&src] -> Indirect&& { + src.emplace(val); + Counter::reset(); + return std::move(*src); + }; + + Indirect i1; + + i1 = make(); + VERIFY( src->valueless_after_move() ); + VERIFY( *i1 == *val ); + VERIFY( Counter::get_allocation_count() == 0 ); + VERIFY( Counter::get_deallocation_count() == sizeof(Vector) ); + VERIFY( Counter::get_construct_count() == 0 ); + VERIFY( Counter::get_destruct_count() == 1 ); + + auto(std::move(i1)); + i1 = make(); + VERIFY( *i1 == *val ); + VERIFY( src->valueless_after_move() ); + verifyNoAllocations(); +} + +constexpr void +test_swap() +{ + const Indirect val1(std::in_place, {1, 2, 3}); + const Indirect val2(std::in_place, {2, 4, 6}); + + Indirect i1(val1); + Indirect i2(val2); + Counter::reset(); + i1.swap(i2); + VERIFY( *i2 == *val1 ); + VERIFY( *i1 == *val2 ); + verifyNoAllocations(); + + auto(std::move(i1)); + + Counter::reset(); + i1.swap(i2); + VERIFY( *i1 == *val1 ); + VERIFY( i2.valueless_after_move() ); + verifyNoAllocations(); +} + +constexpr void +test_valueless() +{ + auto e = [] { + Indirect res; + auto(std::move(res)); + Counter::reset(); + return res; + }; + + Indirect i1(e()); + VERIFY( i1.valueless_after_move() ); + verifyNoAllocations(); + + Indirect i2(std::allocator_arg, {}, e()); + VERIFY( i2.valueless_after_move() ); + verifyNoAllocations(); + + Indirect i3(val); + i3 = e(); + VERIFY( Counter::get_allocation_count() == 0 ); + VERIFY( Counter::get_deallocation_count() == sizeof(Vector) ); + VERIFY( Counter::get_construct_count() == 0 ); + VERIFY( Counter::get_destruct_count() == 1 ); + + i3 = e(); + verifyNoAllocations(); +} + +constexpr void +test_all() +{ + test_ctor(); + test_assign(); + test_swap(); + test_valueless(); +} + +int main() +{ + test_all(); + + static_assert([] { + test_all(); + return true; + }); +} diff --git a/libstdc++-v3/testsuite/std/memory/indirect/move_alloc.cc b/libstdc++-v3/testsuite/std/memory/indirect/move_alloc.cc new file mode 100644 index 0000000..cd6f90d --- /dev/null +++ b/libstdc++-v3/testsuite/std/memory/indirect/move_alloc.cc @@ -0,0 +1,296 @@ +// { dg-do run { target c++26 } } + +#include <memory> +#include <scoped_allocator> +#include <utility> +#include <vector> +#include <optional> + +#include <testsuite_hooks.h> +#include <testsuite_allocator.h> + +using __gnu_test::propagating_allocator; +using __gnu_test::tracker_allocator; +using Counter = __gnu_test::tracker_allocator_counter; + +constexpr void +verifyNoAllocations() +{ + VERIFY( Counter::get_allocation_count() == 0 ); + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 0 ); + VERIFY( Counter::get_destruct_count() == 0 ); +} + +template<bool Propagate> +constexpr void +test_ctor() +{ + using PropAlloc = propagating_allocator<int, Propagate>; + using Vector = std::vector<int, PropAlloc>; + using ScopedAlloc = std::scoped_allocator_adaptor< + propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>, + PropAlloc>; + using Indirect = std::indirect<Vector, ScopedAlloc>; + + const Indirect val(std::in_place, {1, 2, 3}); + std::optional<Indirect> src; + auto make = [&val, &src] -> Indirect&& { + src.emplace(std::allocator_arg, ScopedAlloc{11, 22}, val); + Counter::reset(); + return std::move(*src); + }; + + Indirect i1(make()); + VERIFY( src->valueless_after_move() ); + VERIFY( *i1 == *val ); + VERIFY( i1->get_allocator().get_personality() == 22 ); + VERIFY( i1.get_allocator().get_personality() == 11 ); + verifyNoAllocations(); + + Indirect i2(std::allocator_arg, ScopedAlloc{11, 22}, make()); + VERIFY( src->valueless_after_move() ); + VERIFY( *i2 == *val ); + VERIFY( i2->get_allocator().get_personality() == 22 ); + VERIFY( i2.get_allocator().get_personality() == 11 ); + verifyNoAllocations(); + + Indirect i3(std::allocator_arg, ScopedAlloc{33, 44}, make()); + // We move-from contained object + VERIFY( !src->valueless_after_move() ); + VERIFY( *i3 == *val ); + VERIFY( i3->get_allocator().get_personality() == 44 ); + VERIFY( i3.get_allocator().get_personality() == 33 ); + VERIFY( Counter::get_allocation_count() == sizeof(Vector) ); + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 1 ); + VERIFY( Counter::get_destruct_count() == 0 ); +} + +template<bool Propagate> +constexpr void +test_assign() +{ + using PropAlloc = propagating_allocator<int, Propagate>; + using Vector = std::vector<int, PropAlloc>; + using ScopedAlloc = std::scoped_allocator_adaptor< + propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>, + PropAlloc>; + using Indirect = std::indirect<Vector, ScopedAlloc>; + + const Indirect val(std::in_place, {1, 2, 3}); + std::optional<Indirect> src; + auto make = [&val, &src] -> Indirect&& { + src.emplace(std::allocator_arg, ScopedAlloc{11, 22}, val); + Counter::reset(); + return std::move(*src); + }; + + Indirect i1(std::allocator_arg, ScopedAlloc{11, 22}); + + i1 = make(); + VERIFY( src->valueless_after_move() ); + VERIFY( *i1 == *val ); + VERIFY( i1->get_allocator().get_personality() == 22 ); + VERIFY( i1.get_allocator().get_personality() == 11 ); + VERIFY( Counter::get_allocation_count() == 0 ); + VERIFY( Counter::get_deallocation_count() == sizeof(Vector) ); + VERIFY( Counter::get_construct_count() == 0 ); + VERIFY( Counter::get_destruct_count() == 1 ); + + Indirect i2(std::allocator_arg, ScopedAlloc{33, 44}); + + i2 = make(); + VERIFY( *i2 == *val ); + if (Propagate) + { + VERIFY( src->valueless_after_move() ); + VERIFY( i2->get_allocator().get_personality() == 22 ); + VERIFY( i2.get_allocator().get_personality() == 11 ); + VERIFY( Counter::get_allocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 0 ); + } + else + { + // We allocate new holder and move-from contained object + VERIFY( !src->valueless_after_move() ); + VERIFY( i2->get_allocator().get_personality() == 44 ); + VERIFY( i2.get_allocator().get_personality() == 33 ); + VERIFY( Counter::get_allocation_count() == sizeof(Vector) ); + VERIFY( Counter::get_construct_count() == 1 ); + } + VERIFY( Counter::get_deallocation_count() == sizeof(Vector) ); + VERIFY( Counter::get_destruct_count() == 1 ); + + Indirect i3(std::allocator_arg, ScopedAlloc{11, 22}); + auto(std::move(i3)); + + i3 = make(); + VERIFY( *i3 == *val ); + VERIFY( src->valueless_after_move() ); + VERIFY( i3->get_allocator().get_personality() == 22 ); + VERIFY( i3.get_allocator().get_personality() == 11 ); + verifyNoAllocations(); + + Indirect i4(std::allocator_arg, ScopedAlloc{33, 44}); + auto(std::move(i4)); + + i4 = make(); + VERIFY( *i4 == *val ); + if (Propagate) + { + VERIFY( src->valueless_after_move() ); + VERIFY( i4->get_allocator().get_personality() == 22 ); + VERIFY( i4.get_allocator().get_personality() == 11 ); + VERIFY( Counter::get_allocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 0 ); + } + else + { + // We allocate new holder and move-from contained object + VERIFY( !src->valueless_after_move() ); + VERIFY( i4->get_allocator().get_personality() == 44 ); + VERIFY( i4.get_allocator().get_personality() == 33 ); + VERIFY( Counter::get_allocation_count() == sizeof(Vector) ); + VERIFY( Counter::get_construct_count() == 1 ); + } + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_destruct_count() == 0 ); +} + +template<bool Propagate> +constexpr void +test_swap() +{ + using PropAlloc = propagating_allocator<int, Propagate>; + using Vector = std::vector<int, PropAlloc>; + using ScopedAlloc = std::scoped_allocator_adaptor< + propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>, + PropAlloc>; + using Indirect = std::indirect<Vector, ScopedAlloc>; + + const Indirect val1(std::in_place, {1, 2, 3}); + const Indirect val2(std::in_place, {2, 4, 6}); + + Indirect i1(std::allocator_arg, ScopedAlloc{11, 22}, val1); + Indirect i2(std::allocator_arg, ScopedAlloc{11, 22}, val2); + Counter::reset(); + i1.swap(i2); + VERIFY( *i2 == *val1 ); + VERIFY( *i1 == *val2 ); + verifyNoAllocations(); + + auto(std::move(i1)); + + Counter::reset(); + i1.swap(i2); + VERIFY( *i1 == *val1 ); + VERIFY( i2.valueless_after_move() ); + verifyNoAllocations(); + + if (!Propagate) + return; + + Indirect i3(std::allocator_arg, ScopedAlloc{33, 44}, val2); + Counter::reset(); + i1.swap(i3); + VERIFY( *i1 == *val2 ); + VERIFY( i1->get_allocator().get_personality() == 44 ); + VERIFY( i1.get_allocator().get_personality() == 33 ); + VERIFY( *i3 == *val1 ); + VERIFY( i3->get_allocator().get_personality() == 22 ); + VERIFY( i3.get_allocator().get_personality() == 11 ); + verifyNoAllocations(); + + i1.swap(i2); + VERIFY( i1.valueless_after_move() ); + VERIFY( i1.get_allocator().get_personality() == 11 ); + VERIFY( *i2 == *val2 ); + VERIFY( i2->get_allocator().get_personality() == 44 ); + VERIFY( i2.get_allocator().get_personality() == 33 ); + verifyNoAllocations(); +} + +template<bool Propagate> +constexpr void +test_valueless() +{ + using PropAlloc = propagating_allocator<int, Propagate>; + using Vector = std::vector<int, PropAlloc>; + using ScopedAlloc = std::scoped_allocator_adaptor< + propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>, + PropAlloc>; + using Indirect = std::indirect<Vector, ScopedAlloc>; + + auto e = [] { + Indirect res(std::allocator_arg, ScopedAlloc{11, 22}); + auto(std::move(res)); + Counter::reset(); + return res; + }; + + Indirect i1(e()); + VERIFY( i1.valueless_after_move() ); + VERIFY( i1.get_allocator().get_personality() == 11 ); + verifyNoAllocations(); + + Indirect i2(std::allocator_arg, ScopedAlloc{33, 44}, e()); + VERIFY( i2.valueless_after_move() ); + VERIFY( i2.get_allocator().get_personality() == 33 ); + verifyNoAllocations(); + + Indirect i3(std::allocator_arg, ScopedAlloc{33, 44}); + + i3 = e(); + VERIFY( i3.valueless_after_move() ); + if (Propagate) + VERIFY( i3.get_allocator().get_personality() == 11 ); + else + VERIFY( i3.get_allocator().get_personality() == 33 ); + VERIFY( Counter::get_allocation_count() == 0 ); + VERIFY( Counter::get_deallocation_count() == sizeof(Vector) ); + VERIFY( Counter::get_construct_count() == 0 ); + VERIFY( Counter::get_destruct_count() == 1 ); + + i2 = e(); + VERIFY( i2.valueless_after_move() ); + if (Propagate) + VERIFY( i2.get_allocator().get_personality() == 11 ); + else + VERIFY( i2.get_allocator().get_personality() == 33 ); + verifyNoAllocations(); + + i3.swap(i2); + VERIFY( i2.valueless_after_move() ); + VERIFY( i1.valueless_after_move() ); + verifyNoAllocations(); + + if (!Propagate) + return; + + Indirect i4(std::allocator_arg, ScopedAlloc{33, 44}, e()); + i4.swap(i1); + verifyNoAllocations(); +} + +template<bool Propagate> +constexpr void +test_all() +{ + test_ctor<Propagate>(); + test_assign<Propagate>(); + test_swap<Propagate>(); + test_valueless<Propagate>(); +} + +int main() +{ + test_all<true>(); + test_all<false>(); + + static_assert([] { + test_all<true>(); + test_all<false>(); + return true; + }); +} diff --git a/libstdc++-v3/testsuite/std/memory/indirect/relops.cc b/libstdc++-v3/testsuite/std/memory/indirect/relops.cc new file mode 100644 index 0000000..d77fef2 --- /dev/null +++ b/libstdc++-v3/testsuite/std/memory/indirect/relops.cc @@ -0,0 +1,82 @@ +// { dg-do run { target c++26 } } + +#include <memory> +#include <testsuite_hooks.h> + +struct Obj +{ + int i; + constexpr auto operator<=>(const Obj&) const = default; +}; + +template<> +struct std::hash<Obj> +{ + static size_t operator()(Obj const& obj) + { return std::hash<int>{}(obj.i); } +}; + +constexpr void +test_relops() +{ + std::indirect<Obj> i1; + VERIFY( i1 == i1 ); + VERIFY( i1 <= i1 ); + VERIFY( i1 >= i1 ); + + std::indirect<Obj> i2 = std::move(i1); // make i1 valueless + VERIFY( i1 == i1 ); + VERIFY( i2 == i2 ); + VERIFY( i2 != i1 ); + VERIFY( i1 < i2 ); + VERIFY( i2 >= i1 ); + + std::indirect<Obj> i3 = std::move(i2); // make i2 valueless + VERIFY( i2 == i1 ); + VERIFY( i2 >= i1 ); + VERIFY( i2 <= i1 ); + VERIFY( i3 > i2 ); +} + +constexpr void +test_comp_with_t() +{ + std::indirect<Obj> i1; + Obj o{2}; + VERIFY( i1 != o ); + VERIFY( i1 < o ); + + std::indirect<Obj> i2(Obj{2}); + VERIFY( i2 == o ); + VERIFY( i2 <= o ); + VERIFY( o <= i2 ); + + std::indirect<Obj> i3 = std::move(i2); // make i2 valueless + VERIFY( i2 != o ); + VERIFY( i2 < o ); +} + +void +test_hash() +{ + Obj o{5}; + std::indirect<Obj> i(o); + VERIFY( std::hash<std::indirect<Obj>>{}(i) + == std::hash<Obj>{}(o) ); + + auto(std::move(i)); // make i valueless + (void)std::hash<std::indirect<Obj>>{}(i); +} + +int main() +{ + test_relops(); + test_comp_with_t(); + test_hash(); + + static_assert([] { + test_relops(); + test_comp_with_t(); + return true; + }); +} diff --git a/libstdc++-v3/testsuite/std/memory/polymorphic/copy.cc b/libstdc++-v3/testsuite/std/memory/polymorphic/copy.cc new file mode 100644 index 0000000..bea05ac --- /dev/null +++ b/libstdc++-v3/testsuite/std/memory/polymorphic/copy.cc @@ -0,0 +1,157 @@ +// { dg-do run { target c++26 } } + +#include <memory> +#include <scoped_allocator> +#include <utility> +#include <vector> + +#include <testsuite_hooks.h> +#include <testsuite_allocator.h> + +struct Base { + friend constexpr + bool operator==(const Base& lhs, const Base& rhs) + { return lhs.eq(rhs); } + +private: + constexpr virtual bool + eq(const Base& other) const = 0; +}; + +struct Derived : Base +{ + constexpr Derived() + : x(0), y(0), z(0) + { } + + constexpr Derived(int a, int b, int c) + : x(a), y(b), z(c) + { } + +private: + constexpr bool + eq(const Base& other) const override + { + if (auto op = dynamic_cast<const Derived*>(&other)) + return this->x == op->x && this->y == op->y && this->z == op->z; + return false; + } + + int x; + int y; + int z; +}; + +using __gnu_test::tracker_allocator; +using Counter = __gnu_test::tracker_allocator_counter; +using Polymorhic = std::polymorphic<Base, tracker_allocator<Base>>; +const Polymorhic src(std::in_place_type<Derived>, 1, 2, 3); + +constexpr void +test_ctor() +{ + Counter::reset(); + Polymorhic i1(src); + VERIFY( *i1 == *src ); + VERIFY( &*i1 != &*src ); + VERIFY( Counter::get_allocation_count() >= sizeof(Derived) ); + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 2 ); + VERIFY( Counter::get_destruct_count() == 0 ); + + Counter::reset(); + Polymorhic i2(std::allocator_arg, {}, src); + VERIFY( *i2 == *src ); + VERIFY( &*i2 != &*src ); + VERIFY( Counter::get_allocation_count() >= sizeof(Derived) ); + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 2 ); + VERIFY( Counter::get_destruct_count() == 0 ); +} + +constexpr void +test_assign() +{ + Counter::reset(); + Polymorhic i1(std::in_place_type<Derived>); + const size_t holderSize = Counter::get_allocation_count(); + VERIFY( holderSize >= sizeof(Derived) ); + Counter::reset(); + + i1 = src; + VERIFY( *i1 == *src ); + VERIFY( &*i1 != &*src ); + VERIFY( Counter::get_allocation_count() == holderSize ); + VERIFY( Counter::get_deallocation_count() == holderSize ); + VERIFY( Counter::get_construct_count() == 2 ); + VERIFY( Counter::get_destruct_count() == 1 ); + + auto(std::move(i1)); + Counter::reset(); + + i1 = src; + VERIFY( *i1 == *src ); + VERIFY( &*i1 != &*src ); + VERIFY( Counter::get_allocation_count() == holderSize ); + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 2 ); + VERIFY( Counter::get_destruct_count() == 0 ); +} + +constexpr void +test_valueless() +{ + Polymorhic e(std::in_place_type<Derived>); + auto(std::move(e)); + VERIFY( e.valueless_after_move() ); + + Counter::reset(); + Polymorhic i1(e); + VERIFY( i1.valueless_after_move() ); + VERIFY( Counter::get_allocation_count() == 0 ); + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 0 ); + VERIFY( Counter::get_destruct_count() == 0 ); + + Polymorhic i2(std::allocator_arg, {}, e); + VERIFY( i2.valueless_after_move() ); + VERIFY( Counter::get_allocation_count() == 0 ); + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 0 ); + VERIFY( Counter::get_destruct_count() == 0 ); + + Polymorhic i3(src); + Counter::reset(); + i3 = e; + VERIFY( i3.valueless_after_move() ); + VERIFY( Counter::get_allocation_count() == 0 ); + VERIFY( Counter::get_deallocation_count() >= sizeof(Derived) ); + VERIFY( Counter::get_construct_count() == 0 ); + VERIFY( Counter::get_destruct_count() == 1 ); + + Counter::reset(); + i3 = e; + VERIFY( i3.valueless_after_move() ); + VERIFY( Counter::get_allocation_count() == 0 ); + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 0 ); + VERIFY( Counter::get_destruct_count() == 0 ); +} + +constexpr void +test_all() +{ + test_ctor(); + test_assign(); + test_valueless(); +} + +int main() +{ + test_all(); + + static_assert([] { + test_all(); + return true; + }); +} diff --git a/libstdc++-v3/testsuite/std/memory/polymorphic/copy_alloc.cc b/libstdc++-v3/testsuite/std/memory/polymorphic/copy_alloc.cc new file mode 100644 index 0000000..f41c32e --- /dev/null +++ b/libstdc++-v3/testsuite/std/memory/polymorphic/copy_alloc.cc @@ -0,0 +1,270 @@ +// { dg-do run { target c++26 } } + +#include <memory> +#include <scoped_allocator> +#include <utility> +#include <vector> + +#include <testsuite_hooks.h> +#include <testsuite_allocator.h> + +struct Base { + friend constexpr + bool operator==(const Base& lhs, const Base& rhs) + { return lhs.eq(rhs); } + + virtual constexpr int + get_alloc_personality() const + { return -1; } + +private: + constexpr virtual bool + eq(const Base& other) const = 0; +}; + +template<typename T, typename Allocator> +struct VecDerived : Base, std::vector<T, Allocator> +{ + using VecBase = std::vector<T, Allocator>; + + using VecBase::VecBase; + + constexpr int + get_alloc_personality() const override + { return this->get_allocator().get_personality(); } + +private: + + constexpr bool + eq(const Base& other) const override + { + if (auto op = dynamic_cast<const VecDerived*>(&other)) + return *static_cast<const VecBase*>(this) + == *static_cast<const VecBase*>(op); + return false; + } +}; + +using __gnu_test::propagating_allocator; +using __gnu_test::tracker_allocator; +using Counter = __gnu_test::tracker_allocator_counter; + +template<bool Propagate> +constexpr void +test_ctor() +{ + using PropAlloc = propagating_allocator<int, Propagate>; + using Vector = VecDerived<int, PropAlloc>; + using ScopedAlloc = std::scoped_allocator_adaptor< + propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>, + PropAlloc>; + using Polymorphic = std::polymorphic<Vector, ScopedAlloc>; + + const Polymorphic src(std::allocator_arg, ScopedAlloc{11, 22}, + std::in_place_type<Vector>, {1, 2, 3}); + + Counter::reset(); + Polymorphic i1(src); + VERIFY( *i1 == *src ); + VERIFY( &*i1 != &*src ); + if (Propagate) + { + VERIFY( i1->get_alloc_personality() == 22 ); + VERIFY( i1.get_allocator().get_personality() == 11 ); + } + else + { + VERIFY( i1->get_alloc_personality() == 0 ); + VERIFY( i1.get_allocator().get_personality() == 0 ); + } + VERIFY( Counter::get_allocation_count() >= sizeof(Vector) ); + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 2 ); + VERIFY( Counter::get_destruct_count() == 0 ); + + + Counter::reset(); + Polymorphic i2(std::allocator_arg, ScopedAlloc{33, 44}, src); + VERIFY( *i2 == *src ); + VERIFY( &*i2 != &*src ); + VERIFY( i2->get_alloc_personality() == 44 ); + VERIFY( i2.get_allocator().get_personality() == 33 ); + VERIFY( Counter::get_allocation_count() >= sizeof(Vector) ); + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 2 ); + VERIFY( Counter::get_destruct_count() == 0 ); +} + +template<bool Propagate> +constexpr void +test_assign() +{ + using PropAlloc = propagating_allocator<int, Propagate>; + using Vector = VecDerived<int, PropAlloc>; + using ScopedAlloc = std::scoped_allocator_adaptor< + propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>, + PropAlloc>; + using Polymorphic = std::polymorphic<Vector, ScopedAlloc>; + + const Polymorphic src(std::allocator_arg, ScopedAlloc{11, 22}, + std::in_place_type<Vector>, {1, 2, 3}); + + Counter::reset(); + Polymorphic i1(std::allocator_arg, ScopedAlloc{11, 22}, + std::in_place_type<Vector>); + const size_t holderSize = Counter::get_allocation_count(); + VERIFY( holderSize >= sizeof(Vector) ); + Counter::reset(); + + i1 = src; + VERIFY( *i1 == *src ); + VERIFY( &*i1 != &*src ); + VERIFY( i1->get_alloc_personality() == 22 ); + VERIFY( i1.get_allocator().get_personality() == 11 ); + VERIFY( Counter::get_allocation_count() == holderSize ); + VERIFY( Counter::get_deallocation_count() == holderSize ); + VERIFY( Counter::get_construct_count() == 2 ); + VERIFY( Counter::get_destruct_count() == 1 ); + + Polymorphic i2(std::allocator_arg, ScopedAlloc{33, 44}); + Counter::reset(); + + i2 = src; + VERIFY( *i2 == *src ); + VERIFY( &*i2 != &*src ); + if (Propagate) + { + VERIFY( i2->get_alloc_personality() == 22 ); + VERIFY( i2.get_allocator().get_personality() == 11 ); + } + else + { + VERIFY( i2->get_alloc_personality() == 44 ); + VERIFY( i2.get_allocator().get_personality() == 33 ); + } + VERIFY( Counter::get_allocation_count() == holderSize ); + VERIFY( Counter::get_deallocation_count() == holderSize ); + VERIFY( Counter::get_construct_count() == 2 ); + VERIFY( Counter::get_destruct_count() == 1 ); + + Polymorphic i3(std::allocator_arg, ScopedAlloc{11, 22}); + auto(std::move(i3)); + Counter::reset(); + + i3 = src; + VERIFY( *i3 == *src ); + VERIFY( &*i3 != &*src ); + VERIFY( i3->get_alloc_personality() == 22 ); + VERIFY( i3.get_allocator().get_personality() == 11 ); + VERIFY( Counter::get_allocation_count() == holderSize ); + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 2 ); + VERIFY( Counter::get_destruct_count() == 0 ); + + Polymorphic i4(std::allocator_arg, ScopedAlloc{33, 44}); + auto(std::move(i4)); + Counter::reset(); + + i4 = src; + VERIFY( *i4 == *src ); + VERIFY( &*i4 != &*src ); + if (Propagate) + { + VERIFY( i4->get_alloc_personality() == 22 ); + VERIFY( i4.get_allocator().get_personality() == 11 ); + } + else + { + VERIFY( i4->get_alloc_personality() == 44 ); + VERIFY( i4.get_allocator().get_personality() == 33 ); + } + VERIFY( Counter::get_allocation_count() == holderSize ); + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 2 ); + VERIFY( Counter::get_destruct_count() == 0 ); +} + +template<bool Propagate> +constexpr void +test_valueless() +{ + using PropAlloc = propagating_allocator<int, Propagate>; + using Vector = VecDerived<int, PropAlloc>; + using ScopedAlloc = std::scoped_allocator_adaptor< + propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>, + PropAlloc>; + using Polymorphic = std::polymorphic<Vector, ScopedAlloc>; + + Polymorphic e(std::allocator_arg, ScopedAlloc{11, 22}, + std::in_place_type<Vector>); + auto(std::move(e)); + VERIFY( e.valueless_after_move() ); + + Counter::reset(); + Polymorphic i1(e); + VERIFY( i1.valueless_after_move() ); + if (Propagate) + VERIFY( i1.get_allocator().get_personality() == 11 ); + else + VERIFY( i1.get_allocator().get_personality() == 0 ); + VERIFY( Counter::get_allocation_count() == 0 ); + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 0 ); + VERIFY( Counter::get_destruct_count() == 0 ); + + Counter::reset(); + Polymorphic i2(std::allocator_arg, ScopedAlloc{33, 44}, e); + VERIFY( i2.valueless_after_move() ); + VERIFY( i2.get_allocator().get_personality() == 33 ); + VERIFY( Counter::get_allocation_count() == 0 ); + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 0 ); + VERIFY( Counter::get_destruct_count() == 0 ); + + Polymorphic i3(std::allocator_arg, ScopedAlloc{33, 44}); + Counter::reset(); + + i3 = e; + VERIFY( i3.valueless_after_move() ); + if (Propagate) + VERIFY( i3.get_allocator().get_personality() == 11 ); + else + VERIFY( i3.get_allocator().get_personality() == 33 ); + VERIFY( Counter::get_allocation_count() == 0 ); + VERIFY( Counter::get_deallocation_count() >= sizeof(Vector) ); + VERIFY( Counter::get_construct_count() == 0 ); + VERIFY( Counter::get_destruct_count() == 1 ); + + Counter::reset(); + i2 = e; + VERIFY( i2.valueless_after_move() ); + if (Propagate) + VERIFY( i2.get_allocator().get_personality() == 11 ); + else + VERIFY( i2.get_allocator().get_personality() == 33 ); + VERIFY( Counter::get_allocation_count() == 0 ); + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 0 ); + VERIFY( Counter::get_destruct_count() == 0 ); +} + +template<bool Propagate> +constexpr void +test_all() +{ + test_ctor<Propagate>(); + test_assign<Propagate>(); + test_valueless<Propagate>(); +} + +int main() +{ + test_all<true>(); + test_all<false>(); + + static_assert([] { + test_all<true>(); + test_all<false>(); + return true; + }); +} diff --git a/libstdc++-v3/testsuite/std/memory/polymorphic/ctor.cc b/libstdc++-v3/testsuite/std/memory/polymorphic/ctor.cc new file mode 100644 index 0000000..bb4c947 --- /dev/null +++ b/libstdc++-v3/testsuite/std/memory/polymorphic/ctor.cc @@ -0,0 +1,190 @@ +// { dg-do run { target c++26 } } + +#include <memory> +#include <scoped_allocator> +#include <utility> +#include <vector> + +#ifndef __cpp_lib_polymorphic +# error __cpp_lib_polymorphic feature test macro missing in <memory> +#elif __cpp_lib_polymorphic != 202502 +# error __cpp_lib_polymorphic feature test macro has wrong value in <memory> +#endif + +#include <testsuite_hooks.h> +#include <testsuite_allocator.h> + +using __gnu_test::uneq_allocator; +using UneqAlloc = uneq_allocator<int>; +using ScopedAlloc = std::scoped_allocator_adaptor< + uneq_allocator<std::vector<int, UneqAlloc>>, + UneqAlloc>; + +struct Obj +{ + int i; + char c[2]; +}; + +constexpr void +test_default_ctor() +{ + using __gnu_test::default_init_allocator; + + std::polymorphic<Obj, default_init_allocator<Obj>> i1; + default_init_allocator<int> a{}; + + // The contained object and the allocator should be value-initialized. + VERIFY( i1->i == 0 ); + VERIFY( i1->c[0] == 0 ); + VERIFY( i1->c[1] == 0 ); + VERIFY( i1.get_allocator() == a ); + + a.state = 5; + // Allocator-extended default constructor: + std::polymorphic<Obj, default_init_allocator<Obj>> i2(std::allocator_arg, a); + VERIFY( i2.get_allocator() == a ); + + // Object is constructed using allocator-aware constructor. + std::polymorphic<std::vector<int, UneqAlloc>, ScopedAlloc> + i3(std::allocator_arg, ScopedAlloc(11, 22)); + VERIFY( i3->empty() ); + VERIFY( i3->get_allocator().get_personality() == 22 ); + VERIFY( i3.get_allocator().get_personality() == 11 ); +} + +constexpr void +test_forwarding_ctor() +{ + Obj obj{1, {'2', '3'}}; + auto verify = [](std::polymorphic<Obj> const& i) + { + VERIFY( i->i == 1 ); + VERIFY( i->c[0] == '2' ); + VERIFY( i->c[1] == '3' ); + }; + + std::polymorphic<Obj> i1(std::as_const(obj)); + verify(i1); + std::polymorphic<Obj> i2(std::move(std::as_const(obj))); + verify(i2); + std::polymorphic<Obj> i3(obj); + verify(i3); + std::polymorphic<Obj> i4(std::move(obj)); + verify(i4); + + std::polymorphic<Obj> i5({1, {'2', '3'}}); + verify(i5); + + std::vector<int, UneqAlloc> v{1, 2, 3, 4, 5}; + // Object is constructed using allocator-aware constructor. + std::polymorphic<std::vector<int, UneqAlloc>, ScopedAlloc> + i7(std::allocator_arg, ScopedAlloc(11, 22), v); + VERIFY( i7->size() == 5 ); + VERIFY( v.size() == 5 ); + VERIFY( i7->get_allocator().get_personality() == 22 ); + VERIFY( i7.get_allocator().get_personality() == 11 ); + + std::polymorphic<std::vector<int, UneqAlloc>, ScopedAlloc> + i8(std::allocator_arg, ScopedAlloc(11, 22), std::move(v)); + VERIFY( i8->size() == 5 ); + VERIFY( v.size() == 0 ); + VERIFY( i8->get_allocator().get_personality() == 22 ); + VERIFY( i8.get_allocator().get_personality() == 11 ); +} + +constexpr void +test_inplace_ctor() +{ + std::polymorphic<Obj> i1(std::in_place_type<Obj>); + VERIFY( i1->i == 0 ); + VERIFY( i1->c[0] == 0 ); + VERIFY( i1->c[1] == 0 ); + + std::polymorphic<Obj> i2(std::in_place_type<Obj>, 10); + VERIFY( i2->i == 10 ); + VERIFY( i2->c[0] == 0 ); + VERIFY( i2->c[1] == 0 ); + + std::polymorphic<Obj, uneq_allocator<Obj>> + i3(std::allocator_arg, 42, std::in_place_type<Obj>); + VERIFY( i3->i == 0 ); + VERIFY( i3->c[0] == 0 ); + VERIFY( i3->c[1] == 0 ); + VERIFY( i3.get_allocator().get_personality() == 42 ); + + std::polymorphic<Obj, uneq_allocator<Obj>> + i4(std::allocator_arg, 42, std::in_place_type<Obj>, 10); + VERIFY( i4->i == 10 ); + VERIFY( i4->c[0] == 0 ); + VERIFY( i4->c[1] == 0 ); + VERIFY( i4.get_allocator().get_personality() == 42 ); + + std::polymorphic<std::vector<int>> + i5(std::in_place_type<std::vector<int>>); + VERIFY( i5->size() == 0 ); + + std::polymorphic<std::vector<int>> + i6(std::in_place_type<std::vector<int>>, 5, 13); + VERIFY( i6->size() == 5 ); + VERIFY( i6->at(0) == 13 ); + + std::polymorphic<std::vector<int>> + i7(std::in_place_type<std::vector<int>>, {1, 2, 3, 4}); + VERIFY( i7->size() == 4 ); + VERIFY( i7->at(2) == 3 ); + + std::polymorphic<std::vector<int, UneqAlloc>> + i8(std::in_place_type<std::vector<int, UneqAlloc>>, UneqAlloc{42}); + VERIFY( i8->size() == 0 ); + VERIFY( i8->get_allocator().get_personality() == 42 ); + + std::polymorphic<std::vector<int, UneqAlloc>> + i9(std::in_place_type<std::vector<int, UneqAlloc>>, 5, 13, UneqAlloc{42}); + VERIFY( i9->size() == 5 ); + VERIFY( i9->at(0) == 13 ); + VERIFY( i9->get_allocator().get_personality() == 42 ); + + std::polymorphic<std::vector<int, UneqAlloc>> + i10(std::in_place_type<std::vector<int, UneqAlloc>>, {1, 2, 3, 4}, UneqAlloc{42}); + VERIFY( i10->size() == 4 ); + VERIFY( i10->at(2) == 3 ); + VERIFY( i10->get_allocator().get_personality() == 42 ); + + std::polymorphic<std::vector<int, UneqAlloc>, ScopedAlloc> + i14(std::allocator_arg, ScopedAlloc(11, 22), + std::in_place_type<std::vector<int, UneqAlloc>>); + VERIFY( i14->size() == 0 ); + VERIFY( i14->get_allocator().get_personality() == 22 ); + VERIFY( i14.get_allocator().get_personality() == 11 ); + + std::polymorphic<std::vector<int, UneqAlloc>, ScopedAlloc> + i15(std::allocator_arg, ScopedAlloc(11, 22), + std::in_place_type<std::vector<int, UneqAlloc>>, 5, 13); + VERIFY( i15->size() == 5 ); + VERIFY( i15->at(0) == 13 ); + VERIFY( i15->get_allocator().get_personality() == 22 ); + VERIFY( i15.get_allocator().get_personality() == 11 ); + + std::polymorphic<std::vector<int, UneqAlloc>, ScopedAlloc> + i16(std::allocator_arg, ScopedAlloc(11, 22), + std::in_place_type<std::vector<int, UneqAlloc>>, {1, 2, 3, 4}); + VERIFY( i16->size() == 4 ); + VERIFY( i16->at(2) == 3 ); + VERIFY( i16->get_allocator().get_personality() == 22 ); + VERIFY( i16.get_allocator().get_personality() == 11 ); +} + +int main() +{ + test_default_ctor(); + test_forwarding_ctor(); + test_inplace_ctor(); + + static_assert([] { + test_default_ctor(); + test_forwarding_ctor(); + test_inplace_ctor(); + return true; + }); +} diff --git a/libstdc++-v3/testsuite/std/memory/polymorphic/ctor_poly.cc b/libstdc++-v3/testsuite/std/memory/polymorphic/ctor_poly.cc new file mode 100644 index 0000000..03519a1 --- /dev/null +++ b/libstdc++-v3/testsuite/std/memory/polymorphic/ctor_poly.cc @@ -0,0 +1,220 @@ +// { dg-do run { target c++26 } } + +#include <memory> +#include <scoped_allocator> +#include <utility> +#include <vector> + +#ifndef __cpp_lib_polymorphic +# error __cpp_lib_polymorphic feature test macro missing in <memory> +#elif __cpp_lib_polymorphic != 202502 +# error __cpp_lib_polymorphic feature test macro has wrong value in <memory> +#endif + +#include <testsuite_hooks.h> +#include <testsuite_allocator.h> + +struct Base { + friend constexpr + bool operator==(const Base& lhs, const Base& rhs) + { return lhs.eq(rhs); } + + virtual constexpr int + get_personality() const + { return -1; } + +private: + constexpr virtual bool + eq(const Base& other) const + { return true; } +}; + +struct ObjDerived : Base +{ + constexpr ObjDerived() + : x(0), y(0), z(0) + { } + + constexpr ObjDerived(int a, int b, int c) + : x(a), y(b), z(c) + { } + + virtual constexpr int + get_personality() const + { return -2; } + +private: + constexpr bool + eq(const Base& other) const override + { + if (auto op = dynamic_cast<const ObjDerived*>(&other)) + return this->x == op->x && this->y == op->y && this->z == op->z; + return false; + } + + int x; + int y; + int z; +}; + +template<typename T, typename Allocator> +struct VecDerived : Base, std::vector<T, Allocator> +{ + using VecBase = std::vector<T, Allocator>; + + using VecBase::VecBase; + + constexpr int + get_personality() const override + { return this->get_allocator().get_personality(); } + +private: + + constexpr bool + eq(const Base& other) const override + { + if (auto op = dynamic_cast<const VecDerived*>(&other)) + return *static_cast<const VecBase*>(this) + == *static_cast<const VecBase*>(op); + return false; + } +}; + +using __gnu_test::uneq_allocator; +using UneqAlloc = uneq_allocator<int>; +using ScopedAlloc = std::scoped_allocator_adaptor< + uneq_allocator<Base>, + UneqAlloc>; + +constexpr void +test_default_ctor() +{ + using __gnu_test::default_init_allocator; + + std::polymorphic<Base, default_init_allocator<Base>> i1; + default_init_allocator<int> a{}; + + // The contained object and the allocator should be value-initialized. + VERIFY( *i1 == Base() ); + VERIFY( i1->get_personality() == -1 ); + VERIFY( i1.get_allocator() == a ); + + a.state = 5; + // Allocator-extended default constructor: + std::polymorphic<Base, default_init_allocator<Base>> i2(std::allocator_arg, a); + VERIFY( *i1 == Base() ); + VERIFY( i1->get_personality() == -1 ); +} + +constexpr void +test_forwarding_ctor() +{ + const ObjDerived src(1, 2, 3); + + std::polymorphic<Base> i1(src); + VERIFY( *i1 == src ); + VERIFY( i1->get_personality() == -2 ); + std::polymorphic<Base> i2(std::move(src)); + VERIFY( *i2 == src ); + VERIFY( i2->get_personality() == -2 ); + + ObjDerived obj = src; + std::polymorphic<Base> i3(obj); + VERIFY( *i3 == src ); + VERIFY( i3->get_personality() == -2 ); + std::polymorphic<Base> i4(std::move(obj)); + VERIFY( *i4 == src ); + VERIFY( i4->get_personality() == -2 ); + + const VecDerived<int, UneqAlloc> v{1, 2, 3, 4, 5}; + // Object is constructed using allocator-aware constructor. + std::polymorphic<Base, ScopedAlloc> + i5(std::allocator_arg, ScopedAlloc(11, 22), v); + VERIFY( *i5 == v ); + VERIFY( i5->get_personality() == 22 ); + VERIFY( i5.get_allocator().get_personality() == 11 ); + + std::polymorphic<Base, ScopedAlloc> + i6(std::allocator_arg, ScopedAlloc(11, 22), auto(v)); + VERIFY( *i6 == v ); + VERIFY( i6->get_personality() == 22 ); + VERIFY( i6.get_allocator().get_personality() == 11 ); +} + +constexpr void +test_inplace_ctor() +{ + std::polymorphic<Base> i1(std::in_place_type<ObjDerived>); + VERIFY( *i1 == ObjDerived() ); + VERIFY( i1->get_personality() == -2 ); + + std::polymorphic<Base> i2(std::in_place_type<ObjDerived>, 10, 20, 30); + VERIFY( *i2 == ObjDerived(10, 20, 30) ); + VERIFY( i2->get_personality() == -2 ); + + std::polymorphic<Base, uneq_allocator<Base>> + i3(std::allocator_arg, 42, std::in_place_type<ObjDerived>); + VERIFY( *i3 == ObjDerived() ); + VERIFY( i3->get_personality() == -2 ); + VERIFY( i3.get_allocator().get_personality() == 42 ); + + std::polymorphic<Base, uneq_allocator<Base>> + i4(std::allocator_arg, 42, std::in_place_type<ObjDerived>, 10, 20, 30); + VERIFY( *i4 == ObjDerived(10, 20, 30) ); + VERIFY( i4->get_personality() == -2 ); + VERIFY( i4.get_allocator().get_personality() == 42 ); + + const VecDerived<int, UneqAlloc> ze; + const VecDerived<int, UneqAlloc> fe(5, 13); + const VecDerived<int, UneqAlloc> il{1, 2, 3 ,4}; + + std::polymorphic<Base> + i5(std::in_place_type<VecDerived<int, UneqAlloc>>, UneqAlloc{42}); + VERIFY( *i5 == ze ); + VERIFY( i5->get_personality() == 42 ); + + std::polymorphic<Base> + i6(std::in_place_type<VecDerived<int, UneqAlloc>>, 5, 13, UneqAlloc{42}); + VERIFY( *i6 == fe ); + VERIFY( i6->get_personality() == 42 ); + + std::polymorphic<Base> + i7(std::in_place_type<VecDerived<int, UneqAlloc>>, {1, 2, 3, 4}, UneqAlloc{42}); + VERIFY( *i7 == il ); + VERIFY( i7->get_personality() == 42 ); + + std::polymorphic<Base, ScopedAlloc> + i8(std::allocator_arg, ScopedAlloc(11, 22), + std::in_place_type<VecDerived<int, UneqAlloc>>); + VERIFY( *i8 == ze ); + VERIFY( i8->get_personality() == 22 ); + VERIFY( i8.get_allocator().get_personality() == 11 ); + + std::polymorphic<Base, ScopedAlloc> + i9(std::allocator_arg, ScopedAlloc(11, 22), + std::in_place_type<VecDerived<int, UneqAlloc>>, 5, 13); + VERIFY( *i9 == fe ); + VERIFY( i9->get_personality() == 22 ); + VERIFY( i9.get_allocator().get_personality() == 11 ); + + std::polymorphic<Base, ScopedAlloc> + i10(std::allocator_arg, ScopedAlloc(11, 22), + std::in_place_type<VecDerived<int, UneqAlloc>>, {1, 2, 3, 4}); + VERIFY( *i10 == il ); + VERIFY( i10->get_personality() == 22 ); + VERIFY( i10.get_allocator().get_personality() == 11 ); +} + +int main() +{ + test_default_ctor(); + test_forwarding_ctor(); + test_inplace_ctor(); + + static_assert([] { + test_default_ctor(); + test_forwarding_ctor(); + test_inplace_ctor(); + return true; + }); +} diff --git a/libstdc++-v3/testsuite/std/memory/polymorphic/incomplete.cc b/libstdc++-v3/testsuite/std/memory/polymorphic/incomplete.cc new file mode 100644 index 0000000..e5dd78f --- /dev/null +++ b/libstdc++-v3/testsuite/std/memory/polymorphic/incomplete.cc @@ -0,0 +1,13 @@ +// { dg-do compile { target c++26 } } + +#include <memory> + +struct Incomplete; + +std::polymorphic<Incomplete>* +test_move(std::polymorphic<Incomplete>& i1, std::polymorphic<Incomplete>& i2) +{ + i1 = std::move(i2); + swap(i1, i2); + return new std::polymorphic<Incomplete>(std::move(i1)); +} diff --git a/libstdc++-v3/testsuite/std/memory/polymorphic/invalid_neg.cc b/libstdc++-v3/testsuite/std/memory/polymorphic/invalid_neg.cc new file mode 100644 index 0000000..a01af3f --- /dev/null +++ b/libstdc++-v3/testsuite/std/memory/polymorphic/invalid_neg.cc @@ -0,0 +1,28 @@ +// { dg-do compile { target c++26 } } + +#include <memory> + +// In every specialization polymorphic<T, Allocator>, if the type +// allocator_traits<Allocator>::value_type is not the same type as T, +// the program is ill-formed. +using T1 = std::polymorphic<int, std::allocator<long>>::value_type; // { dg-error "here" } + +// A program that instantiates the definition of the template +// polymorphic<T, Allocator> with a type for the T parameter that is +// a non-object type, an array type, in_place_t, +// a specialization of in_place_type_t, or a cv-qualified type is ill-formed. + +using T2 = std::polymorphic<int&>::value_type; // { dg-error "here" } + +using T3 = std::polymorphic<int[1]>::value_type; // { dg-error "here" } + +using T4 = std::polymorphic<std::in_place_t>::value_type; // { dg-error "here" } + +using T5 = std::polymorphic<std::in_place_type_t<int>>::value_type; // { dg-error "here" } + +using T6 = std::polymorphic<const int>::value_type; // { dg-error "here" } + +using T7 = std::polymorphic<volatile int>::value_type; // { dg-error "here" } + +// { dg-error "static assertion failed" "" { target *-*-* } 0 } +// { dg-prune-output "forming pointer to reference" } diff --git a/libstdc++-v3/testsuite/std/memory/polymorphic/move.cc b/libstdc++-v3/testsuite/std/memory/polymorphic/move.cc new file mode 100644 index 0000000..c802159 --- /dev/null +++ b/libstdc++-v3/testsuite/std/memory/polymorphic/move.cc @@ -0,0 +1,177 @@ +// { dg-do run { target c++26 } } + +#include <memory> +#include <scoped_allocator> +#include <utility> +#include <vector> +#include <optional> + +#include <testsuite_hooks.h> +#include <testsuite_allocator.h> + +struct Base { + friend constexpr + bool operator==(const Base& lhs, const Base& rhs) + { return lhs.eq(rhs); } + +private: + constexpr virtual bool + eq(const Base& other) const = 0; +}; + +struct Derived : Base +{ + constexpr Derived() + : x(0), y(0), z(0) + { } + + constexpr Derived(int a, int b, int c) + : x(a), y(b), z(c) + { } + +private: + constexpr bool + eq(const Base& other) const override + { + if (auto op = dynamic_cast<const Derived*>(&other)) + return this->x == op->x && this->y == op->y && this->z == op->z; + return false; + } + + int x; + int y; + int z; +}; + +using __gnu_test::tracker_allocator; +using Counter = __gnu_test::tracker_allocator_counter; +using Polymorphic = std::polymorphic<Base, tracker_allocator<Base>>; +const Polymorphic val(std::in_place_type<Derived>, 1, 2, 3); + +constexpr void +verifyNoAllocations() +{ + VERIFY( Counter::get_allocation_count() == 0 ); + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 0 ); + VERIFY( Counter::get_destruct_count() == 0 ); +} + +constexpr void +test_ctor() +{ + std::optional<Polymorphic> src; + auto make = [&src] -> Polymorphic&& { + src.emplace(val); + Counter::reset(); + return std::move(*src); + }; + + Polymorphic i1(make()); + VERIFY( src->valueless_after_move() ); + VERIFY( *i1 == *val ); + verifyNoAllocations(); + + Polymorphic i2(std::allocator_arg, {}, make()); + VERIFY( src->valueless_after_move() ); + VERIFY( *i2 == *val ); + verifyNoAllocations(); +} + +constexpr void +test_assign() +{ + std::optional<Polymorphic> src; + auto make = [&src] -> Polymorphic&& { + src.emplace(val); + Counter::reset(); + return std::move(*src); + }; + + Polymorphic i1(std::in_place_type<Derived>); + + i1 = make(); + VERIFY( src->valueless_after_move() ); + VERIFY( *i1 == *val ); + VERIFY( Counter::get_allocation_count() == 0 ); + VERIFY( Counter::get_deallocation_count() >= sizeof(Derived) ); + VERIFY( Counter::get_construct_count() == 0 ); + VERIFY( Counter::get_destruct_count() == 1 ); + + auto(std::move(i1)); + i1 = make(); + VERIFY( *i1 == *val ); + VERIFY( src->valueless_after_move() ); + verifyNoAllocations(); +} + +constexpr void +test_swap() +{ + const Polymorphic val1(std::in_place_type<Derived>, 1, 2, 3); + const Polymorphic val2(std::in_place_type<Derived>, 2, 4, 6); + + Polymorphic i1(val1); + Polymorphic i2(val2); + Counter::reset(); + i1.swap(i2); + VERIFY( *i2 == *val1 ); + VERIFY( *i1 == *val2 ); + verifyNoAllocations(); + + auto(std::move(i1)); + + Counter::reset(); + i1.swap(i2); + VERIFY( *i1 == *val1 ); + VERIFY( i2.valueless_after_move() ); + verifyNoAllocations(); +} + +constexpr void +test_valueless() +{ + auto e = [] { + Polymorphic res(std::in_place_type<Derived>); + auto(std::move(res)); + Counter::reset(); + return res; + }; + + Polymorphic i1(e()); + VERIFY( i1.valueless_after_move() ); + verifyNoAllocations(); + + Polymorphic i2(std::allocator_arg, {}, e()); + VERIFY( i2.valueless_after_move() ); + verifyNoAllocations(); + + Polymorphic i3(val); + i3 = e(); + VERIFY( Counter::get_allocation_count() == 0 ); + VERIFY( Counter::get_deallocation_count() >= sizeof(Derived) ); + VERIFY( Counter::get_construct_count() == 0 ); + VERIFY( Counter::get_destruct_count() == 1 ); + + i3 = e(); + verifyNoAllocations(); +} + +constexpr void +test_all() +{ + test_ctor(); + test_assign(); + test_swap(); + test_valueless(); +} + +int main() +{ + test_all(); + + static_assert([] { + test_all(); + return true; + }); +} diff --git a/libstdc++-v3/testsuite/std/memory/polymorphic/move_alloc.cc b/libstdc++-v3/testsuite/std/memory/polymorphic/move_alloc.cc new file mode 100644 index 0000000..09afedb --- /dev/null +++ b/libstdc++-v3/testsuite/std/memory/polymorphic/move_alloc.cc @@ -0,0 +1,339 @@ +// { dg-do run { target c++26 } } + +#include <memory> +#include <scoped_allocator> +#include <utility> +#include <vector> +#include <optional> + +#include <testsuite_hooks.h> +#include <testsuite_allocator.h> + +struct Base { + friend constexpr + bool operator==(const Base& lhs, const Base& rhs) + { return lhs.eq(rhs); } + + virtual constexpr int + get_alloc_personality() const + { return -1; } + +private: + constexpr virtual bool + eq(const Base& other) const = 0; +}; + +template<typename T, typename Allocator> +struct VecDerived : Base, std::vector<T, Allocator> +{ + using VecBase = std::vector<T, Allocator>; + + using VecBase::VecBase; + + constexpr int + get_alloc_personality() const override + { return this->get_allocator().get_personality(); } + +private: + + constexpr bool + eq(const Base& other) const override + { + if (auto op = dynamic_cast<const VecDerived*>(&other)) + return *static_cast<const VecBase*>(this) + == *static_cast<const VecBase*>(op); + return false; + } +}; + +using __gnu_test::propagating_allocator; +using __gnu_test::tracker_allocator; +using Counter = __gnu_test::tracker_allocator_counter; + +constexpr void +verifyNoAllocations() +{ + VERIFY( Counter::get_allocation_count() == 0 ); + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 0 ); + VERIFY( Counter::get_destruct_count() == 0 ); +} + +template<bool Propagate> +constexpr void +test_ctor() +{ + using PropAlloc = propagating_allocator<int, Propagate>; + using Vector = VecDerived<int, PropAlloc>; + using ScopedAlloc = std::scoped_allocator_adaptor< + propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>, + PropAlloc>; + using Polymorphic = std::polymorphic<Vector, ScopedAlloc>; + + const Polymorphic val(std::in_place_type<Vector>, {1, 2, 3}); + std::optional<Polymorphic> src; + auto make = [&val, &src] -> Polymorphic&& { + src.emplace(std::allocator_arg, ScopedAlloc{11, 22}, val); + Counter::reset(); + return std::move(*src); + }; + + Polymorphic i1(make()); + VERIFY( src->valueless_after_move() ); + VERIFY( *i1 == *val ); + VERIFY( i1->get_alloc_personality() == 22 ); + VERIFY( i1.get_allocator().get_personality() == 11 ); + verifyNoAllocations(); + + Polymorphic i2(std::allocator_arg, ScopedAlloc{11, 22}, make()); + VERIFY( src->valueless_after_move() ); + VERIFY( *i2 == *val ); + VERIFY( i2->get_alloc_personality() == 22 ); + VERIFY( i2.get_allocator().get_personality() == 11 ); + verifyNoAllocations(); + + Polymorphic i3(std::allocator_arg, ScopedAlloc{33, 44}, make()); + // We move-from contained object + VERIFY( !src->valueless_after_move() ); + VERIFY( *i3 == *val ); + VERIFY( i3->get_alloc_personality() == 44 ); + VERIFY( i3.get_allocator().get_personality() == 33 ); + VERIFY( Counter::get_allocation_count() >= sizeof(Vector) ); + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 2 ); + VERIFY( Counter::get_destruct_count() == 0 ); +} + +template<bool Propagate> +constexpr void +test_assign() +{ + using PropAlloc = propagating_allocator<int, Propagate>; + using Vector = VecDerived<int, PropAlloc>; + using ScopedAlloc = std::scoped_allocator_adaptor< + propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>, + PropAlloc>; + using Polymorphic = std::polymorphic<Vector, ScopedAlloc>; + + const Polymorphic val(std::in_place_type<Vector>, {1, 2, 3}); + std::optional<Polymorphic> src; + auto make = [&val, &src] -> Polymorphic&& { + src.emplace(std::allocator_arg, ScopedAlloc{11, 22}, val); + Counter::reset(); + return std::move(*src); + }; + + Counter::reset(); + Polymorphic i1(std::allocator_arg, ScopedAlloc{11, 22}); + const std::size_t holderSize = Counter::get_allocation_count(); + VERIFY( holderSize >= sizeof(Vector) ); + + i1 = make(); + VERIFY( src->valueless_after_move() ); + VERIFY( *i1 == *val ); + VERIFY( i1->get_alloc_personality() == 22 ); + VERIFY( i1.get_allocator().get_personality() == 11 ); + VERIFY( Counter::get_allocation_count() == 0 ); + VERIFY( Counter::get_deallocation_count() == holderSize ); + VERIFY( Counter::get_construct_count() == 0 ); + VERIFY( Counter::get_destruct_count() == 1 ); + + Polymorphic i2(std::allocator_arg, ScopedAlloc{33, 44}); + + i2 = make(); + VERIFY( *i2 == *val ); + if (Propagate) + { + VERIFY( src->valueless_after_move() ); + VERIFY( i2->get_alloc_personality() == 22 ); + VERIFY( i2.get_allocator().get_personality() == 11 ); + VERIFY( Counter::get_allocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 0 ); + } + else + { + // We allocate new holder and move-from contained object + VERIFY( !src->valueless_after_move() ); + VERIFY( i2->get_alloc_personality() == 44 ); + VERIFY( i2.get_allocator().get_personality() == 33 ); + VERIFY( Counter::get_allocation_count() == holderSize ); + VERIFY( Counter::get_construct_count() == 2 ); + } + VERIFY( Counter::get_deallocation_count() == holderSize ); + VERIFY( Counter::get_destruct_count() == 1 ); + + Polymorphic i3(std::allocator_arg, ScopedAlloc{11, 22}, + std::in_place_type<Vector>); + auto(std::move(i3)); + + i3 = make(); + VERIFY( *i3 == *val ); + VERIFY( src->valueless_after_move() ); + VERIFY( i3->get_alloc_personality() == 22 ); + VERIFY( i3.get_allocator().get_personality() == 11 ); + verifyNoAllocations(); + + Polymorphic i4(std::allocator_arg, ScopedAlloc{33, 44}, + std::in_place_type<Vector>); + auto(std::move(i4)); + + i4 = make(); + VERIFY( *i4 == *val ); + if (Propagate) + { + VERIFY( src->valueless_after_move() ); + VERIFY( i4->get_alloc_personality() == 22 ); + VERIFY( i4.get_allocator().get_personality() == 11 ); + VERIFY( Counter::get_allocation_count() == 0 ); + VERIFY( Counter::get_construct_count() == 0 ); + } + else + { + // We allocate new holder and move-from contained object + VERIFY( !src->valueless_after_move() ); + VERIFY( i4->get_alloc_personality() == 44 ); + VERIFY( i4.get_allocator().get_personality() == 33 ); + VERIFY( Counter::get_allocation_count() == holderSize ); + VERIFY( Counter::get_construct_count() == 2 ); + } + VERIFY( Counter::get_deallocation_count() == 0 ); + VERIFY( Counter::get_destruct_count() == 0 ); +} + +template<bool Propagate> +constexpr void +test_swap() +{ + using PropAlloc = propagating_allocator<int, Propagate>; + using Vector = VecDerived<int, PropAlloc>; + using ScopedAlloc = std::scoped_allocator_adaptor< + propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>, + PropAlloc>; + using Polymorphic = std::polymorphic<Vector, ScopedAlloc>; + + const Polymorphic val1(std::in_place_type<Vector>, {1, 2, 3}); + const Polymorphic val2(std::in_place_type<Vector>, {2, 4, 6}); + + Polymorphic i1(std::allocator_arg, ScopedAlloc{11, 22}, val1); + Polymorphic i2(std::allocator_arg, ScopedAlloc{11, 22}, val2); + Counter::reset(); + i1.swap(i2); + VERIFY( *i2 == *val1 ); + VERIFY( *i1 == *val2 ); + verifyNoAllocations(); + + auto(std::move(i1)); + + Counter::reset(); + i1.swap(i2); + VERIFY( *i1 == *val1 ); + VERIFY( i2.valueless_after_move() ); + verifyNoAllocations(); + + if (!Propagate) + return; + + Polymorphic i3(std::allocator_arg, ScopedAlloc{33, 44}, val2); + Counter::reset(); + i1.swap(i3); + VERIFY( *i1 == *val2 ); + VERIFY( i1->get_alloc_personality() == 44 ); + VERIFY( i1.get_allocator().get_personality() == 33 ); + VERIFY( *i3 == *val1 ); + VERIFY( i3->get_alloc_personality() == 22 ); + VERIFY( i3.get_allocator().get_personality() == 11 ); + verifyNoAllocations(); + + i1.swap(i2); + VERIFY( i1.valueless_after_move() ); + VERIFY( i1.get_allocator().get_personality() == 11 ); + VERIFY( *i2 == *val2 ); + VERIFY( i2->get_alloc_personality() == 44 ); + VERIFY( i2.get_allocator().get_personality() == 33 ); + verifyNoAllocations(); +} + +template<bool Propagate> +constexpr void +test_valueless() +{ + using PropAlloc = propagating_allocator<int, Propagate>; + using Vector = VecDerived<int, PropAlloc>; + using ScopedAlloc = std::scoped_allocator_adaptor< + propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>, + PropAlloc>; + using Polymorphic = std::polymorphic<Vector, ScopedAlloc>; + + auto e = [] { + Polymorphic res(std::allocator_arg, ScopedAlloc{11, 22}, + std::in_place_type<Vector>); + auto(std::move(res)); + Counter::reset(); + return res; + }; + + Polymorphic i1(e()); + VERIFY( i1.valueless_after_move() ); + VERIFY( i1.get_allocator().get_personality() == 11 ); + verifyNoAllocations(); + + Polymorphic i2(std::allocator_arg, ScopedAlloc{33, 44}, e()); + VERIFY( i2.valueless_after_move() ); + VERIFY( i2.get_allocator().get_personality() == 33 ); + verifyNoAllocations(); + + Polymorphic i3(std::allocator_arg, ScopedAlloc{33, 44}); + + i3 = e(); + VERIFY( i3.valueless_after_move() ); + if (Propagate) + VERIFY( i3.get_allocator().get_personality() == 11 ); + else + VERIFY( i3.get_allocator().get_personality() == 33 ); + VERIFY( Counter::get_allocation_count() == 0 ); + VERIFY( Counter::get_deallocation_count() >= sizeof(Vector) ); + VERIFY( Counter::get_construct_count() == 0 ); + VERIFY( Counter::get_destruct_count() == 1 ); + + i2 = e(); + VERIFY( i2.valueless_after_move() ); + if (Propagate) + VERIFY( i2.get_allocator().get_personality() == 11 ); + else + VERIFY( i2.get_allocator().get_personality() == 33 ); + verifyNoAllocations(); + + i3.swap(i2); + VERIFY( i2.valueless_after_move() ); + VERIFY( i1.valueless_after_move() ); + verifyNoAllocations(); + + if (!Propagate) + return; + + Polymorphic i4(std::allocator_arg, ScopedAlloc{33, 44}, e()); + i4.swap(i1); + verifyNoAllocations(); +} + +template<bool Propagate> +constexpr void +test_all() +{ + test_ctor<Propagate>(); + test_assign<Propagate>(); + test_swap<Propagate>(); + test_valueless<Propagate>(); +} + +int main() +{ + test_all<true>(); + test_all<false>(); + + static_assert([] { + test_all<true>(); + test_all<false>(); + return true; + }); +} diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc index 3f1f8eb..5ccf47d 100644 --- a/libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc @@ -69,10 +69,23 @@ test03() auto r2 = views::as_const(views::all(v)); } +void +test04() +{ + // PR libstdc++/115046 - meta-recursion with join_view and as_const_view + int x[3] = {1,2,3}; + auto v = x + | views::chunk(3) + | views::transform(views::as_const) + | views::join; + VERIFY( ranges::equal(v, x) ); +} + int main() { static_assert(test01()); static_assert(test02()); test03(); + test04(); } diff --git a/libstdc++-v3/testsuite/std/ranges/concat/1.cc b/libstdc++-v3/testsuite/std/ranges/concat/1.cc index 1672191..f78ed08 100644 --- a/libstdc++-v3/testsuite/std/ranges/concat/1.cc +++ b/libstdc++-v3/testsuite/std/ranges/concat/1.cc @@ -99,6 +99,18 @@ test04() using type = decltype(v); } +void +test05() +{ + // PR libstdc++/120934 - views::concat is ill-formed depending on argument order + auto v1 = views::single(1); + std::vector<int> vec = {2, 3}; + auto v2 = views::join(views::transform(vec, views::single)); + + static_assert( ranges::range<decltype(views::concat(v1, v2))> ); + static_assert( ranges::range<decltype(views::concat(v2, v1))> ); +} + int main() { @@ -107,4 +119,5 @@ main() test02(); test03(); test04(); + test05(); } diff --git a/libstdc++-v3/testsuite/std/ranges/iota/max_size_type.cc b/libstdc++-v3/testsuite/std/ranges/iota/max_size_type.cc index 3e6f954..4739d9e 100644 --- a/libstdc++-v3/testsuite/std/ranges/iota/max_size_type.cc +++ b/libstdc++-v3/testsuite/std/ranges/iota/max_size_type.cc @@ -400,6 +400,13 @@ static_assert(max_diff_t(max_size_t(1) << (numeric_limits<max_size_t>::digits-1)) == numeric_limits<max_diff_t>::min()); +// Verify that the types are structural types and can therefore be used +// as NTTP types. +template<max_size_t V> struct Su { static_assert(V*V == V+132); }; +template<max_diff_t V> struct Ss { static_assert(V*V == V+132); }; +template struct Su<12>; +template struct Ss<12>; + int main() { diff --git a/libstdc++-v3/testsuite/std/time/clock/local/io.cc b/libstdc++-v3/testsuite/std/time/clock/local/io.cc index b4d562f..67818e8 100644 --- a/libstdc++-v3/testsuite/std/time/clock/local/io.cc +++ b/libstdc++-v3/testsuite/std/time/clock/local/io.cc @@ -89,6 +89,9 @@ test_format() s = std::format("{}", local_seconds{}); VERIFY( s == "1970-01-01 00:00:00" ); + + s = std::format("{}", local_days{}); // PR libstdc++/120293 + VERIFY( s == "1970-01-01" ); } void diff --git a/libstdc++-v3/testsuite/std/time/format/data_not_present_neg.cc b/libstdc++-v3/testsuite/std/time/format/data_not_present_neg.cc new file mode 100644 index 0000000..bb09451 --- /dev/null +++ b/libstdc++-v3/testsuite/std/time/format/data_not_present_neg.cc @@ -0,0 +1,164 @@ +// { dg-do compile { target c++20 } } + +#include <chrono> +#include <format> + +using namespace std::chrono; + +auto d1 = std::format("{:%w}", 10d); // { dg-error "call to consteval function" } +auto d2 = std::format("{:%m}", 10d); // { dg-error "call to consteval function" } +auto d3 = std::format("{:%y}", 10d); // { dg-error "call to consteval function" } +auto d4 = std::format("{:%F}", 10d); // { dg-error "call to consteval function" } +auto d5 = std::format("{:%T}", 10d); // { dg-error "call to consteval function" } +auto d6 = std::format("{:%Q}", 10d); // { dg-error "call to consteval function" } +auto d7 = std::format("{:%Z}", 10d); // { dg-error "call to consteval function" } + +auto w1 = std::format("{:%d}", Thursday); // { dg-error "call to consteval function" } +auto w2 = std::format("{:%m}", Thursday); // { dg-error "call to consteval function" } +auto w3 = std::format("{:%y}", Thursday); // { dg-error "call to consteval function" } +auto w4 = std::format("{:%F}", Thursday); // { dg-error "call to consteval function" } +auto w5 = std::format("{:%T}", Thursday); // { dg-error "call to consteval function" } +auto w6 = std::format("{:%Q}", Thursday); // { dg-error "call to consteval function" } +auto w7 = std::format("{:%Z}", Thursday); // { dg-error "call to consteval function" } + +auto wi1 = std::format("{:%d}", Thursday[2]); // { dg-error "call to consteval function" } +auto wi2 = std::format("{:%m}", Thursday[2]); // { dg-error "call to consteval function" } +auto wi3 = std::format("{:%y}", Thursday[2]); // { dg-error "call to consteval function" } +auto wi4 = std::format("{:%F}", Thursday[2]); // { dg-error "call to consteval function" } +auto wi5 = std::format("{:%T}", Thursday[2]); // { dg-error "call to consteval function" } +auto wi6 = std::format("{:%Q}", Thursday[2]); // { dg-error "call to consteval function" } +auto wi7 = std::format("{:%Z}", Thursday[2]); // { dg-error "call to consteval function" } + +auto wl1 = std::format("{:%d}", Thursday[last]); // { dg-error "call to consteval function" } +auto wl2 = std::format("{:%m}", Thursday[last]); // { dg-error "call to consteval function" } +auto wl3 = std::format("{:%y}", Thursday[last]); // { dg-error "call to consteval function" } +auto wl4 = std::format("{:%F}", Thursday[last]); // { dg-error "call to consteval function" } +auto wl5 = std::format("{:%T}", Thursday[last]); // { dg-error "call to consteval function" } +auto wl6 = std::format("{:%Q}", Thursday[last]); // { dg-error "call to consteval function" } +auto wl7 = std::format("{:%Z}", Thursday[last]); // { dg-error "call to consteval function" } + +auto m1 = std::format("{:%d}", January); // { dg-error "call to consteval function" } +auto m2 = std::format("{:%w}", January); // { dg-error "call to consteval function" } +auto m3 = std::format("{:%y}", January); // { dg-error "call to consteval function" } +auto m4 = std::format("{:%F}", January); // { dg-error "call to consteval function" } +auto m5 = std::format("{:%T}", January); // { dg-error "call to consteval function" } +auto m6 = std::format("{:%Q}", January); // { dg-error "call to consteval function" } +auto m7 = std::format("{:%Z}", January); // { dg-error "call to consteval function" } + +auto yr1 = std::format("{:%d}", 2025y); // { dg-error "call to consteval function" } +auto yr2 = std::format("{:%w}", 2025y); // { dg-error "call to consteval function" } +auto yr3 = std::format("{:%m}", 2025y); // { dg-error "call to consteval function" } +auto yr4 = std::format("{:%F}", 2025y); // { dg-error "call to consteval function" } +auto yr5 = std::format("{:%T}", 2025y); // { dg-error "call to consteval function" } +auto yr6 = std::format("{:%Q}", 2025y); // { dg-error "call to consteval function" } +auto yr7 = std::format("{:%Z}", 2025y); // { dg-error "call to consteval function" } + +auto md1 = std::format("{:%w}", January/10d); // { dg-error "call to consteval function" } +auto md2 = std::format("{:%y}", January/10d); // { dg-error "call to consteval function" } +auto md3 = std::format("{:%F}", January/10d); // { dg-error "call to consteval function" } +auto md4 = std::format("{:%T}", January/10d); // { dg-error "call to consteval function" } +auto md5 = std::format("{:%Q}", January/10d); // { dg-error "call to consteval function" } +auto md6 = std::format("{:%Z}", January/10d); // { dg-error "call to consteval function" } + +auto mwi1 = std::format("{:%d}", January/Thursday[2]); // { dg-error "call to consteval function" } +auto mwi2 = std::format("{:%y}", January/Thursday[2]); // { dg-error "call to consteval function" } +auto mwi3 = std::format("{:%F}", January/Thursday[2]); // { dg-error "call to consteval function" } +auto mwi4 = std::format("{:%T}", January/Thursday[2]); // { dg-error "call to consteval function" } +auto mwi5 = std::format("{:%Q}", January/Thursday[2]); // { dg-error "call to consteval function" } +auto mwi6 = std::format("{:%Z}", January/Thursday[2]); // { dg-error "call to consteval function" } + +auto mwl1 = std::format("{:%d}", January/Thursday[last]); // { dg-error "call to consteval function" } +auto mwl2 = std::format("{:%y}", January/Thursday[last]); // { dg-error "call to consteval function" } +auto mwl3 = std::format("{:%F}", January/Thursday[last]); // { dg-error "call to consteval function" } +auto mwl4 = std::format("{:%T}", January/Thursday[last]); // { dg-error "call to consteval function" } +auto mwl5 = std::format("{:%Q}", January/Thursday[last]); // { dg-error "call to consteval function" } +auto mwl6 = std::format("{:%Z}", January/Thursday[last]); // { dg-error "call to consteval function" } + +auto ml1 = std::format("{:%d}", January/last); // { dg-error "call to consteval function" } +auto ml2 = std::format("{:%w}", January/last); // { dg-error "call to consteval function" } +auto ml3 = std::format("{:%y}", January/last); // { dg-error "call to consteval function" } +auto ml4 = std::format("{:%F}", January/last); // { dg-error "call to consteval function" } +auto ml5 = std::format("{:%T}", January/last); // { dg-error "call to consteval function" } +auto ml6 = std::format("{:%Q}", January/last); // { dg-error "call to consteval function" } +auto ml7 = std::format("{:%Z}", January/last); // { dg-error "call to consteval function" } + +auto ym1 = std::format("{:%d}", 2024y/March); // { dg-error "call to consteval function" } +auto ym2 = std::format("{:%w}", 2024y/March); // { dg-error "call to consteval function" } +auto ym3 = std::format("{:%F}", 2024y/March); // { dg-error "call to consteval function" } +auto ym4 = std::format("{:%T}", 2024y/March); // { dg-error "call to consteval function" } +auto ym5 = std::format("{:%Q}", 2024y/March); // { dg-error "call to consteval function" } +auto ym6 = std::format("{:%Z}", 2024y/March); // { dg-error "call to consteval function" } + +auto ymd1 = std::format("{:%T}", 2021y/January/10d); // { dg-error "call to consteval function" } +auto ymd2 = std::format("{:%Q}", 2021y/January/10d); // { dg-error "call to consteval function" } +auto ymd3 = std::format("{:%Z}", 2021y/January/10d); // { dg-error "call to consteval function" } + +auto ymwi1 = std::format("{:%T}", 2021y/January/Thursday[2]); // { dg-error "call to consteval function" } +auto ymwi2 = std::format("{:%Q}", 2021y/January/Thursday[2]); // { dg-error "call to consteval function" } +auto ymwi3 = std::format("{:%Z}", 2021y/January/Thursday[2]); // { dg-error "call to consteval function" } + +auto ymwl1 = std::format("{:%T}", 2021y/January/Thursday[last]); // { dg-error "call to consteval function" } +auto ymwl2 = std::format("{:%Q}", 2021y/January/Thursday[last]); // { dg-error "call to consteval function" } +auto ymwl3 = std::format("{:%Z}", 2021y/January/Thursday[last]); // { dg-error "call to consteval function" } + +auto yml1 = std::format("{:%T}", 2021y/January/last); // { dg-error "call to consteval function" } +auto yml2 = std::format("{:%Q}", 2021y/January/last); // { dg-error "call to consteval function" } +auto yml3 = std::format("{:%Z}", 2021y/January/last); // { dg-error "call to consteval function" } + +auto ls1 = std::format("{:%Q}", local_seconds(20s)); // { dg-error "call to consteval function" } +auto ls2 = std::format("{:%Z}", local_seconds(10s)); // { dg-error "call to consteval function" } +auto ld1 = std::format("{:%Q}", local_days(days(20))); // { dg-error "call to consteval function" } +auto ld2 = std::format("{:%Z}", local_days(days(10))); // { dg-error "call to consteval function" } + +auto ss1 = std::format("{:%Q}", sys_seconds(20s)); // { dg-error "call to consteval function" } +auto sd1 = std::format("{:%Q}", sys_days(days(20))); // { dg-error "call to consteval function" } + +auto utc = std::format("{:%Q}", utc_clock::now()); // { dg-error "call to consteval function" } +auto gps = std::format("{:%Q}", gps_clock::now()); // { dg-error "call to consteval function" } +auto tai = std::format("{:%Q}", tai_clock::now()); // { dg-error "call to consteval function" } +auto file = std::format("{:%Q}", file_clock::now()); // { dg-error "call to consteval function" } + +const auto ltc = local_seconds(10s); +#if _GLIBCXX_USE_CXX11_ABI || !_GLIBCXX_USE_DUAL_ABI +const auto zt = zoned_time<seconds>("Europe/Sofia", local_seconds(10s)); +auto zt1 = std::format("{:%Q}", zt); // { dg-error "call to consteval function" "" { target cxx11_abi } } +#endif +auto lf1 = std::format("{:%Q}", local_time_format(ltc)); // { dg-error "call to consteval function" } + +auto dur1 = std::format("{:%d}", 123s); // { dg-error "call to consteval function" } +auto dur2 = std::format("{:%w}", 123s); // { dg-error "call to consteval function" } +auto dur3 = std::format("{:%m}", 123s); // { dg-error "call to consteval function" } +auto dur4 = std::format("{:%y}", 123s); // { dg-error "call to consteval function" } +auto dur5 = std::format("{:%F}", 123s); // { dg-error "call to consteval function" } +auto dur6 = std::format("{:%Z}", 123s); // { dg-error "call to consteval function" } + +using HMS = hh_mm_ss<seconds>; +auto hms1 = std::format("{:%d}", HMS(1255s)); // { dg-error "call to consteval function" } +auto hms2 = std::format("{:%w}", HMS(1255s)); // { dg-error "call to consteval function" } +auto hms3 = std::format("{:%m}", HMS(1255s)); // { dg-error "call to consteval function" } +auto hms4 = std::format("{:%y}", HMS(1255s)); // { dg-error "call to consteval function" } +auto hms5 = std::format("{:%F}", HMS(1255s)); // { dg-error "call to consteval function" } +auto hms6 = std::format("{:%Q}", HMS(1255s)); // { dg-error "call to consteval function" } +auto hms7 = std::format("{:%Z}", HMS(1255s)); // { dg-error "call to consteval function" } + +#if _GLIBCXX_USE_CXX11_ABI || !_GLIBCXX_USE_DUAL_ABI +auto li1 = std::format("{:%d}", local_info()); // { dg-error "call to consteval function" "" { target cxx11_abi } } +auto li2 = std::format("{:%w}", local_info()); // { dg-error "call to consteval function" "" { target cxx11_abi } } +auto li3 = std::format("{:%m}", local_info()); // { dg-error "call to consteval function" "" { target cxx11_abi } } +auto li4 = std::format("{:%y}", local_info()); // { dg-error "call to consteval function" "" { target cxx11_abi } } +auto li5 = std::format("{:%F}", local_info()); // { dg-error "call to consteval function" "" { target cxx11_abi } } +auto li6 = std::format("{:%T}", local_info()); // { dg-error "call to consteval function" "" { target cxx11_abi } } +auto li7 = std::format("{:%Q}", local_info()); // { dg-error "call to consteval function" "" { target cxx11_abi } } +auto li8 = std::format("{:%Z}", local_info()); // { dg-error "call to consteval function" "" { target cxx11_abi } } + +auto si1 = std::format("{:%d}", sys_info()); // { dg-error "call to consteval function" "" { target cxx11_abi } } +auto si2 = std::format("{:%w}", sys_info()); // { dg-error "call to consteval function" "" { target cxx11_abi } } +auto si3 = std::format("{:%m}", sys_info()); // { dg-error "call to consteval function" "" { target cxx11_abi } } +auto si4 = std::format("{:%y}", sys_info()); // { dg-error "call to consteval function" "" { target cxx11_abi } } +auto si5 = std::format("{:%F}", sys_info()); // { dg-error "call to consteval function" "" { target cxx11_abi } } +auto si6 = std::format("{:%T}", sys_info()); // { dg-error "call to consteval function" "" { target cxx11_abi } } +auto si7 = std::format("{:%Q}", sys_info()); // { dg-error "call to consteval function" "" { target cxx11_abi } } +auto si8 = std::format("{:%Z}", sys_info()); // { dg-error "call to consteval function" "" { target cxx11_abi } } +#endif + +// { dg-error "call to non-'constexpr' function" "" { target *-*-* } 0 } diff --git a/libstdc++-v3/testsuite/std/time/format/empty_spec.cc b/libstdc++-v3/testsuite/std/time/format/empty_spec.cc new file mode 100644 index 0000000..ef1b19d --- /dev/null +++ b/libstdc++-v3/testsuite/std/time/format/empty_spec.cc @@ -0,0 +1,917 @@ +// { dg-do run { target c++20 } } +// { dg-require-effective-target hosted } +// { dg-timeout-factor 5 } + +#include <chrono> +#include <ranges> +#include <sstream> +#include <testsuite_hooks.h> + +using namespace std::chrono; + +#define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S) +#define WIDEN(S) WIDEN_(CharT, S) + +template<typename CharT, typename T> +void +test_no_empty_spec() +{ + try + { + T t{}; + + if constexpr (std::is_same_v<CharT, char>) + (void)std::vformat("{}", std::make_format_args(t)); +#ifdef _GLIBCXX_USE_WCHAR_T + else + (void)std::vformat(L"{}", std::make_wformat_args(t)); +#endif // _GLIBCXX_USE_WCHAR_T + VERIFY(false); + } + catch (const std::format_error&) + { + VERIFY(true); + } +} + +template<typename T, typename CharT> +void verify(const T& t, std::basic_string_view<CharT> str) +{ + std::basic_string<CharT> res; + + res = std::format(WIDEN("{}"), t); + VERIFY( res == str ); + + std::basic_stringstream<CharT> os; + os << t; + res = std::move(os).str(); + VERIFY( res == str ); +} + +template<typename T, typename CharT> +void verify(const T& t, const CharT* str) +{ verify(t, std::basic_string_view<CharT>(str)); } + +template<typename CharT> +void +test_padding() +{ + std::basic_string<CharT> res; + + res = std::format(WIDEN("{:5}"), day(2)); + VERIFY( res == WIDEN("02 ") ); + + res = std::format(WIDEN("{:>6}"), weekday(4)); + VERIFY( res == WIDEN(" Thu") ); + + res = std::format(WIDEN("{:^7}"), month(3)); + VERIFY( res == WIDEN(" Mar ") ); + + res = std::format(WIDEN("{:-<4}"), day(30)); + VERIFY( res == WIDEN("30--") ); + + res = std::format(WIDEN("{:+>30}"), weekday(9)); + VERIFY( res == WIDEN("++++++9 is not a valid weekday") ); + + res = std::format(WIDEN("{:=^27}"), month(16)); + VERIFY( res == WIDEN("==16 is not a valid month==") ); +} + +template<typename Ret = void, typename Under = long> +struct Rep +{ + using Return + = std::conditional_t<std::is_void_v<Ret>, Rep, Ret>; + + Rep(Under v = 0) : val(v) {} + + template<typename ORet, typename OUnder> + Rep(Rep<ORet, OUnder> o) : val(o.val) {} + + operator Under() const + { return val; } + + Return + operator+() const + { return val; } + + Rep + operator-() const + { return -val; } + + friend Rep + operator+(Rep lhs, Rep rhs) + { return lhs.val + rhs.val; } + + friend Rep + operator-(Rep lhs, Rep rhs) + { return lhs.val - rhs.val; } + + friend Rep + operator*(Rep lhs, Rep rhs) + { return lhs.val * rhs.val; } + + friend Rep + operator/(Rep lhs, Rep rhs) + { return lhs.val / rhs.val; } + + friend auto operator<=>(Rep, Rep) = default; + + template<typename CharT> + friend std::basic_ostream<CharT>& + operator<<(std::basic_ostream<CharT>& os, const Rep& t) + { return os << t.val << WIDEN("[via <<]"); } + + Under val; +}; + +template<typename Ret, typename Under1, typename Under2> +struct std::common_type<Rep<Ret, Under1>, Rep<Ret, Under2>> +{ + using type = Rep<Ret, std::common_type_t<Under1, Under2>>; +}; + +template<typename Ret, typename Under, typename Other> + requires std::is_integral_v<Other> +struct std::common_type<Rep<Ret, Under>, Other> +{ + using type = Rep<Ret, std::common_type_t<Under, Other>>; +}; + +template<typename Ret, typename Under, typename Other> + requires std::is_integral_v<Other> +struct std::common_type<Other, Rep<Ret, Under>> + : std::common_type<Rep<Ret, Under>, Other> +{ }; + +template<typename Ret, typename Under> +struct std::numeric_limits<Rep<Ret, Under>> + : std::numeric_limits<Under> +{ }; + +template<typename Ret, typename Under, typename CharT> +struct std::formatter<Rep<Ret, Under>, CharT> + : std::formatter<Under, CharT> +{ + template<typename Out> + typename std::basic_format_context<Out, CharT>::iterator + format(const Rep<Ret>& t, std::basic_format_context<Out, CharT>& ctx) const + { + constexpr std::basic_string_view<CharT> suffix = WIDEN("[via format]"); + auto out = std::formatter<Under, CharT>::format(t.val, ctx); + return std::ranges::copy(suffix, out).out; + } +}; + +using deciseconds = duration<seconds::rep, std::deci>; + +template<typename CharT> +void +test_duration() +{ + std::basic_string<CharT> res; + + const milliseconds di(40); + verify( di, WIDEN("40ms") ); + res = std::format(WIDEN("{:>6}"), di); + VERIFY( res == WIDEN(" 40ms") ); + + verify( -di, WIDEN("-40ms") ); + res = std::format(WIDEN("{:>6}"), -di); + VERIFY( res == WIDEN(" -40ms") ); +} + +template<typename CharT> +void +test_duration_fp() +{ + std::basic_string<CharT> res; + + const duration<double> df(11.22); + verify( df, WIDEN("11.22s") ); + res = std::format(WIDEN("{:=^12}"), df); + VERIFY( res == WIDEN("===11.22s===") ); + + verify( -df, WIDEN("-11.22s") ); + res = std::format(WIDEN("{:=^12}"), -df); + VERIFY( res == WIDEN("==-11.22s===") ); + + // precision accepted but ignored + res = std::format(WIDEN("{:.6}"), df); + VERIFY( res == WIDEN("11.22s") ); +} + +template<typename CharT> +void +test_duration_cust() +{ + std::basic_string<CharT> res; + const duration<char, std::ratio<1, 10>> charRep(123); + verify( charRep, WIDEN("123ds") ); + + // +asLong returns long, so formatted as long + const duration<Rep<long>> asLong(20); + verify( asLong, WIDEN("20s") ); + res = std::format(WIDEN("{:>6}"), asLong); + VERIFY( res == WIDEN(" 20s") ); + + verify( -asLong, WIDEN("-20s") ); + res = std::format(WIDEN("{:>6}"), -asLong); + VERIFY( res == WIDEN(" -20s") ); + + res = std::format(WIDEN("{:%Q}"), asLong); + VERIFY( res == WIDEN("20") ); + res = std::format(WIDEN("{:+<7%Q}"), asLong); + VERIFY( res == WIDEN("20+++++") ); + + // +asRep returns Rep<>, so formatted as Rep<> + const duration<Rep<>> asRep(10); + verify( asRep, WIDEN("10[via <<]s") ); + res = std::format(WIDEN("{:=^15}"), asRep); + VERIFY( res == WIDEN("==10[via <<]s==") ); + + verify( -asRep, WIDEN("-10[via <<]s") ); + res = std::format(WIDEN("{:=^15}"), -asRep); + VERIFY( res == WIDEN("=-10[via <<]s==") ); + + res = std::format(WIDEN("{:%Q}"), asRep); + VERIFY( res == WIDEN("10[via format]") ); + res = std::format(WIDEN("{:=^18%Q}"), asRep); + VERIFY( res == WIDEN("==10[via format]==") ); + + const duration<Rep<>, std::milli> milliRep(10); + verify( milliRep, WIDEN("10[via <<]ms") ); + res = std::format(WIDEN("{:=^15}"), milliRep); + VERIFY( res == WIDEN("=10[via <<]ms==") ); + + verify( -milliRep, WIDEN("-10[via <<]ms") ); + res = std::format(WIDEN("{:=^15}"), -milliRep); + VERIFY( res == WIDEN("=-10[via <<]ms=") ); + + res = std::format(WIDEN("{:%Q}"), milliRep); + VERIFY( res == WIDEN("10[via format]") ); + res = std::format(WIDEN("{:=^18%Q}"), milliRep); + VERIFY( res == WIDEN("==10[via format]==") ); +} + +template<typename Ratio, typename Rep, typename Period> +constexpr auto +hms(const duration<Rep, Period>& d) +{ + using Dur = duration<Rep, typename Ratio::period>; + return hh_mm_ss<Dur>(duration_cast<Dur>(d)); +} + +template<typename CharT> +void +test_hh_mm_ss() +{ + auto dt = 22h + 24min + 54s + 111222333ns; + verify( hms<nanoseconds>(dt), + WIDEN("22:24:54.111222333") ); + verify( hms<microseconds>(dt), + WIDEN("22:24:54.111222") ); + verify( hms<milliseconds>(dt), + WIDEN("22:24:54.111") ); + verify( hms<deciseconds>(dt), + WIDEN("22:24:54.1") ); + verify( hms<seconds>(dt), + WIDEN("22:24:54") ); + verify( hms<minutes>(dt), + WIDEN("22:24:00") ); + verify( hms<hours>(dt), + WIDEN("22:00:00") ); + verify( hms<nanoseconds>(-dt), + WIDEN("-22:24:54.111222333") ); + verify( hms<microseconds>(-dt), + WIDEN("-22:24:54.111222") ); + verify( hms<milliseconds>(-dt), + WIDEN("-22:24:54.111") ); + verify( hms<deciseconds>(-dt), + WIDEN("-22:24:54.1") ); + verify( hms<seconds>(-dt), + WIDEN("-22:24:54") ); + verify( hms<minutes>(-dt), + WIDEN("-22:24:00") ); + verify( hms<hours>(-dt), + WIDEN("-22:00:00") ); + + verify( hms<nanoseconds>(-dt), + WIDEN("-22:24:54.111222333") ); + + dt += 300h; + verify( hms<nanoseconds>(dt), + WIDEN("322:24:54.111222333") ); + verify( hms<nanoseconds>(-dt), + WIDEN("-322:24:54.111222333") ); + + dt += 14000h; + verify( hms<nanoseconds>(dt), + WIDEN("14322:24:54.111222333") ); + verify( hms<nanoseconds>(-dt), + WIDEN("-14322:24:54.111222333") ); +} + +template<typename CharT> +void +test_hh_mm_ss_fp() +{ + duration<double> dt = 22h + 24min + 54s + 111222333ns; + // period controls number of subseconds + verify( hms<nanoseconds>(dt), + WIDEN("22:24:54.111222333") ); + verify( hms<microseconds>(dt), + WIDEN("22:24:54.111222") ); + verify( hms<milliseconds>(dt), + WIDEN("22:24:54.111") ); + verify( hms<deciseconds>(dt), + WIDEN("22:24:54.1") ); + verify( hms<seconds>(dt), + WIDEN("22:24:54") ); + verify( hms<nanoseconds>(-dt), + WIDEN("-22:24:54.111222333") ); + verify( hms<microseconds>(-dt), + WIDEN("-22:24:54.111222") ); + verify( hms<milliseconds>(-dt), + WIDEN("-22:24:54.111") ); + verify( hms<deciseconds>(-dt), + WIDEN("-22:24:54.1") ); + verify( hms<seconds>(-dt), + WIDEN("-22:24:54") ); + + // but hour and minutes are preserved + verify( hms<minutes>(dt), + WIDEN("22:24:54") ); + verify( hms<hours>(dt), + WIDEN("22:24:54") ); + verify( hms<minutes>(-dt), + WIDEN("-22:24:54") ); + verify( hms<hours>(-dt), + WIDEN("-22:24:54") ); +} + +template<typename CharT> +void +test_hh_mm_ss_cust() +{ + const duration<char, deciseconds::period> charRep(123); + verify( hms<deciseconds>(charRep), + WIDEN("00:00:12.3") ); + verify( hms<seconds>(charRep), + WIDEN("00:00:12") ); + + auto dt = 22h + 24min + 54s + 123ms; + // +plus returns long, so formatted as long + const duration<Rep<long>, std::milli> asLong(dt.count()); + verify( hms<milliseconds>(asLong), + WIDEN("22:24:54.123") ); + verify( hms<deciseconds>(asLong), + WIDEN("22:24:54.1") ); + verify( hms<seconds>(asLong), + WIDEN("22:24:54") ); + verify( hms<milliseconds>(-asLong), + WIDEN("-22:24:54.123") ); + verify( hms<deciseconds>(-asLong), + WIDEN("-22:24:54.1") ); + verify( hms<seconds>(-asLong), + WIDEN("-22:24:54") ); + + // +asRep returns Rep<>, so formatted as Rep<> + const duration<Rep<>, std::milli> asRep(dt.count()); + verify( hms<milliseconds>(asRep), + WIDEN("22:24:54.123") ); + verify( hms<deciseconds>(asRep), + WIDEN("22:24:54.1") ); + verify( hms<seconds>(asLong), + WIDEN("22:24:54") ); + verify( hms<milliseconds>(-asLong), + WIDEN("-22:24:54.123") ); + verify( hms<deciseconds>(-asLong), + WIDEN("-22:24:54.1") ); + verify( hms<seconds>(-asLong), + WIDEN("-22:24:54") ); +} + +template<typename CharT> +void +test_durations() +{ + test_duration<CharT>(); + test_duration_fp<CharT>(); + test_duration_cust<CharT>(); + + test_hh_mm_ss<CharT>(); + test_hh_mm_ss_fp<CharT>(); + test_hh_mm_ss_cust<CharT>(); +} + +template<typename CharT> +void +test_day() +{ + verify( day(0), WIDEN("00 is not a valid day") ); + verify( day(1), WIDEN("01") ); + verify( day(10), WIDEN("10") ); + verify( day(32), WIDEN("32 is not a valid day") ); + verify( day(110), WIDEN("110 is not a valid day") ); + verify( day(255), WIDEN("255 is not a valid day") ); +} + +template<typename CharT> +void +test_month() +{ + verify( month(0), WIDEN("0 is not a valid month") ); + verify( month(1), WIDEN("Jan") ); + verify( month(10), WIDEN("Oct") ); + verify( month(32), WIDEN("32 is not a valid month") ); + verify( month(110), WIDEN("110 is not a valid month") ); + verify( month(100), WIDEN("100 is not a valid month") ); + verify( month(110), WIDEN("110 is not a valid month") ); + verify( month(255), WIDEN("255 is not a valid month") ); +} + +template<typename CharT> +void +test_year() +{ + verify( year(-32768), WIDEN("-32768 is not a valid year") ); + verify( year(-32767), WIDEN("-32767") ); + verify( year(-67), WIDEN( "-0067") ); + verify( year(-1), WIDEN( "-0001") ); + verify( year(0), WIDEN( "0000") ); + verify( year(1), WIDEN( "0001") ); + verify( year(123), WIDEN( "0123") ); + verify( year(2025), WIDEN( "2025") ); + verify( year(32767), WIDEN( "32767") ); +} + +template<typename CharT> +void +test_weekday() +{ + verify( weekday(0), WIDEN("Sun") ); + verify( weekday(2), WIDEN("Tue") ); + verify( weekday(6), WIDEN("Sat") ); + verify( weekday(7), WIDEN("Sun") ); + verify( weekday(9), WIDEN("9 is not a valid weekday") ); + verify( weekday(32), WIDEN("32 is not a valid weekday") ); + verify( weekday(110), WIDEN("110 is not a valid weekday") ); + verify( weekday(255), WIDEN("255 is not a valid weekday") ); +} + +template<typename CharT> +void +test_weekday_indexed() +{ + verify( weekday(0)[0], WIDEN("Sun[0 is not a valid index]") ); + verify( weekday(2)[1], WIDEN("Tue[1]") ); + verify( weekday(6)[5], WIDEN("Sat[5]") ); + verify( weekday(7)[6], WIDEN("Sun[6 is not a valid index]") ); + verify( weekday(7)[12], WIDEN("Sun[12 is not a valid index]") ); + verify( weekday(5)[117], WIDEN("Fri[117 is not a valid index]") ); + verify( weekday(7)[255], WIDEN("Sun[255 is not a valid index]") ); + verify( weekday(9)[1], WIDEN("9 is not a valid weekday[1]") ); + verify( weekday(32)[7], WIDEN("32 is not a valid weekday[7 is not a valid index]") ); +} + +template<typename CharT> +void +test_weekday_last() +{ + verify( weekday(0)[last], WIDEN("Sun[last]") ); + verify( weekday(9)[last], WIDEN("9 is not a valid weekday[last]") ); +} + +template<typename CharT> +void +test_month_day() +{ + verify( month(1)/30, WIDEN("Jan/30") ); + verify( month(3)/32, WIDEN("Mar/32 is not a valid day") ); + verify( month(13)/30, WIDEN("13 is not a valid month/30") ); + verify( month(13)/32, WIDEN("13 is not a valid month/32 is not a valid day") ); +} + +template<typename CharT> +void +test_month_day_last() +{ + verify( month(1)/last, WIDEN("Jan/last") ); + verify( month(14)/last, WIDEN("14 is not a valid month/last") ); +} + +template<typename CharT> +void +test_month_weekday() +{ + verify( month(1)/weekday(2)[1], + WIDEN("Jan/Tue[1]") ); + verify( month(3)/weekday(9)[2], + WIDEN("Mar/9 is not a valid weekday[2]") ); + verify( month(13)/weekday(1)[7], + WIDEN("13 is not a valid month/Mon[7 is not a valid index]") ); + verify( month(13)/weekday(10)[3], + WIDEN("13 is not a valid month/10 is not a valid weekday[3]") ); + verify( month(13)/weekday(130)[0], + WIDEN("13 is not a valid month/130 is not a valid weekday[0 is not a valid index]") ); +} + +template<typename CharT> +void +test_month_weekday_last() +{ + verify( month(1)/weekday(2)[last], + WIDEN("Jan/Tue[last]") ); + verify( month(3)/weekday(9)[last], + WIDEN("Mar/9 is not a valid weekday[last]") ); + verify( month(13)/weekday(1)[last], + WIDEN("13 is not a valid month/Mon[last]") ); + verify( month(13)/weekday(10)[last], + WIDEN("13 is not a valid month/10 is not a valid weekday[last]") ); +} + +template<typename CharT> +void +test_year_month() +{ + verify( year(2024)/month(1), + WIDEN("2024/Jan") ); + verify( year(2025)/month(14), + WIDEN("2025/14 is not a valid month") ); + verify( year(-32768)/month(2), + WIDEN("-32768 is not a valid year/Feb") ); + verify( year(-32768)/month(0), + WIDEN("-32768 is not a valid year/0 is not a valid month") ); +} + +template<typename CharT> +void +test_year_month_day() +{ + verify( year(2024)/month(1)/30, + WIDEN("2024-01-30") ); + verify( year(-100)/month(14)/1, + WIDEN("-0100-14-01 is not a valid date") ); + verify( year(2025)/month(11)/100, + WIDEN("2025-11-100 is not a valid date") ); + verify( year(-32768)/month(2)/10, + WIDEN("-32768-02-10 is not a valid date") ); + verify( year(-32768)/month(212)/10, + WIDEN("-32768-212-10 is not a valid date") ); + verify( year(-32768)/month(2)/105, + WIDEN("-32768-02-105 is not a valid date") ); + verify( year(-32768)/month(14)/55, + WIDEN("-32768-14-55 is not a valid date") ); +} + +template<typename CharT> +void +test_year_month_last() +{ + verify( year(2024)/month(1)/last, + WIDEN("2024/Jan/last") ); + verify( year(2025)/month(14)/last, + WIDEN("2025/14 is not a valid month/last") ); + verify( year(-32768)/month(2)/last, + WIDEN("-32768 is not a valid year/Feb/last") ); + verify( year(-32768)/month(0)/last, + WIDEN("-32768 is not a valid year/0 is not a valid month/last") ); +} + +template<typename CharT> +void +test_year_month_weekday() +{ + verify( year(2024)/month(1)/weekday(2)[1], + WIDEN("2024/Jan/Tue[1]") ); + verify( year(-1)/month(3)/weekday(9)[2], + WIDEN("-0001/Mar/9 is not a valid weekday[2]") ); + verify( year(-32768)/month(13)/weekday(1)[7], + WIDEN("-32768 is not a valid year/13 is not a valid month/Mon[7 is not a valid index]") ); + verify( year(-100)/month(13)/weekday(10)[3], + WIDEN("-0100/13 is not a valid month/10 is not a valid weekday[3]") ); + verify( year(-32768)/month(13)/weekday(130)[0], + WIDEN("-32768 is not a valid year/13 is not a valid month/130 is not a valid weekday[0 is not a valid index]") ); +} + +template<typename CharT> +void +test_year_month_weekday_last() +{ + verify( year(2024)/month(1)/weekday(2)[last], + WIDEN("2024/Jan/Tue[last]") ); + verify( year(-1)/month(3)/weekday(9)[last], + WIDEN("-0001/Mar/9 is not a valid weekday[last]") ); + verify( year(-32768)/month(13)/weekday(1)[last], + WIDEN("-32768 is not a valid year/13 is not a valid month/Mon[last]") ); + verify( year(-100)/month(13)/weekday(10)[last], + WIDEN("-0100/13 is not a valid month/10 is not a valid weekday[last]") ); + verify( year(-32768)/month(13)/weekday(130)[last], + WIDEN("-32768 is not a valid year/13 is not a valid month/130 is not a valid weekday[last]") ); +} + +template<typename CharT> +void +test_calendar() +{ + test_day<CharT>(); + test_month<CharT>(); + test_year<CharT>(); + + test_weekday<CharT>(); + test_weekday_indexed<CharT>(); + test_weekday_last<CharT>(); + + test_month_day<CharT>(); + test_month_day_last<CharT>(); + test_month_weekday<CharT>(); + test_month_weekday_last<CharT>(); + + test_year_month<CharT>(); + test_year_month_day<CharT>(); + test_year_month_last<CharT>(); + test_year_month_weekday<CharT>(); + test_year_month_weekday_last<CharT>(); +} + +template<typename Clock, typename Dur, typename Dur2> +constexpr auto +wall_cast(const local_time<Dur2>& tp) +{ + using TP = time_point<Clock, std::common_type_t<Dur, days>>; + if constexpr (std::is_same_v<Clock, utc_clock> || std::is_same_v<Clock, file_clock>) + return clock_cast<Clock>(wall_cast<system_clock, Dur>(tp)); + else if constexpr (std::is_same_v<Clock, tai_clock>) + return TP(floor<Dur>(tp.time_since_epoch()) + days(4383)); + else if constexpr (std::is_same_v<Clock, gps_clock>) + return TP(floor<Dur>(tp.time_since_epoch()) - days(3657)); + else // system_clock, local_t + return time_point<Clock, Dur>(floor<Dur>(tp.time_since_epoch())); +} + +using decadays = duration<days::rep, std::ratio_multiply<std::deca, days::period>>; +using kilodays = duration<days::rep, std::ratio_multiply<std::kilo, days::period>>; + +template<typename CharT, typename Clock> +void +test_time_point(bool daysAsTime) +{ + std::basic_string<CharT> res; + + const auto lt = local_days(2024y/March/22) + 13h + 24min + 54s + 111222333ns; + auto strip_time = [daysAsTime](std::basic_string_view<CharT> sv) + { return daysAsTime ? sv : sv.substr(0, 10); }; + + verify( wall_cast<Clock, nanoseconds>(lt), + WIDEN("2024-03-22 13:24:54.111222333") ); + verify( wall_cast<Clock, microseconds>(lt), + WIDEN("2024-03-22 13:24:54.111222") ); + verify( wall_cast<Clock, milliseconds>(lt), + WIDEN("2024-03-22 13:24:54.111") ); + verify( wall_cast<Clock, seconds>(lt), + WIDEN("2024-03-22 13:24:54") ); + verify( wall_cast<Clock, minutes>(lt), + WIDEN("2024-03-22 13:24:00") ); + verify( wall_cast<Clock, hours>(lt), + WIDEN("2024-03-22 13:00:00") ); + verify( wall_cast<Clock, days>(lt), + strip_time(WIDEN("2024-03-22 00:00:00")) ); + verify( wall_cast<Clock, decadays>(lt), + strip_time(WIDEN("2024-03-18 00:00:00")) ); + verify( wall_cast<Clock, kilodays>(lt), + strip_time(WIDEN("2022-01-08 00:00:00")) ); +} + +template<typename CharT> +void +test_leap_second() +{ + std::basic_string<CharT> res; + + const auto st = sys_days(2012y/June/30) + 23h + 59min + 59s + 111222333ns; + auto tp = clock_cast<utc_clock>(st); + tp += 1s; + + verify( floor<nanoseconds>(tp), + WIDEN("2012-06-30 23:59:60.111222333") ); + verify( floor<microseconds>(tp), + WIDEN("2012-06-30 23:59:60.111222") ); + verify( floor<milliseconds>(tp), + WIDEN("2012-06-30 23:59:60.111") ); + verify( floor<seconds>(tp), + WIDEN("2012-06-30 23:59:60") ); +} + +#if _GLIBCXX_USE_CXX11_ABI || !_GLIBCXX_USE_DUAL_ABI +template<typename Dur, typename Dur2> +auto +make_zoned(const sys_time<Dur2>& st, const time_zone* tz) +{ return zoned_time<Dur>(tz, floor<Dur>(st)); } + +template<typename CharT> +void +test_zoned_time() +{ + const auto st = sys_days(2024y/March/22) + 13h + 24min + 54s + 111222333ns; + const time_zone* tz = locate_zone("Europe/Sofia"); + VERIFY( tz != nullptr ); + + verify( make_zoned<nanoseconds>(st, tz), + WIDEN("2024-03-22 15:24:54.111222333 EET") ); + verify( make_zoned<microseconds>(st, tz), + WIDEN("2024-03-22 15:24:54.111222 EET") ); + verify( make_zoned<milliseconds>(st, tz), + WIDEN("2024-03-22 15:24:54.111 EET") ); + verify( make_zoned<seconds>(st, tz), + WIDEN("2024-03-22 15:24:54 EET") ); + verify( make_zoned<minutes>(st, tz), + WIDEN("2024-03-22 15:24:00 EET") ); + verify( make_zoned<hours>(st, tz), + WIDEN("2024-03-22 15:00:00 EET") ); + verify( make_zoned<days>(st, tz), + WIDEN("2024-03-22 02:00:00 EET") ); + verify( make_zoned<decadays>(st, tz), + WIDEN("2024-03-18 02:00:00 EET") ); + verify( make_zoned<kilodays>(st, tz), + WIDEN("2022-01-08 02:00:00 EET") ); +} +#endif + +template<typename Dur, typename Dur2> +auto +local_fmt(const local_time<Dur2>& lt, std::string* zone) +{ return local_time_format(floor<Dur>(lt), zone); } + +template<typename CharT> +void +test_local_time_format() +{ + std::basic_string<CharT> res; + + std::string abbrev = "Zone"; + const auto lt = local_days(2024y/March/22) + 13h + 24min + 54s + 111222333ns; + + res = std::format(WIDEN("{}"), local_fmt<nanoseconds>(lt, &abbrev)); + VERIFY( res == WIDEN("2024-03-22 13:24:54.111222333 Zone") ); + res = std::format(WIDEN("{}"), local_fmt<microseconds>(lt, &abbrev)); + VERIFY( res == WIDEN("2024-03-22 13:24:54.111222 Zone") ); + res = std::format(WIDEN("{}"), local_fmt<milliseconds>(lt, &abbrev)); + VERIFY( res == WIDEN("2024-03-22 13:24:54.111 Zone") ); + res = std::format(WIDEN("{}"), local_fmt<seconds>(lt, &abbrev)); + VERIFY( res == WIDEN("2024-03-22 13:24:54 Zone") ); + res = std::format(WIDEN("{}"), local_fmt<minutes>(lt, &abbrev)); + VERIFY( res == WIDEN("2024-03-22 13:24:00 Zone") ); + res = std::format(WIDEN("{}"), local_fmt<hours>(lt, &abbrev)); + VERIFY( res == WIDEN("2024-03-22 13:00:00 Zone") ); + res = std::format(WIDEN("{}"), local_fmt<days>(lt, &abbrev)); + VERIFY( res == WIDEN("2024-03-22 00:00:00 Zone") ); + res = std::format(WIDEN("{}"), local_fmt<decadays>(lt, &abbrev)); + VERIFY( res == WIDEN("2024-03-18 00:00:00 Zone") ); + res = std::format(WIDEN("{}"), local_fmt<kilodays>(lt, &abbrev)); + VERIFY( res == WIDEN("2022-01-08 00:00:00 Zone") ); +} + +template<typename CharT> +void +test_time_points() +{ + test_time_point<CharT, local_t>(false); + test_time_point<CharT, system_clock>(false); + test_time_point<CharT, utc_clock>(true); + test_time_point<CharT, tai_clock>(true); + test_time_point<CharT, gps_clock>(true); + test_time_point<CharT, file_clock>(true); + test_leap_second<CharT>(); +#if _GLIBCXX_USE_CXX11_ABI || !_GLIBCXX_USE_DUAL_ABI + test_zoned_time<CharT>(); +#endif + test_local_time_format<CharT>(); + + test_no_empty_spec<CharT, sys_time<years>>(); + test_no_empty_spec<CharT, sys_time<duration<float>>>(); +} + +#if _GLIBCXX_USE_CXX11_ABI || !_GLIBCXX_USE_DUAL_ABI +template<typename CharT> +void +test_sys_info() +{ + const sys_info si + { + sys_days(2024y/March/22) + 2h, + sys_days(2025y/April/11) + 23h + 15min + 10s, + 2h + 13min + 4s, + 15min, + "Zone" + }; + const std::basic_string_view<CharT> txt + = WIDEN("[2024-03-22 02:00:00,2025-04-11 23:15:10,02:13:04,15min,Zone]"); + + verify( si, txt ); + + std::basic_string<CharT> res; + std::basic_string_view<CharT> sv; + + sv = res = std::format(WIDEN("{:65}"), si); + VERIFY( sv.ends_with(WIDEN(" ")) ); + sv.remove_suffix(4); + VERIFY( sv == txt ); + + sv = res = std::format(WIDEN("{:=^67}"), si); + VERIFY( sv.starts_with(WIDEN("===")) ); + VERIFY( sv.ends_with(WIDEN("===")) ); + sv.remove_prefix(3); + sv.remove_suffix(3); + VERIFY( sv == txt ); +} + +template<typename CharT> +void test_local_info() +{ + using String = std::basic_string<CharT>; + using StringView = std::basic_string_view<CharT>; + + const sys_info s1 + { + sys_days(2015y/September/11) + 2h, + sys_days(2016y/March/13) + 2h, + -5h, + 0h, + "EET" + }; + const sys_info s2 + { + sys_days(2016y/March/13) + 2h, + sys_days(2015y/September/15) + 2h, + -4h, + 1h, + "EDT" + }; + + const StringView single + = WIDEN("[2015-09-11 02:00:00,2016-03-13 02:00:00,-05:00:00,0min,EET]"); + const StringView both + = WIDEN(" local time between " + "[2015-09-11 02:00:00,2016-03-13 02:00:00,-05:00:00,0min,EET]" + " and " + "[2016-03-13 02:00:00,2015-09-15 02:00:00,-04:00:00,60min,EDT]"); + + const local_info l1{local_info::nonexistent, s1, s2}; + auto exp = WIDEN("[nonexistent") + String(both) + WIDEN("]"); + verify( l1, StringView(exp) ); + + const local_info l2{local_info::ambiguous, s1, s2}; + exp = WIDEN("[ambiguous") + String(both) + WIDEN("]"); + verify( l2, StringView(exp) ); + + const local_info l3{local_info::unique, s1, s1}; + exp = WIDEN("[") + String(single) + WIDEN("]"); + verify( l3, StringView(exp) ); + + String res; + StringView sv; + + sv = res = std::format(WIDEN("{:65}"), l3); + VERIFY( sv.ends_with(WIDEN(" ")) ); + sv.remove_suffix(3); + VERIFY( sv == exp ); + + sv = res = std::format(WIDEN("{:=^67}"), l3); + VERIFY( sv.starts_with(WIDEN("==")) ); + VERIFY( sv.ends_with(WIDEN("===")) ); + sv.remove_prefix(2); + sv.remove_suffix(3); + VERIFY( sv == exp ); +} + +template<typename CharT> +void +test_infos() +{ + test_sys_info<CharT>(); + test_local_info<CharT>(); +} +#endif + +template<typename CharT> +void +test_all() +{ + test_padding<CharT>(); + test_durations<CharT>(); + test_calendar<CharT>(); + test_time_points<CharT>(); +#if _GLIBCXX_USE_CXX11_ABI || !_GLIBCXX_USE_DUAL_ABI + test_infos<CharT>(); +#endif +} + +int main() +{ + test_all<char>(); + +#ifdef _GLIBCXX_USE_WCHAR_T + test_all<wchar_t>(); +#endif // _GLIBCXX_USE_WCHAR_T +} diff --git a/libstdc++-v3/testsuite/std/time/format/pr117214.cc b/libstdc++-v3/testsuite/std/time/format/pr117214.cc index 87c703d..79109c3 100644 --- a/libstdc++-v3/testsuite/std/time/format/pr117214.cc +++ b/libstdc++-v3/testsuite/std/time/format/pr117214.cc @@ -7,10 +7,14 @@ #include <chrono> #include <locale> +#include <span> #include <testsuite_hooks.h> + +template<typename ChronoType> void -test_c() +test_locale_formats(const ChronoType& t, + std::span<const char* const> test_specifiers) { const char *test_locales[] = { "aa_DJ.UTF-8", @@ -19,15 +23,44 @@ test_c() "az_IR.UTF-8", "my_MM.UTF-8", }; - std::chrono::sys_seconds t{std::chrono::seconds{1}}; + auto format_args = std::make_format_args(t); for (auto locale_name : test_locales) { - auto s = std::format(std::locale(locale_name), "{:L%c}", t); - VERIFY( !s.empty() ); + std::locale loc(locale_name); + for (auto specifier : test_specifiers) + { + auto s = std::vformat(loc, specifier, format_args); + VERIFY( !s.empty() ); + } } } +void +test_locale_formats() +{ + using namespace std::chrono; + + const char* test_specifiers[] = { + "{:L%x}", "{:L%Ex}", + "{:L%c}", "{:L%Ec}", + "{:L%X}", "{:L%EX}", + "{:L%r}", + }; + auto date_time_specifiers = std::span(test_specifiers); + auto date_specifiers = date_time_specifiers.subspan(0, 2); + auto time_specifiers = date_time_specifiers.subspan(4); + + auto ymd = 2020y/November/12d; + test_locale_formats(ymd, date_specifiers); + + auto tod = 25h + 10min + 12s; + test_locale_formats(tod, time_specifiers); + + auto tp = sys_days(ymd) + tod; + test_locale_formats(tp, date_time_specifiers); +} + #include <stdlib.h> #include <time.h> @@ -93,7 +126,7 @@ test_c_local() int main() { - test_c(); + test_locale_formats(); test_c_zoned(); test_c_local(); } diff --git a/libstdc++-v3/testsuite/std/time/format/pr120114.cc b/libstdc++-v3/testsuite/std/time/format/pr120114.cc new file mode 100644 index 0000000..cdde468 --- /dev/null +++ b/libstdc++-v3/testsuite/std/time/format/pr120114.cc @@ -0,0 +1,125 @@ +// { dg-do run { target c++23 } } +// { dg-options "-fexec-charset=UTF-8" } +// { dg-timeout-factor 2 } + +#include <algorithm> +#include <chrono> +#include <testsuite_hooks.h> + +#define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S) +#define WIDEN(S) WIDEN_(CharT, S) + +template<typename CharT> +void +test_from_format_string() +{ + std::basic_string<CharT> res; + using namespace std::chrono_literals; + auto date = 2025y/std::chrono::May/05d; + + res = std::format(WIDEN("{:+<13%F\U0001f921}"), date); + VERIFY( res == WIDEN("2025-05-05\U0001f921+") ); + + res = std::format(WIDEN("{:->15%F\U0001f921}"), date); + VERIFY( res == WIDEN("---2025-05-05\U0001f921") ); + + res = std::format(WIDEN("{:=^20%F\U0001f921}"), date); + VERIFY( res == WIDEN("====2025-05-05\U0001f921====") ); +} + +template<typename CharT> +void +test_formatted_value() +{ + // Custom time_put facet which returns Ideographic Telegraph Symbol + // for given month for Om. + struct TimePut : std::time_put<CharT> + { + using iter_type = std::time_put<CharT>::iter_type; + using char_type = std::time_put<CharT>::char_type; + + iter_type + do_put(iter_type out, std::ios_base& io, char_type fill, const tm* t, + char format, char modifier) const override + { + if (format != 'm' && modifier != 'm') + return std::time_put<CharT>::do_put(out, io, fill, t, format, modifier); + std::basic_string_view<CharT> str; + switch (t->tm_mon) + { + case 0: + str = WIDEN("\u32C0"); + break; + case 1: + str = WIDEN("\u32C1"); + break; + case 2: + str = WIDEN("\u32C2"); + break; + case 3: + str = WIDEN("\u32C3"); + break; + case 4: + str = WIDEN("\u32C4"); + break; + case 5: + str = WIDEN("\u32C5"); + break; + case 6: + str = WIDEN("\u32C6"); + break; + case 7: + str = WIDEN("\u32C7"); + break; + case 8: + str = WIDEN("\u32C8"); + break; + case 9: + str = WIDEN("\u32C9"); + break; + case 10: + str = WIDEN("\u32CA"); + break; + case 11: + str = WIDEN("\u32CB"); + break; + }; + return std::copy(str.begin(), str.end(), out); + } + }; + const std::locale loc(std::locale::classic(), new TimePut); + + std::basic_string<CharT> res; + + res = std::format(loc, WIDEN("{:<1L%Om}"), std::chrono::January); + VERIFY( res == WIDEN("\u32C0") ); + + res = std::format(loc, WIDEN("{:>2L%Om}"), std::chrono::February); + VERIFY( res == WIDEN("\u32C1") ); + + res = std::format(loc, WIDEN("{:<3L%Om}"), std::chrono::March); + VERIFY( res == WIDEN("\u32C2 ") ); + + res = std::format(loc, WIDEN("{:^4L%Om}"), std::chrono::April); + VERIFY( res == WIDEN(" \u32C3 ") ); + + res = std::format(loc, WIDEN("{:>5L%Om}"), std::chrono::May); + VERIFY( res == WIDEN(" \u32C4") ); + + res = std::format(loc, WIDEN("{:+<6L%Om}"), std::chrono::June); + VERIFY( res == WIDEN("\u32C5++++") ); + + res = std::format(loc, WIDEN("{:=^7L%Om}"), std::chrono::July); + VERIFY( res == WIDEN("==\u32C6===") ); + + res = std::format(loc, WIDEN("{:->8L%Om}"), std::chrono::August); + VERIFY( res == WIDEN("------\u32C7") ); +} + +int main() +{ + test_from_format_string<char>(); + test_from_format_string<wchar_t>(); + test_formatted_value<char>(); + test_formatted_value<wchar_t>(); +} diff --git a/libstdc++-v3/testsuite/std/time/format/pr120481.cc b/libstdc++-v3/testsuite/std/time/format/pr120481.cc new file mode 100644 index 0000000..a748acb --- /dev/null +++ b/libstdc++-v3/testsuite/std/time/format/pr120481.cc @@ -0,0 +1,324 @@ +// { dg-do run { target c++23 } } +// { dg-options "-fexec-charset=UTF-8" } +// { dg-timeout-factor 2 } + +#include <algorithm> +#include <chrono> +#include <testsuite_hooks.h> + +#define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S) +#define WIDEN(S) WIDEN_(CharT, S) + +using namespace std::chrono; + +template<typename CharT> +void +test_year() +{ + std::basic_string<CharT> res; + + res = std::format(WIDEN("{:%Y}"), year(0)); + VERIFY( res == WIDEN("0000") ); + res = std::format(WIDEN("{:%C}"), year(0)); + VERIFY( res == WIDEN("00") ); + res = std::format(WIDEN("{:%y}"), year(0)); + VERIFY( res == WIDEN("00") ); + + res = std::format(WIDEN("{:%Y}"), year(5)); + VERIFY( res == WIDEN("0005") ); + res = std::format(WIDEN("{:%C}"), year(5)); + VERIFY( res == WIDEN("00") ); + res = std::format(WIDEN("{:%y}"), year(5)); + VERIFY( res == WIDEN("05") ); + res = std::format(WIDEN("{:%Y}"), year(-5)); + VERIFY( res == WIDEN("-0005") ); + res = std::format(WIDEN("{:%C}"), year(-5)); + VERIFY( res == WIDEN("-01") ); + res = std::format(WIDEN("{:%y}"), year(-5)); + VERIFY( res == WIDEN("05") ); + + res = std::format(WIDEN("{:%Y}"), year(213)); + VERIFY( res == WIDEN("0213") ); + res = std::format(WIDEN("{:%C}"), year(213)); + VERIFY( res == WIDEN("02") ); + res = std::format(WIDEN("{:%y}"), year(213)); + VERIFY( res == WIDEN("13") ); + res = std::format(WIDEN("{:%Y}"), year(-213)); + VERIFY( res == WIDEN("-0213") ); + res = std::format(WIDEN("{:%C}"), year(-213)); + VERIFY( res == WIDEN("-03") ); + res = std::format(WIDEN("{:%y}"), year(-213)); + VERIFY( res == WIDEN("13") ); + + res = std::format(WIDEN("{:%Y}"), year(7100)); + VERIFY( res == WIDEN("7100") ); + res = std::format(WIDEN("{:%C}"), year(7100)); + VERIFY( res == WIDEN("71") ); + res = std::format(WIDEN("{:%y}"), year(7100)); + VERIFY( res == WIDEN("00") ); + res = std::format(WIDEN("{:%Y}"), year(-7100)); + VERIFY( res == WIDEN("-7100") ); + res = std::format(WIDEN("{:%C}"), year(-7100)); + VERIFY( res == WIDEN("-71") ); + res = std::format(WIDEN("{:%y}"), year(-7100)); + VERIFY( res == WIDEN("00") ); + + res = std::format(WIDEN("{:%Y}"), year(12101)); + VERIFY( res == WIDEN("12101") ); + res = std::format(WIDEN("{:%C}"), year(12101)); + VERIFY( res == WIDEN("121") ); + res = std::format(WIDEN("{:%y}"), year(12101)); + VERIFY( res == WIDEN("01") ); + res = std::format(WIDEN("{:%Y}"), year(-12101)); + VERIFY( res == WIDEN("-12101") ); + res = std::format(WIDEN("{:%C}"), year(-12101)); + VERIFY( res == WIDEN("-122") ); + res = std::format(WIDEN("{:%y}"), year(-12101)); + VERIFY( res == WIDEN("01") ); +} + +template<typename CharT> +void +test_month() +{ + std::basic_string<CharT> res; + + res = std::format(WIDEN("{:%m}"), month(5)); + VERIFY( res == WIDEN("05") ); + res = std::format(WIDEN("{:%m}"), month(50)); + VERIFY( res == WIDEN("50") ); + res = std::format(WIDEN("{:%m}"), month(127)); + VERIFY( res == WIDEN("127") ); + res = std::format(WIDEN("{:%m}"), month(254)); + VERIFY( res == WIDEN("254") ); +} + +template<typename CharT> +void +test_day() +{ + std::basic_string<CharT> res; + + res = std::format(WIDEN("{:%d}"), day(3)); + VERIFY( res == WIDEN("03") ); + res = std::format(WIDEN("{:%d}"), day(22)); + VERIFY( res == WIDEN("22") ); + res = std::format(WIDEN("{:%d}"), day(100)); + VERIFY( res == WIDEN("100") ); + res = std::format(WIDEN("{:%d}"), day(207)); + VERIFY( res == WIDEN("207") ); + + res = std::format(WIDEN("{:%e}"), day(5)); + VERIFY( res == WIDEN(" 5") ); + res = std::format(WIDEN("{:%e}"), day(99)); + VERIFY( res == WIDEN("99") ); + res = std::format(WIDEN("{:%e}"), day(183)); + VERIFY( res == WIDEN("183") ); + res = std::format(WIDEN("{:%e}"), day(214)); + VERIFY( res == WIDEN("214") ); +} + +template<typename CharT> +void +test_date() +{ + std::basic_string<CharT> res; + + res = std::format(WIDEN("{:%F}"), year(-22)/month(10)/day(20)); + VERIFY( res == WIDEN("-0022-10-20") ); + res = std::format(WIDEN("{:%D}"), year(-22)/month(10)/day(20)); + VERIFY( res == WIDEN("10/20/22") ); + + res = std::format(WIDEN("{:%F}"), year(-2020)/month(123)/day(44)); + VERIFY( res == WIDEN("-2020-123-44") ); + res = std::format(WIDEN("{:%D}"), year(-2020)/month(123)/day(44)); + VERIFY( res == WIDEN("123/44/20") ); + + res = std::format(WIDEN("{:%F}"), year(-23404)/month(99)/day(223)); + VERIFY( res == WIDEN("-23404-99-223") ); + res = std::format(WIDEN("{:%D}"), year(-23404)/month(99)/day(223)); + VERIFY( res == WIDEN("99/223/04") ); + + res = std::format(WIDEN("{:%F}"), year(10000)/month(220)/day(100)); + VERIFY( res == WIDEN("10000-220-100") ); + res = std::format(WIDEN("{:%D}"), year(10000)/month(220)/day(100)); + VERIFY( res == WIDEN("220/100/00") ); +} + +template<typename CharT> +void +test_weekday() +{ + std::basic_string<CharT> res; + + res = std::format(WIDEN("{:%w}"), weekday(0)); + VERIFY( res == WIDEN("0") ); + res = std::format(WIDEN("{:%u}"), weekday(0)); + VERIFY( res == WIDEN("7") ); + + res = std::format(WIDEN("{:%w}"), weekday(7)); + VERIFY( res == WIDEN("0") ); + res = std::format(WIDEN("{:%u}"), weekday(7)); + VERIFY( res == WIDEN("7") ); + + res = std::format(WIDEN("{:%w}"), weekday(8)); + VERIFY( res == WIDEN("8") ); + res = std::format(WIDEN("{:%u}"), weekday(8)); + VERIFY( res == WIDEN("8") ); + + res = std::format(WIDEN("{:%w}"), weekday(10)); + VERIFY( res == WIDEN("10") ); + res = std::format(WIDEN("{:%u}"), weekday(10)); + VERIFY( res == WIDEN("10") ); + + res = std::format(WIDEN("{:%w}"), weekday(76)); + VERIFY( res == WIDEN("76") ); + res = std::format(WIDEN("{:%u}"), weekday(76)); + VERIFY( res == WIDEN("76") ); + + res = std::format(WIDEN("{:%w}"), weekday(100)); + VERIFY( res == WIDEN("100") ); + res = std::format(WIDEN("{:%u}"), weekday(100)); + VERIFY( res == WIDEN("100") ); + + res = std::format(WIDEN("{:%w}"), weekday(202)); + VERIFY( res == WIDEN("202") ); + res = std::format(WIDEN("{:%u}"), weekday(202)); + VERIFY( res == WIDEN("202") ); +} + +template<typename CharT> +void +test_hour() +{ + std::basic_string<CharT> res; + + res = std::format(WIDEN("{:%H}"), 0h + 5min + 6s); + VERIFY( res == WIDEN("00") ); + res = std::format(WIDEN("{:%R}"), 0h + 5min + 6s); + VERIFY( res == WIDEN("00:05") ); + res = std::format(WIDEN("{:%T}"), 0h + 5min + 6s); + VERIFY( res == WIDEN("00:05:06") ); + res = std::format(WIDEN("{:%I}"), 0h + 5min + 6s); + VERIFY( res == WIDEN("12") ); + res = std::format(WIDEN("{:%p}"), 0h + 5min + 6s); + VERIFY( res == WIDEN("AM") ); + + res = std::format(WIDEN("{:%H}"), 7h + 15min + 6s); + VERIFY( res == WIDEN("07") ); + res = std::format(WIDEN("{:%R}"), 7h + 15min + 6s); + VERIFY( res == WIDEN("07:15") ); + res = std::format(WIDEN("{:%T}"), 7h + 15min + 6s); + VERIFY( res == WIDEN("07:15:06") ); + res = std::format(WIDEN("{:%I}"), 7h + 15min + 6s); + VERIFY( res == WIDEN("07") ); + res = std::format(WIDEN("{:%p}"), 7h + 15min + 6s); + VERIFY( res == WIDEN("AM") ); + + res = std::format(WIDEN("{:%H}"), 15h + 55min + 26s); + VERIFY( res == WIDEN("15") ); + res = std::format(WIDEN("{:%R}"), 15h + 55min + 26s); + VERIFY( res == WIDEN("15:55") ); + res = std::format(WIDEN("{:%T}"), 15h + 55min + 26s); + VERIFY( res == WIDEN("15:55:26") ); + res = std::format(WIDEN("{:%I}"), 15h + 55min + 26s); + VERIFY( res == WIDEN("03") ); + res = std::format(WIDEN("{:%p}"), 15h + 55min + 26s); + VERIFY( res == WIDEN("PM") ); + + res = std::format(WIDEN("{:%H}"), 50h + 33min + 37s); + VERIFY( res == WIDEN("50") ); + res = std::format(WIDEN("{:%R}"), 50h + 33min + 37s); + VERIFY( res == WIDEN("50:33") ); + res = std::format(WIDEN("{:%T}"), 50h + 33min + 37s); + VERIFY( res == WIDEN("50:33:37") ); + res = std::format(WIDEN("{:%I}"), 50h + 33min + 37s); + VERIFY( res == WIDEN("02") ); + res = std::format(WIDEN("{:%p}"), 50h + 33min + 37s); + VERIFY( res == WIDEN("AM") ); + + res = std::format(WIDEN("{:%H}"), 100h + 21min + 48s); + VERIFY( res == WIDEN("100") ); + res = std::format(WIDEN("{:%R}"), 100h + 21min + 48s); + VERIFY( res == WIDEN("100:21") ); + res = std::format(WIDEN("{:%T}"), 100h + 21min + 48s); + VERIFY( res == WIDEN("100:21:48") ); + res = std::format(WIDEN("{:%I}"), 100h + 21min + 48s); + VERIFY( res == WIDEN("04") ); + res = std::format(WIDEN("{:%p}"), 100h + 21min + 48s); + VERIFY( res == WIDEN("AM") ); + + res = std::format(WIDEN("{:%H}"), 228h + 45min + 33s); + VERIFY( res == WIDEN("228") ); + res = std::format(WIDEN("{:%R}"), 228h + 45min + 33s); + VERIFY( res == WIDEN("228:45") ); + res = std::format(WIDEN("{:%T}"), 228h + 45min + 33s); + VERIFY( res == WIDEN("228:45:33") ); + res = std::format(WIDEN("{:%I}"), 228h + 4min + 33s); + VERIFY( res == WIDEN("12") ); + res = std::format(WIDEN("{:%p}"), 228h + 4min + 33s); + VERIFY( res == WIDEN("PM") ); + + res = std::format(WIDEN("{:%H}"), 1024h + 3min); + VERIFY( res == WIDEN("1024") ); + res = std::format(WIDEN("{:%R}"), 1024h + 3min); + VERIFY( res == WIDEN("1024:03") ); + res = std::format(WIDEN("{:%T}"), 1024h + 3min); + VERIFY( res == WIDEN("1024:03:00") ); + res = std::format(WIDEN("{:%I}"), 1024h + 3min); + VERIFY( res == WIDEN("04") ); + res = std::format(WIDEN("{:%p}"), 1024h + 3min); + VERIFY( res == WIDEN("PM") ); + + res = std::format(WIDEN("{:%H}"), 2039h); + VERIFY( res == WIDEN("2039") ); + res = std::format(WIDEN("{:%R}"), 2039h); + VERIFY( res == WIDEN("2039:00") ); + res = std::format(WIDEN("{:%T}"), 2039h); + VERIFY( res == WIDEN("2039:00:00") ); + res = std::format(WIDEN("{:%I}"), 2039h); + VERIFY( res == WIDEN("11") ); + res = std::format(WIDEN("{:%p}"), 2039h); + VERIFY( res == WIDEN("PM") ); + + res = std::format(WIDEN("{:%H}"), 22111h + 59min + 59s); + VERIFY( res == WIDEN("22111") ); + res = std::format(WIDEN("{:%R}"), 22111h + 59min + 59s); + VERIFY( res == WIDEN("22111:59") ); + res = std::format(WIDEN("{:%T}"), 22111h + 59min + 59s); + VERIFY( res == WIDEN("22111:59:59") ); + res = std::format(WIDEN("{:%I}"), 22111h + 59min + 59s); + VERIFY( res == WIDEN("07") ); + res = std::format(WIDEN("{:%p}"), 22111h + 59min + 59s); + VERIFY( res == WIDEN("AM") ); + + res = std::format(WIDEN("{:%H}"), -22111h - 59min - 59s); + VERIFY( res == WIDEN("-22111") ); + res = std::format(WIDEN("{:%R}"), -22111h - 59min - 59s); + VERIFY( res == WIDEN("-22111:59") ); + res = std::format(WIDEN("{:%T}"), -22111h - 59min - 59s); + VERIFY( res == WIDEN("-22111:59:59") ); + res = std::format(WIDEN("{:%I}"), -22111h - 59min - 59s); + VERIFY( res == WIDEN("-07") ); + res = std::format(WIDEN("{:%p}"), -22111h - 59min - 59s); + VERIFY( res == WIDEN("AM") ); +} + +int main() +{ + test_year<char>(); + test_month<char>(); + test_day<char>(); + test_date<char>(); + test_weekday<char>(); + test_hour<char>(); + +#ifdef _GLIBCXX_USE_WCHAR_T + test_year<wchar_t>(); + test_month<wchar_t>(); + test_day<wchar_t>(); + test_date<wchar_t>(); + test_weekday<wchar_t>(); + test_hour<wchar_t>(); +#endif // _GLIBCXX_USE_WCHAR_T +} diff --git a/libstdc++-v3/testsuite/std/time/format/precision.cc b/libstdc++-v3/testsuite/std/time/format/precision.cc new file mode 100644 index 0000000..aa26615 --- /dev/null +++ b/libstdc++-v3/testsuite/std/time/format/precision.cc @@ -0,0 +1,201 @@ +// { dg-do run { target c++20 } } + +#include <chrono> +#include <ranges> +#include <testsuite_hooks.h> + +using namespace std::chrono; + +#define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S) +#define WIDEN(S) WIDEN_(CharT, S) + +template<typename CharT> +void +test_empty() +{ + std::basic_string<CharT> res; + + const duration<double> d(33.111222); + res = std::format(WIDEN("{:}"), d); + VERIFY( res == WIDEN("33.1112s") ); + res = std::format(WIDEN("{:.0}"), d); + VERIFY( res == WIDEN("33.1112s") ); + res = std::format(WIDEN("{:.3}"), d); + VERIFY( res == WIDEN("33.1112s") ); + res = std::format(WIDEN("{:.6}"), d); + VERIFY( res == WIDEN("33.1112s") ); + res = std::format(WIDEN("{:.9}"), d); + VERIFY( res == WIDEN("33.1112s") ); + + // Uses ostream operator<< + const duration<double, std::nano> nd = d; + res = std::format(WIDEN("{:}"), nd); + VERIFY( res == WIDEN("3.31112e+10ns") ); + res = std::format(WIDEN("{:.0}"), nd); + VERIFY( res == WIDEN("3.31112e+10ns") ); + res = std::format(WIDEN("{:.3}"), nd); + VERIFY( res == WIDEN("3.31112e+10ns") ); + res = std::format(WIDEN("{:.6}"), nd); + VERIFY( res == WIDEN("3.31112e+10ns") ); + res = std::format(WIDEN("{:.9}"), nd); + VERIFY( res == WIDEN("3.31112e+10ns") ); +} + +template<typename CharT> +void +test_Q() +{ + std::basic_string<CharT> res; + + const duration<double> d(7.111222); + res = std::format(WIDEN("{:%Q}"), d); + VERIFY( res == WIDEN("7.111222") ); + res = std::format(WIDEN("{:.0%Q}"), d); + VERIFY( res == WIDEN("7.111222") ); + res = std::format(WIDEN("{:.3%Q}"), d); + VERIFY( res == WIDEN("7.111222") ); + res = std::format(WIDEN("{:.6%Q}"), d); + VERIFY( res == WIDEN("7.111222") ); + res = std::format(WIDEN("{:.9%Q}"), d); + VERIFY( res == WIDEN("7.111222") ); + + duration<double, std::milli> md = d; + res = std::format(WIDEN("{:%Q}"), md); + VERIFY( res == WIDEN("7111.222") ); + res = std::format(WIDEN("{:.0%Q}"), md); + VERIFY( res == WIDEN("7111.222") ); + res = std::format(WIDEN("{:.3%Q}"), md); + VERIFY( res == WIDEN("7111.222") ); + res = std::format(WIDEN("{:.6%Q}"), md); + VERIFY( res == WIDEN("7111.222") ); + res = std::format(WIDEN("{:.9%Q}"), md); + VERIFY( res == WIDEN("7111.222") ); + + const duration<double, std::nano> nd = d; + res = std::format(WIDEN("{:%Q}"), nd); + VERIFY( res == WIDEN("7111222000") ); + res = std::format(WIDEN("{:.0%Q}"), nd); + VERIFY( res == WIDEN("7111222000") ); + res = std::format(WIDEN("{:.3%Q}"), nd); + VERIFY( res == WIDEN("7111222000") ); + res = std::format(WIDEN("{:.6%Q}"), nd); + VERIFY( res == WIDEN("7111222000") ); + res = std::format(WIDEN("{:.9%Q}"), nd); + VERIFY( res == WIDEN("7111222000") ); +} + +template<typename CharT> +void +test_S_fp() +{ + std::basic_string<CharT> res; + + // Precision is ignored, but period affects output + duration<double> d(5.111222); + res = std::format(WIDEN("{:%S}"), d); + VERIFY( res == WIDEN("05") ); + res = std::format(WIDEN("{:.0%S}"), d); + VERIFY( res == WIDEN("05") ); + res = std::format(WIDEN("{:.3%S}"), d); + VERIFY( res == WIDEN("05") ); + res = std::format(WIDEN("{:.6%S}"), d); + VERIFY( res == WIDEN("05") ); + res = std::format(WIDEN("{:.9%S}"), d); + VERIFY( res == WIDEN("05") ); + + duration<double, std::milli> md = d; + res = std::format(WIDEN("{:%S}"), md); + VERIFY( res == WIDEN("05.111") ); + res = std::format(WIDEN("{:.0%S}"), md); + VERIFY( res == WIDEN("05.111") ); + res = std::format(WIDEN("{:.3%S}"), md); + VERIFY( res == WIDEN("05.111") ); + res = std::format(WIDEN("{:.6%S}"), md); + VERIFY( res == WIDEN("05.111") ); + res = std::format(WIDEN("{:.9%S}"), md); + VERIFY( res == WIDEN("05.111") ); + + duration<double, std::micro> ud = d; + res = std::format(WIDEN("{:%S}"), ud); + VERIFY( res == WIDEN("05.111222") ); + res = std::format(WIDEN("{:.0%S}"), ud); + VERIFY( res == WIDEN("05.111222") ); + res = std::format(WIDEN("{:.3%S}"), ud); + VERIFY( res == WIDEN("05.111222") ); + res = std::format(WIDEN("{:.6%S}"), ud); + VERIFY( res == WIDEN("05.111222") ); + res = std::format(WIDEN("{:.9%S}"), ud); + VERIFY( res == WIDEN("05.111222") ); + + duration<double, std::nano> nd = d; + res = std::format(WIDEN("{:%S}"), nd); + VERIFY( res == WIDEN("05.111222000") ); + res = std::format(WIDEN("{:.0%S}"), nd); + VERIFY( res == WIDEN("05.111222000") ); + res = std::format(WIDEN("{:.3%S}"), nd); + VERIFY( res == WIDEN("05.111222000") ); + res = std::format(WIDEN("{:.6%S}"), nd); + VERIFY( res == WIDEN("05.111222000") ); + res = std::format(WIDEN("{:.9%S}"), nd); + VERIFY( res == WIDEN("05.111222000") ); + + duration<double, std::pico> pd = d; + res = std::format(WIDEN("{:%S}"), pd); + VERIFY( res == WIDEN("05.111222000000") ); + res = std::format(WIDEN("{:.0%S}"), pd); + VERIFY( res == WIDEN("05.111222000000") ); + res = std::format(WIDEN("{:.3%S}"), pd); + VERIFY( res == WIDEN("05.111222000000") ); + res = std::format(WIDEN("{:.6%S}"), pd); + VERIFY( res == WIDEN("05.111222000000") ); + res = std::format(WIDEN("{:.9%S}"), pd); + VERIFY( res == WIDEN("05.111222000000") ); +} + +template<typename CharT> +void +test_S_int() +{ + std::basic_string<CharT> res; + const nanoseconds src(7'000'012'345); + + auto d = floor<seconds>(src); + res = std::format(WIDEN("{:%S}"), d); + VERIFY( res == WIDEN("07") ); + + auto md = floor<milliseconds>(src); + res = std::format(WIDEN("{:%S}"), md); + VERIFY( res == WIDEN("07.000") ); + + auto ud = floor<microseconds>(src); + res = std::format(WIDEN("{:%S}"), ud); + VERIFY( res == WIDEN("07.000012") ); + + auto nd = floor<nanoseconds>(src); + res = std::format(WIDEN("{:%S}"), nd); + VERIFY( res == WIDEN("07.000012345") ); + + using picoseconds = duration<unsigned long long, std::pico>; + auto pd = floor<picoseconds>(src); + res = std::format(WIDEN("{:%S}"), pd); + VERIFY( res == WIDEN("07.000012345000") ); +} + +template<typename CharT> +void +test_all() +{ + test_empty<CharT>(); + test_Q<CharT>(); + test_S_int<CharT>(); + test_S_fp<CharT>(); +} + +int main() +{ + test_all<char>(); + +#ifdef _GLIBCXX_USE_WCHAR_T + test_all<wchar_t>(); +#endif // _GLIBCXX_USE_WCHAR_T +} diff --git a/libstdc++-v3/testsuite/std/time/format/whitespace.cc b/libstdc++-v3/testsuite/std/time/format/whitespace.cc new file mode 100644 index 0000000..debda08 --- /dev/null +++ b/libstdc++-v3/testsuite/std/time/format/whitespace.cc @@ -0,0 +1,56 @@ +// { dg-do run { target c++20 } } + +#include <chrono> +#include <testsuite_hooks.h> + +using namespace std::chrono; + +#define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S) +#define WIDEN(S) WIDEN_(_CharT, S) + +template<typename _CharT, typename ChronoType> +void +test(const ChronoType& ct) +{ + std::basic_string<_CharT> res; + + res = std::format(WIDEN("{:%% %t %n more text}"), ct); + VERIFY( res == WIDEN("% \t \n more text") ); + + res = std::format(WIDEN("{:7%% %t %n}"), ct); + VERIFY( res == WIDEN("% \t \n ") ); + + res = std::format(WIDEN("{:>6%% %t %n}"), ct); + VERIFY( res == WIDEN(" % \t \n") ); + + res = std::format(WIDEN("{:+>7%% %t %n}"), ct); + VERIFY( res == WIDEN("++% \t \n") ); + + res = std::format(WIDEN("{:=^7%% %t %n}"), ct); + VERIFY( res == WIDEN("=% \t \n=") ); +} + +template<typename CharT> +void +test_all() +{ + test<CharT>(20s); + test<CharT>(10d); + test<CharT>(Monday); + test<CharT>(2020y/January/8); + test<CharT>(local_days(2020y/January/8)); + test<CharT>(sys_days(2020y/January/8) + 13h + 10min + 5s); +#if _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI + test<CharT>(sys_info()); + test<CharT>(local_info()); +#endif +} + +int main() +{ + test_all<char>(); + +#ifdef _GLIBCXX_USE_WCHAR_T + test_all<wchar_t>(); +#endif // _GLIBCXX_USE_WCHAR_T +} diff --git a/libstdc++-v3/testsuite/tr1/2_general_utilities/shared_ptr/cons/43820_neg.cc b/libstdc++-v3/testsuite/tr1/2_general_utilities/shared_ptr/cons/43820_neg.cc index 7b5ede4..03fad14 100644 --- a/libstdc++-v3/testsuite/tr1/2_general_utilities/shared_ptr/cons/43820_neg.cc +++ b/libstdc++-v3/testsuite/tr1/2_general_utilities/shared_ptr/cons/43820_neg.cc @@ -39,9 +39,6 @@ void test01() // { dg-error "incomplete" "" { target *-*-* } 600 } } -// { dg-error "-Wdelete-incomplete" "" { target c++26 } 283 } -// { dg-error "-Wdelete-incomplete" "" { target c++26 } 305 } - // Ignore additional diagnostic given with -Wsystem-headers: // { dg-prune-output "has incomplete type" } // { dg-prune-output "possible problem detected" } diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/01_assoc_laguerre/check_value.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/01_assoc_laguerre/check_value.cc index 1ae8371..77e7648 100644 --- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/01_assoc_laguerre/check_value.cc +++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/01_assoc_laguerre/check_value.cc @@ -2217,7 +2217,6 @@ template<typename Ret, unsigned int Num> void test(const testcase_assoc_laguerre<Ret> (&data)[Num], Ret toler) { - bool test __attribute__((unused)) = true; const Ret eps = std::numeric_limits<Ret>::epsilon(); Ret max_abs_diff = -Ret(1); Ret max_abs_frac = -Ret(1); diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/02_assoc_legendre/check_value.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/02_assoc_legendre/check_value.cc index 023f09d..a30700b 100644 --- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/02_assoc_legendre/check_value.cc +++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/02_assoc_legendre/check_value.cc @@ -1985,7 +1985,6 @@ template<typename Ret, unsigned int Num> void test(const testcase_assoc_legendre<Ret> (&data)[Num], Ret toler) { - bool test __attribute__((unused)) = true; const Ret eps = std::numeric_limits<Ret>::epsilon(); Ret max_abs_diff = -Ret(1); Ret max_abs_frac = -Ret(1); diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/02_assoc_legendre/pr86655.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/02_assoc_legendre/pr86655.cc index 7f7e3a4..ec99b60 100644 --- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/02_assoc_legendre/pr86655.cc +++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/02_assoc_legendre/pr86655.cc @@ -36,7 +36,6 @@ template<typename _Tp> void test_m_gt_l() { - bool test __attribute__((unused)) = true; unsigned int larr[4] = {0u, 1u, 2u, 5u}; for (unsigned int l = 0; l < 4; ++l) for (unsigned int m = larr[l] + 1u; m <= larr[l] + 2u; ++m) diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/03_beta/check_value.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/03_beta/check_value.cc index f61438d..2dcdcbc 100644 --- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/03_beta/check_value.cc +++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/03_beta/check_value.cc @@ -261,7 +261,6 @@ template<typename Ret, unsigned int Num> void test(const testcase_beta<Ret> (&data)[Num], Ret toler) { - bool test __attribute__((unused)) = true; const Ret eps = std::numeric_limits<Ret>::epsilon(); Ret max_abs_diff = -Ret(1); Ret max_abs_frac = -Ret(1); diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/04_comp_ellint_1/check_value.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/04_comp_ellint_1/check_value.cc index 76240db..7faffe8 100644 --- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/04_comp_ellint_1/check_value.cc +++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/04_comp_ellint_1/check_value.cc @@ -73,7 +73,6 @@ template<typename Ret, unsigned int Num> void test(const testcase_comp_ellint_1<Ret> (&data)[Num], Ret toler) { - bool test __attribute__((unused)) = true; const Ret eps = std::numeric_limits<Ret>::epsilon(); Ret max_abs_diff = -Ret(1); Ret max_abs_frac = -Ret(1); diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/05_comp_ellint_2/check_value.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/05_comp_ellint_2/check_value.cc index b46a140..60adcb1 100644 --- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/05_comp_ellint_2/check_value.cc +++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/05_comp_ellint_2/check_value.cc @@ -73,7 +73,6 @@ template<typename Ret, unsigned int Num> void test(const testcase_comp_ellint_2<Ret> (&data)[Num], Ret toler) { - bool test __attribute__((unused)) = true; const Ret eps = std::numeric_limits<Ret>::epsilon(); Ret max_abs_diff = -Ret(1); Ret max_abs_frac = -Ret(1); diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/06_comp_ellint_3/check_value.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/06_comp_ellint_3/check_value.cc index aba5284..34f5956 100644 --- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/06_comp_ellint_3/check_value.cc +++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/06_comp_ellint_3/check_value.cc @@ -459,7 +459,6 @@ template<typename Ret, unsigned int Num> void test(const testcase_comp_ellint_3<Ret> (&data)[Num], Ret toler) { - bool test __attribute__((unused)) = true; const Ret eps = std::numeric_limits<Ret>::epsilon(); Ret max_abs_diff = -Ret(1); Ret max_abs_frac = -Ret(1); diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/07_conf_hyperg/check_value.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/07_conf_hyperg/check_value.cc index 5b10ea4..1cd2733 100644 --- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/07_conf_hyperg/check_value.cc +++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/07_conf_hyperg/check_value.cc @@ -3819,7 +3819,6 @@ template<typename Ret, unsigned int Num> void test(const testcase_conf_hyperg<Ret> (&data)[Num], Ret toler) { - bool test __attribute__((unused)) = true; const Ret eps = std::numeric_limits<Ret>::epsilon(); Ret max_abs_diff = -Ret(1); Ret max_abs_frac = -Ret(1); diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/08_cyl_bessel_i/check_value.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/08_cyl_bessel_i/check_value.cc index cb4b3960..02df6ba 100644 --- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/08_cyl_bessel_i/check_value.cc +++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/08_cyl_bessel_i/check_value.cc @@ -702,7 +702,6 @@ template<typename Ret, unsigned int Num> void test(const testcase_cyl_bessel_i<Ret> (&data)[Num], Ret toler) { - bool test __attribute__((unused)) = true; const Ret eps = std::numeric_limits<Ret>::epsilon(); Ret max_abs_diff = -Ret(1); Ret max_abs_frac = -Ret(1); diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/09_cyl_bessel_j/check_value.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/09_cyl_bessel_j/check_value.cc index 689880d..f3b7fa6 100644 --- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/09_cyl_bessel_j/check_value.cc +++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/09_cyl_bessel_j/check_value.cc @@ -735,7 +735,6 @@ template<typename Ret, unsigned int Num> void test(const testcase_cyl_bessel_j<Ret> (&data)[Num], Ret toler) { - bool test __attribute__((unused)) = true; const Ret eps = std::numeric_limits<Ret>::epsilon(); Ret max_abs_diff = -Ret(1); Ret max_abs_frac = -Ret(1); diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/10_cyl_bessel_k/check_value.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/10_cyl_bessel_k/check_value.cc index a408c3f..10b8092 100644 --- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/10_cyl_bessel_k/check_value.cc +++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/10_cyl_bessel_k/check_value.cc @@ -746,7 +746,6 @@ template<typename Ret, unsigned int Num> void test(const testcase_cyl_bessel_k<Ret> (&data)[Num], Ret toler) { - bool test __attribute__((unused)) = true; const Ret eps = std::numeric_limits<Ret>::epsilon(); Ret max_abs_diff = -Ret(1); Ret max_abs_frac = -Ret(1); diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/11_cyl_neumann/check_value.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/11_cyl_neumann/check_value.cc index 868d278..c365bb5 100644 --- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/11_cyl_neumann/check_value.cc +++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/11_cyl_neumann/check_value.cc @@ -779,7 +779,6 @@ template<typename Ret, unsigned int Num> void test(const testcase_cyl_neumann<Ret> (&data)[Num], Ret toler) { - bool test __attribute__((unused)) = true; const Ret eps = std::numeric_limits<Ret>::epsilon(); Ret max_abs_diff = -Ret(1); Ret max_abs_frac = -Ret(1); diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/12_ellint_1/check_value.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/12_ellint_1/check_value.cc index 2ca367f..acb217d 100644 --- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/12_ellint_1/check_value.cc +++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/12_ellint_1/check_value.cc @@ -459,7 +459,6 @@ template<typename Ret, unsigned int Num> void test(const testcase_ellint_1<Ret> (&data)[Num], Ret toler) { - bool test __attribute__((unused)) = true; const Ret eps = std::numeric_limits<Ret>::epsilon(); Ret max_abs_diff = -Ret(1); Ret max_abs_frac = -Ret(1); diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/13_ellint_2/check_value.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/13_ellint_2/check_value.cc index d9e0f7f..7bb33b5 100644 --- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/13_ellint_2/check_value.cc +++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/13_ellint_2/check_value.cc @@ -459,7 +459,6 @@ template<typename Ret, unsigned int Num> void test(const testcase_ellint_2<Ret> (&data)[Num], Ret toler) { - bool test __attribute__((unused)) = true; const Ret eps = std::numeric_limits<Ret>::epsilon(); Ret max_abs_diff = -Ret(1); Ret max_abs_frac = -Ret(1); diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/14_ellint_3/check_value.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/14_ellint_3/check_value.cc index 2da68ab..df624a0 100644 --- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/14_ellint_3/check_value.cc +++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/14_ellint_3/check_value.cc @@ -6121,7 +6121,6 @@ template<typename Ret, unsigned int Num> void test(const testcase_ellint_3<Ret> (&data)[Num], Ret toler) { - bool test __attribute__((unused)) = true; const Ret eps = std::numeric_limits<Ret>::epsilon(); Ret max_abs_diff = -Ret(1); Ret max_abs_frac = -Ret(1); diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/15_expint/check_value_neg.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/15_expint/check_value_neg.cc index 33d95c9..64f7685 100644 --- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/15_expint/check_value_neg.cc +++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/15_expint/check_value_neg.cc @@ -168,7 +168,6 @@ template<typename Ret, unsigned int Num> void test(const testcase_expint<Ret> (&data)[Num], Ret toler) { - bool test __attribute__((unused)) = true; const Ret eps = std::numeric_limits<Ret>::epsilon(); Ret max_abs_diff = -Ret(1); Ret max_abs_frac = -Ret(1); diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/16_hermite/check_value.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/16_hermite/check_value.cc index 8afbcdd..0676f62 100644 --- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/16_hermite/check_value.cc +++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/16_hermite/check_value.cc @@ -1904,7 +1904,6 @@ template<typename Ret, unsigned int Num> void test(const testcase_hermite<Ret> (&data)[Num], Ret toler) { - bool test __attribute__((unused)) = true; const Ret eps = std::numeric_limits<Ret>::epsilon(); Ret max_abs_diff = -Ret(1); Ret max_abs_frac = -Ret(1); diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/17_hyperg/check_value.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/17_hyperg/check_value.cc index c77dc3d..b83994e 100644 --- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/17_hyperg/check_value.cc +++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/17_hyperg/check_value.cc @@ -12292,7 +12292,6 @@ template<typename Ret, unsigned int Num> void test(const testcase_hyperg<Ret> (&data)[Num], Ret toler) { - bool test __attribute__((unused)) = true; const Ret eps = std::numeric_limits<Ret>::epsilon(); Ret max_abs_diff = -Ret(1); Ret max_abs_frac = -Ret(1); diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/18_laguerre/check_value.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/18_laguerre/check_value.cc index 60d6af0..2fee8e4 100644 --- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/18_laguerre/check_value.cc +++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/18_laguerre/check_value.cc @@ -305,7 +305,6 @@ template<typename Ret, unsigned int Num> void test(const testcase_laguerre<Ret> (&data)[Num], Ret toler) { - bool test __attribute__((unused)) = true; const Ret eps = std::numeric_limits<Ret>::epsilon(); Ret max_abs_diff = -Ret(1); Ret max_abs_frac = -Ret(1); diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/19_legendre/check_value.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/19_legendre/check_value.cc index 19f096d..325ae0d 100644 --- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/19_legendre/check_value.cc +++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/19_legendre/check_value.cc @@ -305,7 +305,6 @@ template<typename Ret, unsigned int Num> void test(const testcase_legendre<Ret> (&data)[Num], Ret toler) { - bool test __attribute__((unused)) = true; const Ret eps = std::numeric_limits<Ret>::epsilon(); Ret max_abs_diff = -Ret(1); Ret max_abs_frac = -Ret(1); diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/20_riemann_zeta/check_value_neg.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/20_riemann_zeta/check_value_neg.cc index 658faa7..cbbccdf 100644 --- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/20_riemann_zeta/check_value_neg.cc +++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/20_riemann_zeta/check_value_neg.cc @@ -273,7 +273,6 @@ template<typename Ret, unsigned int Num> void test(const testcase_riemann_zeta<Ret> (&data)[Num], Ret toler) { - bool test __attribute__((unused)) = true; const Ret eps = std::numeric_limits<Ret>::epsilon(); Ret max_abs_diff = -Ret(1); Ret max_abs_frac = -Ret(1); diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/21_sph_bessel/check_value.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/21_sph_bessel/check_value.cc index 5863f9a..f2ef94b 100644 --- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/21_sph_bessel/check_value.cc +++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/21_sph_bessel/check_value.cc @@ -504,7 +504,6 @@ template<typename Ret, unsigned int Num> void test(const testcase_sph_bessel<Ret> (&data)[Num], Ret toler) { - bool test __attribute__((unused)) = true; const Ret eps = std::numeric_limits<Ret>::epsilon(); Ret max_abs_diff = -Ret(1); Ret max_abs_frac = -Ret(1); diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/22_sph_legendre/check_value.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/22_sph_legendre/check_value.cc index 910485f..1e178a6 100644 --- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/22_sph_legendre/check_value.cc +++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/22_sph_legendre/check_value.cc @@ -1985,7 +1985,6 @@ template<typename Ret, unsigned int Num> void test(const testcase_sph_legendre<Ret> (&data)[Num], Ret toler) { - bool test __attribute__((unused)) = true; const Ret eps = std::numeric_limits<Ret>::epsilon(); Ret max_abs_diff = -Ret(1); Ret max_abs_frac = -Ret(1); diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/22_sph_legendre/pr86655.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/22_sph_legendre/pr86655.cc index 11c9935..87f63ce 100644 --- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/22_sph_legendre/pr86655.cc +++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/22_sph_legendre/pr86655.cc @@ -36,7 +36,6 @@ template<typename _Tp> void test_m_gt_l() { - bool test __attribute__((unused)) = true; unsigned int larr[4] = {0u, 1u, 2u, 5u}; for (unsigned int l = 0; l < 4; ++l) for (unsigned int m = larr[l] + 1u; m <= larr[l] + 2u; ++m) diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/23_sph_neumann/check_value.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/23_sph_neumann/check_value.cc index 8134e7f..64cfce9 100644 --- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/23_sph_neumann/check_value.cc +++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/23_sph_neumann/check_value.cc @@ -554,7 +554,6 @@ template<typename Ret, unsigned int Num> void test(const testcase_sph_neumann<Ret> (&data)[Num], Ret toler) { - bool test __attribute__((unused)) = true; const Ret eps = std::numeric_limits<Ret>::epsilon(); Ret max_abs_diff = -Ret(1); Ret max_abs_frac = -Ret(1); diff --git a/libstdc++-v3/testsuite/util/debug/unordered_checks.h b/libstdc++-v3/testsuite/util/debug/unordered_checks.h index d01ee82..785aeb4 100644 --- a/libstdc++-v3/testsuite/util/debug/unordered_checks.h +++ b/libstdc++-v3/testsuite/util/debug/unordered_checks.h @@ -65,28 +65,36 @@ namespace __gnu_test template<typename _Tp> struct KeyExtractor { - static _Tp get_key(const _Tp& val) + static const _Tp& get_key(const _Tp& val) { return val; } }; template<typename _Tp1, typename _Tp2> - struct KeyExtractor<std::pair<const _Tp1, _Tp2>> + struct KeyExtractor<std::pair<_Tp1, _Tp2>> { - static _Tp1 get_key(const std::pair<const _Tp1, _Tp2>& val) + static const _Tp1& get_key(const std::pair<_Tp1, _Tp2>& val) { return val.first; } }; template<typename _Tp> - void use_erased_local_iterator() + void fill_container(_Tp& c) { typedef _Tp cont_type; typedef typename cont_type::value_type cont_val_type; typedef typename CopyableValueType<cont_val_type>::value_type val_type; generate_unique<val_type> gu; - cont_type c; for (size_t i = 0; i != 5; ++i) c.insert(gu.build()); + } + + template<typename _Tp> + void use_erased_local_iterator() + { + typedef _Tp cont_type; + typedef typename cont_type::value_type cont_val_type; + cont_type c; + fill_container(c); typename cont_type::local_iterator it, end; for (size_t i = 0; i != c.bucket_count(); ++i) @@ -96,22 +104,18 @@ namespace __gnu_test if (it != end) break; } - typename cont_type::key_type key = KeyExtractor<cont_val_type>::get_key(*it); + + const auto& key = KeyExtractor<cont_val_type>::get_key(*it); c.erase(key); VERIFY( it != end ); } template<typename _Tp> - void use_invalid_local_iterator() + typename _Tp::local_iterator + fill_and_get_local_iterator(_Tp& c) { typedef _Tp cont_type; - typedef typename cont_type::value_type cont_val_type; - typedef typename CopyableValueType<cont_val_type>::value_type val_type; - generate_unique<val_type> gu; - - cont_type c; - for (size_t i = 0; i != 5; ++i) - c.insert(gu.build()); + fill_container(c); typename cont_type::local_iterator it; for (size_t i = 0; i != c.bucket_count(); ++i) @@ -120,22 +124,107 @@ namespace __gnu_test if (it != c.end(i)) break; } - cont_val_type val = *it; + + return it; + } + + template<typename _Tp> + void use_invalid_local_iterator() + { + typedef _Tp cont_type; + cont_type c; + auto it = fill_and_get_local_iterator(c); + + const auto& val = *it; c.clear(); VERIFY( *it == val ); } template<typename _Tp> - void invalid_local_iterator_pre_increment() + void invalid_local_iterator_arrow_operator() { typedef _Tp cont_type; - typedef typename cont_type::value_type cont_val_type; - typedef typename CopyableValueType<cont_val_type>::value_type val_type; - generate_unique<val_type> gu; + cont_type c; + auto it = fill_and_get_local_iterator(c); + + const auto& val = *it; + c.clear(); + VERIFY( *it.operator->() == val ); + } + template<typename _Tp> + void invalid_local_iterator_copy_construction() + { + typedef _Tp cont_type; cont_type c; - for (size_t i = 0; i != 5; ++i) - c.insert(gu.build()); + auto it = fill_and_get_local_iterator(c); + + const auto& val = *it; + c.clear(); + typename cont_type::local_iterator lit(it); + VERIFY( *lit == val ); + } + + template<typename _Tp> + void invalid_local_iterator_move_construction() + { + typedef _Tp cont_type; + cont_type c; + auto it = fill_and_get_local_iterator(c); + + const auto& val = *it; + c.clear(); + typename cont_type::local_iterator lit(std::move(it)); + VERIFY( *lit == val ); + } + + template<typename _Tp> + void invalid_local_iterator_copy_assignment() + { + typedef _Tp cont_type; + cont_type c; + auto it = fill_and_get_local_iterator(c); + + const auto& val = *it; + c.clear(); + typename cont_type::local_iterator lit; + lit = it; + VERIFY( *lit == val ); + } + + template<typename _Tp> + void invalid_local_iterator_move_assignment() + { + typedef _Tp cont_type; + cont_type c; + auto it = fill_and_get_local_iterator(c); + + const auto& val = *it; + c.clear(); + typename cont_type::local_iterator lit; + lit = std::move(it); + VERIFY( *lit == val ); + } + + template<typename _Tp> + void invalid_local_iterator_const_conversion() + { + typedef _Tp cont_type; + cont_type c; + auto it = fill_and_get_local_iterator(c); + + const auto& val = *it; + c.clear(); + typename cont_type::const_local_iterator clit(it); + VERIFY( *clit == val ); + } + + template<typename _Tp> + void invalid_local_iterator_pre_increment() + { + typedef _Tp cont_type; + cont_type c; + fill_container(c); auto lit = c.begin(0); for (size_t i = 0; i != 6; ++i) @@ -146,13 +235,8 @@ namespace __gnu_test void invalid_local_iterator_post_increment() { typedef _Tp cont_type; - typedef typename cont_type::value_type cont_val_type; - typedef typename CopyableValueType<cont_val_type>::value_type val_type; - generate_unique<val_type> gu; - cont_type c; - for (size_t i = 0; i != 5; ++i) - c.insert(gu.build()); + fill_container(c); auto lit = c.begin(0); for (size_t i = 0; i != 6; ++i) @@ -163,13 +247,8 @@ namespace __gnu_test void invalid_local_iterator_compare() { typedef _Tp cont_type; - typedef typename cont_type::value_type cont_val_type; - typedef typename CopyableValueType<cont_val_type>::value_type val_type; - generate_unique<val_type> gu; - cont_type c; - for (size_t i = 0; i != 5; ++i) - c.insert(gu.build()); + fill_container(c); typename cont_type::local_iterator it1, it2; size_t i; @@ -194,13 +273,8 @@ namespace __gnu_test void invalid_local_iterator_range() { typedef _Tp cont_type; - typedef typename cont_type::value_type cont_val_type; - typedef typename CopyableValueType<cont_val_type>::value_type val_type; - generate_unique<val_type> gu; - cont_type c; - for (size_t i = 0; i != 5; ++i) - c.insert(gu.build()); + fill_container(c); typename cont_type::local_iterator it, end; for (size_t i = 0; i != c.bucket_count(); ++i) diff --git a/libstdc++-v3/testsuite/util/pstl/test_utils.h b/libstdc++-v3/testsuite/util/pstl/test_utils.h index 55b5100..9c61a714 100644 --- a/libstdc++-v3/testsuite/util/pstl/test_utils.h +++ b/libstdc++-v3/testsuite/util/pstl/test_utils.h @@ -154,7 +154,7 @@ class ForwardIterator explicit ForwardIterator(Iterator i) : my_iterator(i) {} reference operator*() const { return *my_iterator; } Iterator operator->() const { return my_iterator; } - ForwardIterator + ForwardIterator& operator++() { ++my_iterator; @@ -194,13 +194,13 @@ class BidirectionalIterator : public ForwardIterator<Iterator, IteratorTag> explicit BidirectionalIterator(Iterator i) : base_type(i) {} BidirectionalIterator(const base_type& i) : base_type(i.iterator()) {} - BidirectionalIterator + BidirectionalIterator& operator++() { ++base_type::my_iterator; return *this; } - BidirectionalIterator + BidirectionalIterator& operator--() { --base_type::my_iterator; diff --git a/libstdc++-v3/testsuite/util/replacement_memory_operators.h b/libstdc++-v3/testsuite/util/replacement_memory_operators.h index 2516cd2..69afa77 100644 --- a/libstdc++-v3/testsuite/util/replacement_memory_operators.h +++ b/libstdc++-v3/testsuite/util/replacement_memory_operators.h @@ -36,8 +36,12 @@ namespace __gnu_test ~counter() THROW (counter_error) { +#if __cpp_exceptions if (_M_throw && _M_count != 0) throw counter_error(); +#else + VERIFY( !_M_throw || _M_count == 0 ); +#endif } static void @@ -133,8 +137,12 @@ void* operator new(std::size_t size) THROW(std::bad_alloc) { std::printf("operator new is called \n"); void* p = std::malloc(size); +#if __cpp_exceptions if (!p) throw std::bad_alloc(); +#else + VERIFY( p ); +#endif __gnu_test::counter::increment(); return p; } diff --git a/libstdc++-v3/testsuite/util/testsuite_abi.cc b/libstdc++-v3/testsuite/util/testsuite_abi.cc index 1b4044c..4b01023 100644 --- a/libstdc++-v3/testsuite/util/testsuite_abi.cc +++ b/libstdc++-v3/testsuite/util/testsuite_abi.cc @@ -216,6 +216,7 @@ check_version(symbol& test, bool added) known_versions.push_back("GLIBCXX_3.4.32"); known_versions.push_back("GLIBCXX_3.4.33"); known_versions.push_back("GLIBCXX_3.4.34"); + known_versions.push_back("GLIBCXX_3.4.35"); known_versions.push_back("GLIBCXX_LDBL_3.4.31"); known_versions.push_back("GLIBCXX_IEEE128_3.4.29"); known_versions.push_back("GLIBCXX_IEEE128_3.4.30"); @@ -240,6 +241,7 @@ check_version(symbol& test, bool added) #ifdef __riscv known_versions.push_back("CXXABI_1.3.16"); #endif + known_versions.push_back("CXXABI_1.3.17"); known_versions.push_back("CXXABI_IEEE128_1.3.13"); known_versions.push_back("CXXABI_TM_1"); known_versions.push_back("CXXABI_FLOAT128"); @@ -258,8 +260,8 @@ check_version(symbol& test, bool added) test.version_status = symbol::incompatible; // Check that added symbols are added in the latest pre-release version. - bool latestp = (test.version_name == "GLIBCXX_3.4.34" - || test.version_name == "CXXABI_1.3.16" + bool latestp = (test.version_name == "GLIBCXX_3.4.35" + || test.version_name == "CXXABI_1.3.17" || test.version_name == "CXXABI_FLOAT128" || test.version_name == "CXXABI_TM_1"); if (added && !latestp) diff --git a/libstdc++-v3/testsuite/util/testsuite_allocator.h b/libstdc++-v3/testsuite/util/testsuite_allocator.h index be596bf..e5ffad2 100644 --- a/libstdc++-v3/testsuite/util/testsuite_allocator.h +++ b/libstdc++-v3/testsuite/util/testsuite_allocator.h @@ -541,15 +541,16 @@ namespace __gnu_test default_init_allocator() = default; template<typename U> + constexpr default_init_allocator(const default_init_allocator<U>& a) : state(a.state) { } - T* + constexpr T* allocate(std::size_t n) { return std::allocator<T>().allocate(n); } - void + constexpr void deallocate(T* p, std::size_t n) { std::allocator<T>().deallocate(p, n); } @@ -557,15 +558,17 @@ namespace __gnu_test }; template<typename T, typename U> - bool operator==(const default_init_allocator<T>& t, - const default_init_allocator<U>& u) + constexpr bool + operator==(const default_init_allocator<T>& t, + const default_init_allocator<U>& u) { return t.state == u.state; } template<typename T, typename U> - bool operator!=(const default_init_allocator<T>& t, - const default_init_allocator<U>& u) + constexpr bool + operator!=(const default_init_allocator<T>& t, + const default_init_allocator<U>& u) { return !(t == u); } -#endif +#endif // C++11 template<typename Tp> struct ExplicitConsAlloc : std::allocator<Tp> diff --git a/libstdc++-v3/testsuite/util/testsuite_iterators.h b/libstdc++-v3/testsuite/util/testsuite_iterators.h index 0df6dcc..74a8739 100644 --- a/libstdc++-v3/testsuite/util/testsuite_iterators.h +++ b/libstdc++-v3/testsuite/util/testsuite_iterators.h @@ -610,12 +610,10 @@ namespace __gnu_test test_container(T* _first, T* _last) : bounds(_first, _last) { } -#if __cplusplus >= 201103L template<std::size_t N> explicit - test_container(T (&arr)[N]) : test_container(arr, arr+N) + test_container(T (&arr)[N]) : bounds(arr, arr+N) { } -#endif ItType<T> it(int pos) @@ -894,6 +892,9 @@ namespace __gnu_test using test_input_range = test_range<T, input_iterator_wrapper>; template<typename T> + using test_input_range_nocopy + = test_range_nocopy<T, input_iterator_wrapper_nocopy>; + template<typename T> using test_output_range = test_range<T, output_iterator_wrapper>; |