diff options
Diffstat (limited to 'libstdc++-v3/testsuite')
98 files changed, 4151 insertions, 104 deletions
diff --git a/libstdc++-v3/testsuite/17_intro/names.cc b/libstdc++-v3/testsuite/17_intro/names.cc index 4458325..f67818d 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 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/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_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/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/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/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/23_containers/deque/capacity/shrink_to_fit.cc b/libstdc++-v3/testsuite/23_containers/deque/capacity/shrink_to_fit.cc index 7cb6707..4dbf405 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,6 @@ // { dg-do run { target c++11 } } +// { dg-require-effective-target std_allocator_new } +// { dg-xfail-run-if "AIX operator new" { powerpc-ibm-aix* } } // 2010-01-08 Paolo Carlini <paolo.carlini@oracle.com> @@ -19,18 +21,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..4fd33f6 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> diff --git a/libstdc++-v3/testsuite/23_containers/flat_multimap/1.cc b/libstdc++-v3/testsuite/23_containers/flat_multimap/1.cc index ff180bf..ea0d4b4 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> diff --git a/libstdc++-v3/testsuite/23_containers/flat_multiset/1.cc b/libstdc++-v3/testsuite/23_containers/flat_multiset/1.cc index dc3cecd..7d9a33c 100644 --- a/libstdc++-v3/testsuite/23_containers/flat_multiset/1.cc +++ b/libstdc++-v3/testsuite/23_containers/flat_multiset/1.cc @@ -214,6 +214,27 @@ 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 ); +} + int main() { @@ -225,4 +246,5 @@ main() test05(); test06(); test07(); + test08(); } diff --git a/libstdc++-v3/testsuite/23_containers/flat_set/1.cc b/libstdc++-v3/testsuite/23_containers/flat_set/1.cc index 90f5855..ed24fab 100644 --- a/libstdc++-v3/testsuite/23_containers/flat_set/1.cc +++ b/libstdc++-v3/testsuite/23_containers/flat_set/1.cc @@ -229,6 +229,25 @@ 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 ); +} + int main() { @@ -240,4 +259,5 @@ main() test05(); test06(); test07(); + test08(); } 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/cons/from_range.cc b/libstdc++-v3/testsuite/23_containers/map/cons/from_range.cc index c740471..9935f44 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> 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..4a8ea9f 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> 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/cons/from_range.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/cons/from_range.cc index 6d1da5b..36efc2d 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> 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/cons/from_range.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/from_range.cc index 2ca93d3..b551df4 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> 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/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/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/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..eb24b66 --- /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/from_range.cc b/libstdc++-v3/testsuite/23_containers/vector/cons/from_range.cc index ed2e3ca..7a62645 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> 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/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/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/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/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/std/format/debug.cc b/libstdc++-v3/testsuite/std/format/debug.cc new file mode 100644 index 0000000..d3402f8 --- /dev/null +++ b/libstdc++-v3/testsuite/std/format/debug.cc @@ -0,0 +1,833 @@ +// { 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-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("{:*>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("{:*>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/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..93c33b4 100644 --- a/libstdc++-v3/testsuite/std/format/functions/format.cc +++ b/libstdc++-v3/testsuite/std/format/functions/format.cc @@ -370,6 +370,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 @@ -501,9 +513,14 @@ test_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}", "£"); 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..daa73aa --- /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..bf8619d --- /dev/null +++ b/libstdc++-v3/testsuite/std/format/ranges/format_kind_neg.cc @@ -0,0 +1,13 @@ +// { 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> + +template<auto> struct Tester { }; + +Tester<std::format_kind<const int(&)[1]>> t; // { dg-error "here" } + +// { dg-error "use of 'std::format_kind" "" { target *-*-* } 0 } +// { dg-error "primary_template_not_defined" "" { 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..00ce9f6 --- /dev/null +++ b/libstdc++-v3/testsuite/std/format/ranges/formatter.cc @@ -0,0 +1,171 @@ +// { 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 + { + using _CharT = CharT; + _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..1838480 --- /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..75fe4c1 --- /dev/null +++ b/libstdc++-v3/testsuite/std/format/ranges/sequence.cc @@ -0,0 +1,323 @@ +// { 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("{:*>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..cebdd53 --- /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..ff0359b --- /dev/null +++ b/libstdc++-v3/testsuite/std/format/tuple.cc @@ -0,0 +1,352 @@ +// { 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 + { + using _CharT = CharT; + _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/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/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/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/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..90cda2f 100644 --- a/libstdc++-v3/testsuite/util/testsuite_abi.cc +++ b/libstdc++-v3/testsuite/util/testsuite_abi.cc @@ -258,8 +258,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_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>; |