aboutsummaryrefslogtreecommitdiff
path: root/libstdc++-v3/testsuite
diff options
context:
space:
mode:
Diffstat (limited to 'libstdc++-v3/testsuite')
-rw-r--r--libstdc++-v3/testsuite/17_intro/headers/c++1998/49745.cc2
-rw-r--r--libstdc++-v3/testsuite/17_intro/names.cc18
-rw-r--r--libstdc++-v3/testsuite/18_support/comparisons/type_order/1.cc95
-rw-r--r--libstdc++-v3/testsuite/18_support/exception_ptr/exception_ptr_cast.cc81
-rw-r--r--libstdc++-v3/testsuite/18_support/headers/ciso646/macros-2.cc7
-rw-r--r--libstdc++-v3/testsuite/18_support/headers/ciso646/macros.cc1
-rw-r--r--libstdc++-v3/testsuite/20_util/aligned_storage/value.cc6
-rw-r--r--libstdc++-v3/testsuite/20_util/bitset/cons/1.cc1
-rw-r--r--libstdc++-v3/testsuite/20_util/bitset/cons/6282.cc5
-rw-r--r--libstdc++-v3/testsuite/20_util/bitset/cons/string_view.cc132
-rw-r--r--libstdc++-v3/testsuite/20_util/bitset/cons/string_view_wide.cc8
-rw-r--r--libstdc++-v3/testsuite/20_util/copyable_function/call.cc225
-rw-r--r--libstdc++-v3/testsuite/20_util/copyable_function/cons.cc126
-rw-r--r--libstdc++-v3/testsuite/20_util/copyable_function/conv.cc286
-rw-r--r--libstdc++-v3/testsuite/20_util/copyable_function/copy.cc154
-rw-r--r--libstdc++-v3/testsuite/20_util/copyable_function/incomplete_neg.cc18
-rw-r--r--libstdc++-v3/testsuite/20_util/copyable_function/move.cc120
-rw-r--r--libstdc++-v3/testsuite/20_util/expected/119714.cc9
-rw-r--r--libstdc++-v3/testsuite/20_util/expected/equality_constrained.cc2
-rw-r--r--libstdc++-v3/testsuite/20_util/function/cons/70692.cc2
-rw-r--r--libstdc++-v3/testsuite/20_util/function_ref/assign.cc108
-rw-r--r--libstdc++-v3/testsuite/20_util/function_ref/call.cc186
-rw-r--r--libstdc++-v3/testsuite/20_util/function_ref/cons.cc218
-rw-r--r--libstdc++-v3/testsuite/20_util/function_ref/cons_neg.cc30
-rw-r--r--libstdc++-v3/testsuite/20_util/function_ref/conv.cc293
-rw-r--r--libstdc++-v3/testsuite/20_util/function_ref/deduction.cc103
-rw-r--r--libstdc++-v3/testsuite/20_util/function_ref/incomplete_neg.cc18
-rw-r--r--libstdc++-v3/testsuite/20_util/function_ref/mutation.cc85
-rw-r--r--libstdc++-v3/testsuite/20_util/headers/memory/version.cc4
-rw-r--r--libstdc++-v3/testsuite/20_util/is_complete_or_unbounded/120717.cc20
-rw-r--r--libstdc++-v3/testsuite/20_util/is_complete_or_unbounded/memoization.cc2
-rw-r--r--libstdc++-v3/testsuite/20_util/is_complete_or_unbounded/memoization_neg.cc2
-rw-r--r--libstdc++-v3/testsuite/20_util/move_only_function/call.cc21
-rw-r--r--libstdc++-v3/testsuite/20_util/move_only_function/conv.cc223
-rw-r--r--libstdc++-v3/testsuite/20_util/move_only_function/incomplete_neg.cc18
-rw-r--r--libstdc++-v3/testsuite/20_util/move_only_function/move.cc11
-rw-r--r--libstdc++-v3/testsuite/20_util/optional/range.cc163
-rw-r--r--libstdc++-v3/testsuite/20_util/optional/version.cc18
-rw-r--r--libstdc++-v3/testsuite/20_util/shared_ptr/requirements/1.cc111
-rw-r--r--libstdc++-v3/testsuite/20_util/specialized_algorithms/memory_management_tools/destroy_n_neg.cc59
-rw-r--r--libstdc++-v3/testsuite/20_util/specialized_algorithms/memory_management_tools/destroy_neg.cc20
-rw-r--r--libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/constrained.cc30
-rw-r--r--libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_default_construct/120397.cc19
-rw-r--r--libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill/120931.cc16
-rw-r--r--libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_move/constrained.cc29
-rw-r--r--libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_value_construct/120397.cc19
-rw-r--r--libstdc++-v3/testsuite/20_util/system_clock/99832.cc14
-rw-r--r--libstdc++-v3/testsuite/20_util/tuple/dr3528.cc46
-rw-r--r--libstdc++-v3/testsuite/20_util/tuple/element_access/get_neg.cc2
-rw-r--r--libstdc++-v3/testsuite/20_util/weak_ptr/requirements/1.cc33
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/allocator/char/operator_plus.cc2
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/allocator/wchar_t/operator_plus.cc2
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/cons/char/119748.cc35
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/cons/from_range.cc129
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/cons/wchar_t/119748.cc7
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/modifiers/append/append_range.cc125
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/modifiers/assign/assign_range.cc116
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/modifiers/insert/insert_range.cc130
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/modifiers/replace/replace_with_range.cc133
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/stold.cc6
-rw-r--r--libstdc++-v3/testsuite/22_locale/ctype/is/string/89728_neg.cc1
-rw-r--r--libstdc++-v3/testsuite/22_locale/num_put/put/char/lwg4084.cc8
-rw-r--r--libstdc++-v3/testsuite/23_containers/deque/capacity/shrink_to_fit.cc37
-rw-r--r--libstdc++-v3/testsuite/23_containers/deque/cons/from_range.cc5
-rw-r--r--libstdc++-v3/testsuite/23_containers/flat_map/1.cc42
-rw-r--r--libstdc++-v3/testsuite/23_containers/flat_multimap/1.cc32
-rw-r--r--libstdc++-v3/testsuite/23_containers/flat_multiset/1.cc33
-rw-r--r--libstdc++-v3/testsuite/23_containers/flat_set/1.cc31
-rw-r--r--libstdc++-v3/testsuite/23_containers/forward_list/48101_neg.cc1
-rw-r--r--libstdc++-v3/testsuite/23_containers/forward_list/cons/from_range.cc6
-rw-r--r--libstdc++-v3/testsuite/23_containers/list/48101_neg.cc1
-rw-r--r--libstdc++-v3/testsuite/23_containers/list/cons/from_range.cc5
-rw-r--r--libstdc++-v3/testsuite/23_containers/map/48101_neg.cc4
-rw-r--r--libstdc++-v3/testsuite/23_containers/map/cons/deduction.cc46
-rw-r--r--libstdc++-v3/testsuite/23_containers/map/cons/from_range.cc15
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/accessors/default.cc99
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/accessors/default_neg.cc23
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/extents/class_mandates_neg.cc12
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy.cc82
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_default.cc41
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints.cc62
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape.cc160
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/extents/custom_integer.cc87
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/extents/misc.cc224
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/layouts/class_mandate_neg.cc48
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/layouts/ctors.cc436
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/layouts/empty.cc131
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/layouts/mapping.cc568
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/layouts/stride.cc526
-rw-r--r--libstdc++-v3/testsuite/23_containers/multimap/48101_neg.cc4
-rw-r--r--libstdc++-v3/testsuite/23_containers/multimap/cons/deduction.cc46
-rw-r--r--libstdc++-v3/testsuite/23_containers/multimap/cons/from_range.cc15
-rw-r--r--libstdc++-v3/testsuite/23_containers/multiset/48101_neg.cc1
-rw-r--r--libstdc++-v3/testsuite/23_containers/multiset/cons/from_range.cc7
-rw-r--r--libstdc++-v3/testsuite/23_containers/priority_queue/cons_from_range.cc7
-rw-r--r--libstdc++-v3/testsuite/23_containers/queue/cons_from_range.cc7
-rw-r--r--libstdc++-v3/testsuite/23_containers/set/48101_neg.cc1
-rw-r--r--libstdc++-v3/testsuite/23_containers/set/cons/from_range.cc7
-rw-r--r--libstdc++-v3/testsuite/23_containers/stack/cons_from_range.cc7
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_map/96088.cc2
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_map/cons/66055.cc11
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_map/cons/deduction.cc97
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_map/cons/from_range.cc17
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_arrow_operator_neg.cc17
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_const_conversion_neg.cc17
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_copy_assignment_neg.cc17
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_copy_construction_neg.cc17
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_move_assignment_neg.cc17
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_move_construction_neg.cc17
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_map/debug/max_load_factor_neg.cc2
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_multimap/96088.cc2
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/66055.cc10
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/deduction.cc103
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/from_range.cc17
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/begin2_neg.cc4
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/bucket_size_neg.cc2
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/cbegin_neg.cc2
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/cend_neg.cc2
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/end1_neg.cc2
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/end2_neg.cc4
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_arrow_operator_neg.cc17
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_const_conversion_neg.cc17
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_copy_assignment_neg.cc17
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_copy_construction_neg.cc17
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_move_assignment_neg.cc17
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_move_construction_neg.cc17
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/max_load_factor_neg.cc2
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_multiset/96088.cc2
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/66055.cc10
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/deduction.cc28
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/from_range.cc7
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_arrow_operator_neg.cc17
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_const_conversion_neg.cc17
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_copy_assignment_neg.cc17
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_copy_construction_neg.cc17
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_move_assignment_neg.cc17
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_move_construction_neg.cc17
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_set/96088.cc2
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_set/cons/66055.cc10
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_set/cons/deduction.cc28
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_set/cons/from_range.cc7
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_arrow_operator_neg.cc17
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_const_conversion_neg.cc17
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_copy_assignment_neg.cc17
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_copy_construction_neg.cc17
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_move_assignment_neg.cc17
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_move_construction_neg.cc17
-rw-r--r--libstdc++-v3/testsuite/23_containers/vector/allocator/default_init.cc11
-rw-r--r--libstdc++-v3/testsuite/23_containers/vector/bool/allocator/default_init.cc11
-rw-r--r--libstdc++-v3/testsuite/23_containers/vector/bool/cons/from_range.cc6
-rw-r--r--libstdc++-v3/testsuite/23_containers/vector/bool/format.cc72
-rw-r--r--libstdc++-v3/testsuite/23_containers/vector/capacity/114945.cc36
-rw-r--r--libstdc++-v3/testsuite/23_containers/vector/cons/destructible_debug_neg.cc7
-rw-r--r--libstdc++-v3/testsuite/23_containers/vector/cons/destructible_neg.cc7
-rw-r--r--libstdc++-v3/testsuite/23_containers/vector/cons/from_range.cc27
-rw-r--r--libstdc++-v3/testsuite/24_iterators/indirect_callable/projected.cc5
-rw-r--r--libstdc++-v3/testsuite/24_iterators/operations/prev_neg.cc2
-rw-r--r--libstdc++-v3/testsuite/24_iterators/range_generators/lwg3899.cc57
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/ends_with/1.cc165
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/heap/constrained.cc46
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/inplace_merge/constrained.cc36
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/nth_element/constrained.cc31
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/remove_if/120789.cc36
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/sample/constrained.cc26
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/shuffle/constrained.cc25
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/sort/118209.cc23
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/sort/constrained.cc31
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/stable_partition/constrained.cc26
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/stable_sort/constrained.cc30
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/starts_with/1.cc158
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/unique/120789.cc36
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/unique_copy/120384.cc12
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/unique_copy/lwg2439.cc127
-rw-r--r--libstdc++-v3/testsuite/26_numerics/complex/fabs_neg.cc13
-rw-r--r--libstdc++-v3/testsuite/26_numerics/headers/cmath/82644.cc3
-rw-r--r--libstdc++-v3/testsuite/26_numerics/headers/cstdlib/abs128.cc16
-rw-r--r--libstdc++-v3/testsuite/26_numerics/pstl/numeric_ops/108236.cc25
-rw-r--r--libstdc++-v3/testsuite/26_numerics/pstl/numeric_ops/move_only.cc90
-rw-r--r--libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc2
-rw-r--r--libstdc++-v3/testsuite/27_io/basic_istringstream/cons/char/string_view.cc201
-rw-r--r--libstdc++-v3/testsuite/27_io/basic_istringstream/cons/wchar_t/string_view.cc6
-rw-r--r--libstdc++-v3/testsuite/27_io/basic_ostream/inserters_arithmetic/char/hexfloat.cc6
-rw-r--r--libstdc++-v3/testsuite/27_io/basic_ostringstream/cons/char/string_view.cc200
-rw-r--r--libstdc++-v3/testsuite/27_io/basic_ostringstream/cons/wchar_t/string_view.cc6
-rw-r--r--libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/char/string_view.cc211
-rw-r--r--libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/wchar_t/string_view.cc6
-rw-r--r--libstdc++-v3/testsuite/27_io/basic_stringstream/cons/char/string_view.cc210
-rw-r--r--libstdc++-v3/testsuite/27_io/basic_stringstream/cons/wchar_t/string_view.cc6
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/path/concat/120029.cc72
-rw-r--r--libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/100334.cc7
-rw-r--r--libstdc++-v3/testsuite/29_atomics/atomic_integral/wait_notify.cc8
-rw-r--r--libstdc++-v3/testsuite/30_threads/barrier/1.cc3
-rw-r--r--libstdc++-v3/testsuite/30_threads/barrier/2.cc2
-rw-r--r--libstdc++-v3/testsuite/30_threads/barrier/cons.cc6
-rw-r--r--libstdc++-v3/testsuite/30_threads/barrier/lwg3898.cc45
-rw-r--r--libstdc++-v3/testsuite/30_threads/packaged_task/cons/dangling_ref.cc3
-rw-r--r--libstdc++-v3/testsuite/30_threads/packaged_task/cons/lwg4154_neg.cc10
-rw-r--r--libstdc++-v3/testsuite/30_threads/scoped_lock/requirements/typedefs.cc28
-rw-r--r--libstdc++-v3/testsuite/30_threads/semaphore/1.cc24
-rw-r--r--libstdc++-v3/testsuite/30_threads/semaphore/100806.cc2
-rw-r--r--libstdc++-v3/testsuite/30_threads/semaphore/104928-2.cc101
-rw-r--r--libstdc++-v3/testsuite/30_threads/semaphore/104928.cc70
-rw-r--r--libstdc++-v3/testsuite/30_threads/semaphore/2.cc1
-rw-r--r--libstdc++-v3/testsuite/30_threads/semaphore/3.cc19
-rw-r--r--libstdc++-v3/testsuite/30_threads/semaphore/cons.cc9
-rw-r--r--libstdc++-v3/testsuite/30_threads/semaphore/cons_neg.cc12
-rw-r--r--libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc4
-rw-r--r--libstdc++-v3/testsuite/30_threads/semaphore/platform_try_acquire_for.cc9
-rw-r--r--libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc3
-rw-r--r--libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc153
-rw-r--r--libstdc++-v3/testsuite/30_threads/thread/id/output.cc30
-rw-r--r--libstdc++-v3/testsuite/experimental/filesystem/path/concat/120029.cc74
-rw-r--r--libstdc++-v3/testsuite/experimental/names.cc6
-rw-r--r--libstdc++-v3/testsuite/experimental/net/buffer/arithmetic.cc2
-rw-r--r--libstdc++-v3/testsuite/experimental/net/buffer/const.cc1
-rw-r--r--libstdc++-v3/testsuite/experimental/net/buffer/mutable.cc1
-rw-r--r--libstdc++-v3/testsuite/experimental/net/buffer/size.cc2
-rw-r--r--libstdc++-v3/testsuite/experimental/net/timer/waitable/cons.cc6
-rw-r--r--libstdc++-v3/testsuite/experimental/net/timer/waitable/dest.cc2
-rw-r--r--libstdc++-v3/testsuite/experimental/net/timer/waitable/ops.cc4
-rw-r--r--libstdc++-v3/testsuite/ext/special_functions/airy_ai/check_value.cc1
-rw-r--r--libstdc++-v3/testsuite/ext/special_functions/airy_bi/check_value.cc1
-rw-r--r--libstdc++-v3/testsuite/ext/special_functions/conf_hyperg/check_value.cc1
-rw-r--r--libstdc++-v3/testsuite/ext/special_functions/hyperg/check_value.cc1
-rw-r--r--libstdc++-v3/testsuite/lib/libstdc++.exp25
-rw-r--r--libstdc++-v3/testsuite/lib/prune.exp3
-rw-r--r--libstdc++-v3/testsuite/special_functions/01_assoc_laguerre/check_value.cc1
-rw-r--r--libstdc++-v3/testsuite/special_functions/02_assoc_legendre/check_value.cc1
-rw-r--r--libstdc++-v3/testsuite/special_functions/02_assoc_legendre/pr86655.cc1
-rw-r--r--libstdc++-v3/testsuite/special_functions/03_beta/check_value.cc1
-rw-r--r--libstdc++-v3/testsuite/special_functions/04_comp_ellint_1/check_value.cc1
-rw-r--r--libstdc++-v3/testsuite/special_functions/05_comp_ellint_2/check_value.cc1
-rw-r--r--libstdc++-v3/testsuite/special_functions/06_comp_ellint_3/check_value.cc1
-rw-r--r--libstdc++-v3/testsuite/special_functions/07_cyl_bessel_i/check_value.cc1
-rw-r--r--libstdc++-v3/testsuite/special_functions/08_cyl_bessel_j/check_value.cc1
-rw-r--r--libstdc++-v3/testsuite/special_functions/09_cyl_bessel_k/check_value.cc1
-rw-r--r--libstdc++-v3/testsuite/special_functions/10_cyl_neumann/check_value.cc1
-rw-r--r--libstdc++-v3/testsuite/special_functions/11_ellint_1/check_value.cc1
-rw-r--r--libstdc++-v3/testsuite/special_functions/12_ellint_2/check_value.cc1
-rw-r--r--libstdc++-v3/testsuite/special_functions/13_ellint_3/check_value.cc1
-rw-r--r--libstdc++-v3/testsuite/special_functions/14_expint/check_value.cc1
-rw-r--r--libstdc++-v3/testsuite/special_functions/15_hermite/check_value.cc1
-rw-r--r--libstdc++-v3/testsuite/special_functions/16_laguerre/check_value.cc1
-rw-r--r--libstdc++-v3/testsuite/special_functions/17_legendre/check_value.cc1
-rw-r--r--libstdc++-v3/testsuite/special_functions/18_riemann_zeta/check_value.cc1
-rw-r--r--libstdc++-v3/testsuite/special_functions/19_sph_bessel/check_value.cc1
-rw-r--r--libstdc++-v3/testsuite/special_functions/20_sph_legendre/check_value.cc1
-rw-r--r--libstdc++-v3/testsuite/special_functions/20_sph_legendre/pr86655.cc1
-rw-r--r--libstdc++-v3/testsuite/special_functions/21_sph_neumann/check_value.cc1
-rw-r--r--libstdc++-v3/testsuite/std/format/arguments/args.cc45
-rw-r--r--libstdc++-v3/testsuite/std/format/debug.cc843
-rw-r--r--libstdc++-v3/testsuite/std/format/debug_nonunicode.cc5
-rw-r--r--libstdc++-v3/testsuite/std/format/formatter/120625.cc19
-rw-r--r--libstdc++-v3/testsuite/std/format/formatter/lwg3944.cc2
-rw-r--r--libstdc++-v3/testsuite/std/format/formatter/requirements.cc14
-rw-r--r--libstdc++-v3/testsuite/std/format/functions/format.cc32
-rw-r--r--libstdc++-v3/testsuite/std/format/parse_ctx.cc72
-rw-r--r--libstdc++-v3/testsuite/std/format/ranges/adaptors.cc156
-rw-r--r--libstdc++-v3/testsuite/std/format/ranges/feature_test.cc9
-rw-r--r--libstdc++-v3/testsuite/std/format/ranges/format_kind.cc94
-rw-r--r--libstdc++-v3/testsuite/std/format/ranges/format_kind_neg.cc18
-rw-r--r--libstdc++-v3/testsuite/std/format/ranges/formatter.cc170
-rw-r--r--libstdc++-v3/testsuite/std/format/ranges/map.cc210
-rw-r--r--libstdc++-v3/testsuite/std/format/ranges/sequence.cc332
-rw-r--r--libstdc++-v3/testsuite/std/format/ranges/string.cc290
-rw-r--r--libstdc++-v3/testsuite/std/format/tuple.cc351
-rw-r--r--libstdc++-v3/testsuite/std/memory/indirect/copy.cc121
-rw-r--r--libstdc++-v3/testsuite/std/memory/indirect/copy_alloc.cc228
-rw-r--r--libstdc++-v3/testsuite/std/memory/indirect/ctor.cc204
-rw-r--r--libstdc++-v3/testsuite/std/memory/indirect/incomplete.cc38
-rw-r--r--libstdc++-v3/testsuite/std/memory/indirect/invalid_neg.cc28
-rw-r--r--libstdc++-v3/testsuite/std/memory/indirect/move.cc144
-rw-r--r--libstdc++-v3/testsuite/std/memory/indirect/move_alloc.cc296
-rw-r--r--libstdc++-v3/testsuite/std/memory/indirect/relops.cc82
-rw-r--r--libstdc++-v3/testsuite/std/memory/polymorphic/copy.cc157
-rw-r--r--libstdc++-v3/testsuite/std/memory/polymorphic/copy_alloc.cc270
-rw-r--r--libstdc++-v3/testsuite/std/memory/polymorphic/ctor.cc190
-rw-r--r--libstdc++-v3/testsuite/std/memory/polymorphic/ctor_poly.cc220
-rw-r--r--libstdc++-v3/testsuite/std/memory/polymorphic/incomplete.cc13
-rw-r--r--libstdc++-v3/testsuite/std/memory/polymorphic/invalid_neg.cc28
-rw-r--r--libstdc++-v3/testsuite/std/memory/polymorphic/move.cc177
-rw-r--r--libstdc++-v3/testsuite/std/memory/polymorphic/move_alloc.cc339
-rw-r--r--libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc13
-rw-r--r--libstdc++-v3/testsuite/std/ranges/concat/1.cc13
-rw-r--r--libstdc++-v3/testsuite/std/ranges/iota/max_size_type.cc7
-rw-r--r--libstdc++-v3/testsuite/std/time/clock/local/io.cc3
-rw-r--r--libstdc++-v3/testsuite/std/time/format/data_not_present_neg.cc164
-rw-r--r--libstdc++-v3/testsuite/std/time/format/empty_spec.cc917
-rw-r--r--libstdc++-v3/testsuite/std/time/format/pr117214.cc43
-rw-r--r--libstdc++-v3/testsuite/std/time/format/pr120114.cc125
-rw-r--r--libstdc++-v3/testsuite/std/time/format/pr120481.cc324
-rw-r--r--libstdc++-v3/testsuite/std/time/format/precision.cc201
-rw-r--r--libstdc++-v3/testsuite/std/time/format/whitespace.cc56
-rw-r--r--libstdc++-v3/testsuite/tr1/2_general_utilities/shared_ptr/cons/43820_neg.cc3
-rw-r--r--libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/01_assoc_laguerre/check_value.cc1
-rw-r--r--libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/02_assoc_legendre/check_value.cc1
-rw-r--r--libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/02_assoc_legendre/pr86655.cc1
-rw-r--r--libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/03_beta/check_value.cc1
-rw-r--r--libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/04_comp_ellint_1/check_value.cc1
-rw-r--r--libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/05_comp_ellint_2/check_value.cc1
-rw-r--r--libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/06_comp_ellint_3/check_value.cc1
-rw-r--r--libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/07_conf_hyperg/check_value.cc1
-rw-r--r--libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/08_cyl_bessel_i/check_value.cc1
-rw-r--r--libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/09_cyl_bessel_j/check_value.cc1
-rw-r--r--libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/10_cyl_bessel_k/check_value.cc1
-rw-r--r--libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/11_cyl_neumann/check_value.cc1
-rw-r--r--libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/12_ellint_1/check_value.cc1
-rw-r--r--libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/13_ellint_2/check_value.cc1
-rw-r--r--libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/14_ellint_3/check_value.cc1
-rw-r--r--libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/15_expint/check_value_neg.cc1
-rw-r--r--libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/16_hermite/check_value.cc1
-rw-r--r--libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/17_hyperg/check_value.cc1
-rw-r--r--libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/18_laguerre/check_value.cc1
-rw-r--r--libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/19_legendre/check_value.cc1
-rw-r--r--libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/20_riemann_zeta/check_value_neg.cc1
-rw-r--r--libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/21_sph_bessel/check_value.cc1
-rw-r--r--libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/22_sph_legendre/check_value.cc1
-rw-r--r--libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/22_sph_legendre/pr86655.cc1
-rw-r--r--libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/23_sph_neumann/check_value.cc1
-rw-r--r--libstdc++-v3/testsuite/util/debug/unordered_checks.h152
-rw-r--r--libstdc++-v3/testsuite/util/pstl/test_utils.h6
-rw-r--r--libstdc++-v3/testsuite/util/replacement_memory_operators.h8
-rw-r--r--libstdc++-v3/testsuite/util/testsuite_abi.cc6
-rw-r--r--libstdc++-v3/testsuite/util/testsuite_allocator.h17
-rw-r--r--libstdc++-v3/testsuite/util/testsuite_iterators.h7
325 files changed, 17085 insertions, 579 deletions
diff --git a/libstdc++-v3/testsuite/17_intro/headers/c++1998/49745.cc b/libstdc++-v3/testsuite/17_intro/headers/c++1998/49745.cc
index 7fafe7b..3b9d2eb 100644
--- a/libstdc++-v3/testsuite/17_intro/headers/c++1998/49745.cc
+++ b/libstdc++-v3/testsuite/17_intro/headers/c++1998/49745.cc
@@ -131,5 +131,3 @@
#endif
int truncate = 0;
-
-// { dg-xfail-if "PR libstdc++/99995" { c++20 } }
diff --git a/libstdc++-v3/testsuite/17_intro/names.cc b/libstdc++-v3/testsuite/17_intro/names.cc
index 4458325..e94da9d 100644
--- a/libstdc++-v3/testsuite/17_intro/names.cc
+++ b/libstdc++-v3/testsuite/17_intro/names.cc
@@ -142,6 +142,10 @@
#define try_emplace (
#endif
+#if __cplusplus < 202002L
+#define ranges (
+#endif
+
// These clash with newlib so don't use them.
# define __lockable cannot be used as an identifier
# define __null_sentinel cannot be used as an identifier
@@ -244,6 +248,10 @@
#undef r
#undef x
#undef y
+// <stdlib.h> defines drand48_data::a
+#undef a
+// <sys/localedef.h> defines _LC_weight_t::n
+#undef n
// <sys/poll.h> defines pollfd_ext::u on AIX 7.3
#undef u
// <sys/var.h> defines vario::v
@@ -319,6 +327,7 @@
#ifdef __sun__
// <fenv.h> defines these as members of fex_numeric_t
+#undef i
#undef l
#undef f
#undef d
@@ -328,8 +337,11 @@
#undef ptr
// <sys/timespec_util.h> uses this as parameter
#undef r
-// <stdlib.h> uses this as member of drand48_data
+// <stdlib.h> uses these as members of drand48_data
+#undef a
#undef x
+// <string.h> defines this as a parameter of timingsafe_memcmp
+#undef n
#endif
#ifdef __VXWORKS__
@@ -392,4 +404,8 @@
# endif
#endif
+// PR libstdc++/119496
+// _Temporary_buffer used to have a member with this name
+#define requested_size 1
+
#include <bits/stdc++.h>
diff --git a/libstdc++-v3/testsuite/18_support/comparisons/type_order/1.cc b/libstdc++-v3/testsuite/18_support/comparisons/type_order/1.cc
new file mode 100644
index 0000000..b510494
--- /dev/null
+++ b/libstdc++-v3/testsuite/18_support/comparisons/type_order/1.cc
@@ -0,0 +1,95 @@
+// Copyright (C) 2025 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do compile { target c++26 } }
+
+#include <compare>
+
+#if __cpp_lib_type_order != 202506L
+# error "__cpp_lib_type_order != 202506"
+#endif
+
+static_assert (std::is_same_v <decltype (std::type_order <int, int>::value),
+ const std::strong_ordering>);
+static_assert (std::is_same_v <decltype (std::type_order_v <char, short>),
+ const std::strong_ordering>);
+struct S;
+struct T;
+template <typename T>
+struct U
+{
+};
+typedef int int2;
+struct V {};
+namespace
+{
+ struct W {};
+}
+
+template <typename T, typename U>
+struct eq
+{
+ constexpr eq ()
+ {
+ static_assert (std::type_order <T, U>::value == std::strong_ordering::equal);
+ static_assert (std::type_order <U, T>::value == std::strong_ordering::equal);
+ static_assert (std::type_order_v <T, U> == std::strong_ordering::equal);
+ static_assert (std::type_order_v <U, T> == std::strong_ordering::equal);
+ }
+};
+template <typename T, typename U>
+struct ne
+{
+ constexpr ne ()
+ {
+ static_assert (std::type_order <T, U>::value != std::strong_ordering::equal);
+ static_assert (std::type_order <U, T>::value != std::strong_ordering::equal);
+ static_assert (std::type_order <T, U>::value == std::strong_ordering::greater
+ ? std::type_order <U, T>::value == std::strong_ordering::less
+ : std::type_order <U, T>::value == std::strong_ordering::greater);
+ static_assert (std::type_order_v <T, U> != std::strong_ordering::equal);
+ static_assert (std::type_order_v <U, T> != std::strong_ordering::equal);
+ static_assert (std::type_order_v <T, U> == std::strong_ordering::greater
+ ? std::type_order_v <U, T> == std::strong_ordering::less
+ : std::type_order_v <U, T> == std::strong_ordering::greater);
+ }
+};
+
+constexpr eq <void, void> a;
+constexpr eq <const void, const void> b;
+constexpr eq <int, int> c;
+constexpr eq <long int, long int> d;
+constexpr eq <const volatile unsigned, const volatile unsigned> e;
+constexpr eq <S, S> f;
+constexpr eq <U <int>, U <int>> g;
+constexpr eq <unsigned[2], unsigned[2]> h;
+constexpr eq <int, int2> i;
+constexpr eq <int (*) (int, long), int (*) (int, long)> j;
+constexpr ne <int, long> k;
+constexpr ne <const int, int> l;
+constexpr ne <S, T> m;
+constexpr ne <int &, int &&> n;
+constexpr ne <U <S>, U <T>> o;
+constexpr ne <U <short>, U <char>> p;
+static_assert (std::type_order_v <S, T> != std::strong_ordering::less
+ || std::type_order_v <T, V> != std::strong_ordering::less
+ || std::type_order_v <S, V> == std::strong_ordering::less);
+constexpr ne <int (*) (int, long), int (*) (int, int)> q;
+constexpr eq <W, W> r;
+constexpr ne <V, W> s;
+constexpr eq <U <W>, U <W>> t;
+constexpr ne <U <V>, U <W>> u;
diff --git a/libstdc++-v3/testsuite/18_support/exception_ptr/exception_ptr_cast.cc b/libstdc++-v3/testsuite/18_support/exception_ptr/exception_ptr_cast.cc
new file mode 100644
index 0000000..6a6fbfe
--- /dev/null
+++ b/libstdc++-v3/testsuite/18_support/exception_ptr/exception_ptr_cast.cc
@@ -0,0 +1,81 @@
+// { dg-do run { target c++26 } }
+
+// Copyright (C) 2025 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// exception_ptr_cast.
+
+#include <exception>
+#include <testsuite_hooks.h>
+
+#if __cpp_lib_exception_ptr_cast != 202506L
+# error "__cpp_lib_exception_ptr_cast != 202506"
+#endif
+
+struct A { int a; };
+struct B : A {};
+struct C : B {};
+struct D {};
+struct E : virtual C { int e; virtual ~E () {} };
+struct F : virtual E, virtual C { int f; };
+struct G : virtual F, virtual C, virtual E {
+ G () : g (4) { a = 1; e = 2; f = 3; } int g;
+};
+
+void test01()
+{
+ auto a = std::make_exception_ptr(C{ 42 });
+ auto b = std::exception_ptr_cast<C>(a);
+ VERIFY( b != nullptr );
+ VERIFY( b->a == 42 );
+ auto c = std::exception_ptr_cast<B>(a);
+ VERIFY( c == static_cast<const B*>(b) );
+ auto d = std::exception_ptr_cast<A>(a);
+ VERIFY( d == static_cast<const A*>(b) );
+ auto e = std::exception_ptr_cast<D>(a);
+ VERIFY( e == nullptr );
+ auto f = std::make_exception_ptr(42L);
+ auto g = std::exception_ptr_cast<long>(f);
+ VERIFY( g != nullptr );
+ VERIFY( *g == 42L );
+ try
+ {
+ throw G ();
+ }
+ catch (...)
+ {
+ auto h = std::current_exception();
+ auto i = std::exception_ptr_cast<G>(h);
+ VERIFY( i != nullptr );
+ VERIFY( i->a == 1 && i->e == 2 && i->f == 3 && i->g == 4 );
+ auto j = std::exception_ptr_cast<A>(h);
+ VERIFY( j == static_cast<const A*>(i) );
+ auto k = std::exception_ptr_cast<C>(h);
+ VERIFY( k == static_cast<const C*>(i) );
+ auto l = std::exception_ptr_cast<E>(h);
+ VERIFY( l == static_cast<const E*>(i) );
+ auto m = std::exception_ptr_cast<F>(h);
+ VERIFY( m == static_cast<const F*>(i) );
+ auto n = std::exception_ptr_cast<G>(a);
+ VERIFY( n == nullptr );
+ }
+}
+
+int main()
+{
+ test01();
+}
diff --git a/libstdc++-v3/testsuite/18_support/headers/ciso646/macros-2.cc b/libstdc++-v3/testsuite/18_support/headers/ciso646/macros-2.cc
new file mode 100644
index 0000000..a492924
--- /dev/null
+++ b/libstdc++-v3/testsuite/18_support/headers/ciso646/macros-2.cc
@@ -0,0 +1,7 @@
+// { dg-options " -Wdeprecated -fno-operator-names" }
+// { dg-do preprocess }
+
+// Should get a warning for C++20 and up without -D_GLIBCXX_USE_DEPRECATED=0
+// { dg-warning "not a standard header" "" { target c++20 } 0 }
+
+#include "macros.cc"
diff --git a/libstdc++-v3/testsuite/18_support/headers/ciso646/macros.cc b/libstdc++-v3/testsuite/18_support/headers/ciso646/macros.cc
index ab3a041..0cb5168 100644
--- a/libstdc++-v3/testsuite/18_support/headers/ciso646/macros.cc
+++ b/libstdc++-v3/testsuite/18_support/headers/ciso646/macros.cc
@@ -3,7 +3,6 @@
#include <ciso646>
-// { dg-warning "deprecated" "" { target c++17_only } 0 }
// { dg-error "not a standard header" "" { target c++20 } 0 }
#ifdef and
diff --git a/libstdc++-v3/testsuite/20_util/aligned_storage/value.cc b/libstdc++-v3/testsuite/20_util/aligned_storage/value.cc
index e2c6f7b5..6a2c424 100644
--- a/libstdc++-v3/testsuite/20_util/aligned_storage/value.cc
+++ b/libstdc++-v3/testsuite/20_util/aligned_storage/value.cc
@@ -21,14 +21,14 @@
#include <type_traits>
#include <testsuite_tr1.h>
-struct MSAlignType { } __attribute__((__aligned__));
+struct MSAlignType { } __attribute__((__aligned__));
void test01()
{
using std::aligned_storage;
using std::alignment_of;
using namespace __gnu_test;
-
+
const std::size_t align_c = alignment_of<char>::value;
static_assert(sizeof(aligned_storage<4, align_c>::type) >= 4, "");
static_assert(__alignof__(aligned_storage<4, align_c>::type) == align_c, "");
@@ -55,9 +55,11 @@ void test01()
static_assert(__alignof__(aligned_storage<11, align_ct>::type) == align_ct,
"");
+#if !_GLIBCXX_INLINE_VERSION
const std::size_t align_msa = alignment_of<MSAlignType>::value;
static_assert(sizeof(aligned_storage<5>::type) >= 5, "");
static_assert(__alignof__(aligned_storage<5>::type) == align_msa, "");
+#endif
}
// { dg-warning "deprecated" "" { target c++23 } 0 }
diff --git a/libstdc++-v3/testsuite/20_util/bitset/cons/1.cc b/libstdc++-v3/testsuite/20_util/bitset/cons/1.cc
index 0a40b6c..6441332 100644
--- a/libstdc++-v3/testsuite/20_util/bitset/cons/1.cc
+++ b/libstdc++-v3/testsuite/20_util/bitset/cons/1.cc
@@ -47,6 +47,7 @@ void test01(void)
const size_t n3 = 128;
try {
std::bitset<n3> bit03(str01, 5);
+ VERIFY(false);
}
catch(std::invalid_argument& fail) {
VERIFY( true );
diff --git a/libstdc++-v3/testsuite/20_util/bitset/cons/6282.cc b/libstdc++-v3/testsuite/20_util/bitset/cons/6282.cc
index fafa9fc..ee348c3 100644
--- a/libstdc++-v3/testsuite/20_util/bitset/cons/6282.cc
+++ b/libstdc++-v3/testsuite/20_util/bitset/cons/6282.cc
@@ -39,6 +39,8 @@ void test02(void)
std::bitset<0> z3(std::string("10101010101"));
VERIFY( z3.any() == false );
+ VERIFY( z1.to_ulong() == 0 );
+ VERIFY( (z1.to_string<char,char_traits<char>,allocator<char> >().empty() ));
try {
z1.set(0);
VERIFY( false );
@@ -49,9 +51,6 @@ void test02(void)
catch(...) {
VERIFY( false );
}
-
- VERIFY( z1.to_ulong() == 0 );
- VERIFY( (z1.to_string<char,char_traits<char>,allocator<char> >().empty() ));
}
int main()
diff --git a/libstdc++-v3/testsuite/20_util/bitset/cons/string_view.cc b/libstdc++-v3/testsuite/20_util/bitset/cons/string_view.cc
new file mode 100644
index 0000000..ec3a6c86
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/bitset/cons/string_view.cc
@@ -0,0 +1,132 @@
+// C++26 [bitset.cons]
+
+// { dg-do run { target c++26 } }
+
+#ifndef C
+# define C char
+# define L(s) s
+#endif
+
+#include <bitset>
+#include <string>
+#include <string_view>
+#include <algorithm> // std::reverse, std::transform
+#include <stdexcept>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+ // template<_C,_T>
+ // constexpr explicit
+ // bitset(const basic_string_view<_C,_T>,
+ // size_type pos, size_type n, _C zero, _C one)
+ try {
+ std::basic_string_view<C> str(L("stuff smith sessions"));
+ const std::size_t n = 128;
+ std::bitset<n> bit(str, 5);
+ VERIFY(false);
+ }
+ catch(std::invalid_argument& fail) {
+ VERIFY( true );
+ }
+ catch(...) {
+ VERIFY( false );
+ }
+
+ try {
+ std::basic_string_view<C> str(L("010101000011"));
+ const std::size_t n = 128;
+ const auto sz = str.size();
+ std::bitset<n> bit(str, 0);
+ std::basic_string<C> str02;
+ for (std::size_t i = 0; i < sz; ++i)
+ str02 += (bit.test(i) ? C('1') : C('0'));
+ std::reverse(str02.begin(), str02.end());
+ VERIFY( str02 == str );
+ }
+ catch(std::invalid_argument& fail) {
+ VERIFY( false );
+ }
+ catch(...) {
+ VERIFY( false );
+ }
+
+ // substring<C> "010101000011"
+ // "10100001"
+ try {
+ std::basic_string_view<C> str(L("010101000011"));
+ const std::size_t n = 128;
+ const auto sz = 8;
+ std::bitset<n> bit(str, 3, sz);
+ std::basic_string<C> str02;
+ for (std::size_t i = 0; i < sz; ++i)
+ str02 += (bit.test(i) ? C('1') : C('0'));
+ std::reverse(str02.begin(), str02.end());
+ VERIFY( str02 == str.substr(3, sz) );
+ }
+ catch(std::invalid_argument& fail) {
+ VERIFY( false );
+ }
+ catch(...) {
+ VERIFY( false );
+ }
+
+ // "abababaaaabb", zero = 'a', one = 'b'
+ try {
+ std::basic_string_view<C> str(L("010101000011"));
+ const std::size_t n = 128;
+ const auto sz = str.size();
+ std::basic_string<C> str02(str);
+ std::transform(str02.cbegin(), str02.cend(), str02.begin(), [](auto c) {
+ return (c - C('0')) + C('a');
+ });
+ std::basic_string_view<C> str03(str02);
+ std::bitset<n> bit(str03, 0, 100, C('a'), C('b'));
+ std::basic_string<C> str04;
+ for (std::size_t i = 0; i < sz; ++i)
+ str04 += (bit.test(i) ? C('1') : C('0'));
+ std::reverse(str04.begin(), str04.end());
+ VERIFY( str04 == str );
+ }
+ catch(std::invalid_argument& fail) {
+ VERIFY( false );
+ }
+ catch(...) {
+ VERIFY( false );
+ }
+
+ // "aba0aba", zero = 'a', one = 'b', '0' appears
+ try {
+ const std::size_t n = 128;
+ std::basic_string_view<C> str05(L("aba0aba"));
+ std::bitset<n> bit(str05, 0, 100, C('a'), C('b'));
+ VERIFY( false );
+ }
+ catch(std::invalid_argument& fail) {
+ VERIFY( true );
+ }
+ catch(...) {
+ VERIFY( false );
+ }
+
+ // pos > str.size()
+ try {
+ std::basic_string_view<C> str(L("010101000011"));
+ const std::size_t n = 128;
+ const auto sz = str.size();
+ std::bitset<n> bit(str, sz + 1, 100);
+ VERIFY( false );
+ }
+ catch(std::out_of_range& fail) {
+ VERIFY( true );
+ }
+ catch(...) {
+ VERIFY( false );
+ }
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/20_util/bitset/cons/string_view_wide.cc b/libstdc++-v3/testsuite/20_util/bitset/cons/string_view_wide.cc
new file mode 100644
index 0000000..b53fe74
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/bitset/cons/string_view_wide.cc
@@ -0,0 +1,8 @@
+// C++26 [bitset.cons]
+
+// { dg-do run { target c++26 } }
+
+#define C wchar_t
+#define L(s) L ## s
+
+#include "./string_view.cc"
diff --git a/libstdc++-v3/testsuite/20_util/copyable_function/call.cc b/libstdc++-v3/testsuite/20_util/copyable_function/call.cc
new file mode 100644
index 0000000..0ac5348
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/copyable_function/call.cc
@@ -0,0 +1,225 @@
+// { dg-do run { target c++26 } }
+// { dg-require-effective-target hosted }
+
+#include <functional>
+#include <utility>
+#include <testsuite_hooks.h>
+
+using std::copyable_function;
+
+using std::is_same_v;
+using std::is_invocable_v;
+using std::is_nothrow_invocable_v;
+using std::invoke_result_t;
+
+// Check return types
+static_assert( is_same_v<void, invoke_result_t<copyable_function<void()>>> );
+static_assert( is_same_v<int, invoke_result_t<copyable_function<int()>>> );
+static_assert( is_same_v<int&, invoke_result_t<copyable_function<int&()>>> );
+
+// With const qualifier
+static_assert( ! is_invocable_v< copyable_function<void()> const > );
+static_assert( ! is_invocable_v< copyable_function<void()> const &> );
+static_assert( is_invocable_v< copyable_function<void() const> > );
+static_assert( is_invocable_v< copyable_function<void() const> &> );
+static_assert( is_invocable_v< copyable_function<void() const> const > );
+static_assert( is_invocable_v< copyable_function<void() const> const &> );
+
+// With no ref-qualifier
+static_assert( is_invocable_v< copyable_function<void()> > );
+static_assert( is_invocable_v< copyable_function<void()> &> );
+static_assert( is_invocable_v< copyable_function<void() const> > );
+static_assert( is_invocable_v< copyable_function<void() const> &> );
+static_assert( is_invocable_v< copyable_function<void() const> const > );
+static_assert( is_invocable_v< copyable_function<void() const> const &> );
+
+// With & ref-qualifier
+static_assert( ! is_invocable_v< copyable_function<void()&> > );
+static_assert( is_invocable_v< copyable_function<void()&> &> );
+static_assert( is_invocable_v< copyable_function<void() const&> > );
+static_assert( is_invocable_v< copyable_function<void() const&> &> );
+static_assert( is_invocable_v< copyable_function<void() const&> const > );
+static_assert( is_invocable_v< copyable_function<void() const&> const &> );
+
+// With && ref-qualifier
+static_assert( is_invocable_v< copyable_function<void()&&> > );
+static_assert( ! is_invocable_v< copyable_function<void()&&> &> );
+static_assert( is_invocable_v< copyable_function<void() const&&> > );
+static_assert( ! is_invocable_v< copyable_function<void() const&&> &> );
+static_assert( is_invocable_v< copyable_function<void() const&&> const > );
+static_assert( ! is_invocable_v< copyable_function<void() const&&> const &> );
+
+// With noexcept-specifier
+static_assert( ! is_nothrow_invocable_v< copyable_function<void()> > );
+static_assert( ! is_nothrow_invocable_v< copyable_function<void() noexcept(false)> > );
+static_assert( is_nothrow_invocable_v< copyable_function<void() noexcept> > );
+static_assert( is_nothrow_invocable_v< copyable_function<void()& noexcept>& > );
+
+void
+test01()
+{
+ struct F
+ {
+ int operator()() { return 0; }
+ int operator()() const { return 1; }
+ };
+
+ copyable_function<int()> f0{F{}};
+ VERIFY( f0() == 0 );
+ VERIFY( std::move(f0)() == 0 );
+
+ copyable_function<int() const> f1{F{}};
+ VERIFY( f1() == 1 );
+ VERIFY( std::as_const(f1)() == 1 );
+ VERIFY( std::move(f1)() == 1 );
+ VERIFY( std::move(std::as_const(f1))() == 1 );
+
+ copyable_function<int()&> f2{F{}};
+ VERIFY( f2() == 0 );
+ // Not rvalue-callable: std::move(f2)()
+
+ copyable_function<int() const&> f3{F{}};
+ VERIFY( f3() == 1 );
+ VERIFY( std::as_const(f3)() == 1 );
+ VERIFY( std::move(f3)() == 1 );
+ VERIFY( std::move(std::as_const(f3))() == 1 );
+
+ copyable_function<int()&&> f4{F{}};
+ // Not lvalue-callable: f4()
+ VERIFY( std::move(f4)() == 0 );
+
+ copyable_function<int() const&&> f5{F{}};
+ // Not lvalue-callable: f5()
+ VERIFY( std::move(f5)() == 1 );
+ VERIFY( std::move(std::as_const(f5))() == 1 );
+}
+
+void
+test02()
+{
+ struct F
+ {
+ int operator()() & { return 0; }
+ int operator()() && { return 1; }
+ };
+
+ copyable_function<int()> f0{F{}};
+ VERIFY( f0() == 0 );
+ VERIFY( std::move(f0)() == 0 );
+
+ copyable_function<int()&&> f1{F{}};
+ // Not lvalue callable: f1()
+ VERIFY( std::move(f1)() == 1 );
+
+ copyable_function<int()&> f2{F{}};
+ VERIFY( f2() == 0 );
+ // Not rvalue-callable: std::move(f2)()
+}
+
+void
+test03()
+{
+ struct F
+ {
+ int operator()() const & { return 0; }
+ int operator()() && { return 1; }
+ };
+
+ copyable_function<int()> f0{F{}};
+ VERIFY( f0() == 0 );
+ VERIFY( std::move(f0)() == 0 );
+
+ copyable_function<int()&&> f1{F{}};
+ // Not lvalue callable: f1()
+ VERIFY( std::move(f1)() == 1 );
+
+ copyable_function<int() const> f2{F{}};
+ VERIFY( f2() == 0 );
+ VERIFY( std::as_const(f2)() == 0 );
+ VERIFY( std::move(f2)() == 0 );
+ VERIFY( std::move(std::as_const(f2))() == 0 );
+
+ copyable_function<int() const &&> f3{F{}};
+ // Not lvalue callable: f3()
+ VERIFY( std::move(f3)() == 0 );
+ VERIFY( std::move(std::as_const(f3))() == 0 );
+
+ copyable_function<int() const &> f4{F{}};
+ VERIFY( f4() == 0 );
+ VERIFY( std::as_const(f4)() == 0 );
+ // Not rvalue-callable: std::move(f4)()
+}
+
+void
+test04()
+{
+ struct F
+ {
+ int operator()() & { return 0; }
+ int operator()() && { return 1; }
+ int operator()() const & { return 2; }
+ int operator()() const && { return 3; }
+ };
+
+ copyable_function<int()> f0{F{}};
+ VERIFY( f0() == 0 );
+ VERIFY( std::move(f0)() == 0 );
+
+ copyable_function<int()&> f1{F{}};
+ VERIFY( f1() == 0 );
+ // Not rvalue-callable: std::move(f1)()
+
+ copyable_function<int()&&> f2{F{}};
+ // Not lvalue callable: f2()
+ VERIFY( std::move(f2)() == 1 );
+
+ copyable_function<int() const> f3{F{}};
+ VERIFY( f3() == 2 );
+ VERIFY( std::as_const(f3)() == 2 );
+ VERIFY( std::move(f3)() == 2 );
+ VERIFY( std::move(std::as_const(f3))() == 2 );
+
+ copyable_function<int() const &> f4{F{}};
+ VERIFY( f4() == 2 );
+ VERIFY( std::as_const(f4)() == 2 );
+ // Not rvalue-callable: std::move(f4)()
+
+ copyable_function<int() const &&> f5{F{}};
+ // Not lvalue callable: f5()
+ VERIFY( std::move(f5)() == 3 );
+ VERIFY( std::move(std::as_const(f5))() == 3 );
+}
+
+void
+test05()
+{
+ int (*fp)() = [] { return 0; };
+ copyable_function<int()> f0{fp};
+ VERIFY( f0() == 0 );
+ VERIFY( std::move(f0)() == 0 );
+
+ const copyable_function<int() const> f1{fp};
+ VERIFY( f1() == 0 );
+ VERIFY( std::move(f1)() == 0 );
+}
+
+struct Incomplete;
+enum CompleteEnum : int;
+
+void
+test_params()
+{
+ std::copyable_function<void(Incomplete&)> f1;
+ std::copyable_function<void(Incomplete&&)> f2;
+ std::copyable_function<void(CompleteEnum)> f4;
+}
+
+int main()
+{
+ test01();
+ test02();
+ test03();
+ test04();
+ test05();
+ test_params();
+}
diff --git a/libstdc++-v3/testsuite/20_util/copyable_function/cons.cc b/libstdc++-v3/testsuite/20_util/copyable_function/cons.cc
new file mode 100644
index 0000000..8d422dc
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/copyable_function/cons.cc
@@ -0,0 +1,126 @@
+// { dg-do compile { target c++26 } }
+// { dg-require-effective-target hosted }
+// { dg-add-options no_pch }
+
+#include <functional>
+
+#ifndef __cpp_lib_copyable_function
+# error "Feature-test macro for copyable_function missing in <functional>"
+#elif __cpp_lib_copyable_function != 202306L
+# error "Feature-test macro for copyable_function has wrong value in <functional>"
+#endif
+
+using std::copyable_function;
+
+using std::is_constructible_v;
+using std::is_copy_constructible_v;
+using std::is_nothrow_default_constructible_v;
+using std::is_nothrow_move_constructible_v;
+using std::is_nothrow_constructible_v;
+using std::nullptr_t;
+using std::in_place_type_t;
+
+static_assert( is_nothrow_default_constructible_v<copyable_function<void()>> );
+static_assert( is_nothrow_constructible_v<copyable_function<void()>, nullptr_t> );
+static_assert( is_nothrow_move_constructible_v<copyable_function<void()>> );
+static_assert( is_copy_constructible_v<copyable_function<void()>> );
+
+static_assert( is_constructible_v<copyable_function<void()>, void()> );
+static_assert( is_constructible_v<copyable_function<void()>, void(&)()> );
+static_assert( is_constructible_v<copyable_function<void()>, void(*)()> );
+static_assert( is_constructible_v<copyable_function<void()>, int()> );
+static_assert( is_constructible_v<copyable_function<void()>, int(&)()> );
+static_assert( is_constructible_v<copyable_function<void()>, int(*)()> );
+static_assert( ! is_constructible_v<copyable_function<void()>, void(int)> );
+static_assert( is_constructible_v<copyable_function<void(int)>, void(int)> );
+
+static_assert( is_constructible_v<copyable_function<void(int)>,
+ in_place_type_t<void(*)(int)>, void(int)> );
+
+static_assert( is_constructible_v<copyable_function<void()>,
+ void() noexcept> );
+static_assert( is_constructible_v<copyable_function<void() noexcept>,
+ void() noexcept> );
+static_assert( ! is_constructible_v<copyable_function<void() noexcept>,
+ void() > );
+
+struct Q
+{
+ void operator()() const &;
+ void operator()() &&;
+};
+
+static_assert( is_constructible_v<copyable_function<void()>, Q> );
+static_assert( is_constructible_v<copyable_function<void() const>, Q> );
+static_assert( is_constructible_v<copyable_function<void() &>, Q> );
+static_assert( is_constructible_v<copyable_function<void() const &>, Q> );
+static_assert( is_constructible_v<copyable_function<void() &&>, Q> );
+static_assert( is_constructible_v<copyable_function<void() const &&>, Q> );
+
+struct R
+{
+ void operator()() &;
+ void operator()() &&;
+};
+
+static_assert( is_constructible_v<copyable_function<void()>, R> );
+static_assert( is_constructible_v<copyable_function<void()&>, R> );
+static_assert( is_constructible_v<copyable_function<void()&&>, R> );
+static_assert( ! is_constructible_v<copyable_function<void() const>, R> );
+static_assert( ! is_constructible_v<copyable_function<void() const&>, R> );
+static_assert( ! is_constructible_v<copyable_function<void() const&&>, R> );
+
+// The following nothrow-constructible guarantees are a GCC extension,
+// not required by the standard.
+
+static_assert( is_nothrow_constructible_v<copyable_function<void()>, void()> );
+static_assert( is_nothrow_constructible_v<copyable_function<void(int)>,
+ in_place_type_t<void(*)(int)>,
+ void(int)> );
+
+// These types are all small and nothrow move constructible
+struct F { void operator()(); };
+struct G { void operator()() const; };
+static_assert( is_nothrow_constructible_v<copyable_function<void()>, F> );
+static_assert( is_nothrow_constructible_v<copyable_function<void()>, G> );
+static_assert( is_nothrow_constructible_v<copyable_function<void() const>, G> );
+
+struct H {
+ H(int);
+ H(int, int) noexcept;
+ void operator()() noexcept;
+};
+static_assert( is_nothrow_constructible_v<copyable_function<void()>, H> );
+static_assert( is_nothrow_constructible_v<copyable_function<void() noexcept>,
+ H> );
+static_assert( ! is_nothrow_constructible_v<copyable_function<void() noexcept>,
+ in_place_type_t<H>, int> );
+static_assert( is_nothrow_constructible_v<copyable_function<void() noexcept>,
+ in_place_type_t<H>, int, int> );
+
+struct I {
+ I(int, const char*);
+ I(std::initializer_list<char>);
+ int operator()() const noexcept;
+};
+
+static_assert( is_constructible_v<copyable_function<void()>,
+ std::in_place_type_t<I>,
+ int, const char*> );
+static_assert( is_constructible_v<copyable_function<void()>,
+ std::in_place_type_t<I>,
+ std::initializer_list<char>> );
+
+void
+test_instantiation()
+{
+ // Instantiate the constructor bodies
+ copyable_function<void()> f0;
+ copyable_function<void()> f1(nullptr);
+ copyable_function<void()> f2( I(1, "two") );
+ copyable_function<void()> f3(std::in_place_type<I>, 3, "four");
+ copyable_function<void()> f4(std::in_place_type<I>, // PR libstdc++/102825
+ { 'P', 'R', '1', '0', '2', '8', '2', '5'});
+ auto f5 = std::move(f4);
+ f4 = std::move(f5);
+}
diff --git a/libstdc++-v3/testsuite/20_util/copyable_function/conv.cc b/libstdc++-v3/testsuite/20_util/copyable_function/conv.cc
new file mode 100644
index 0000000..11c839b
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/copyable_function/conv.cc
@@ -0,0 +1,286 @@
+// { dg-do run { target c++26 } }
+// { dg-require-effective-target hosted }
+
+#include <functional>
+#include <string_view>
+#include <testsuite_hooks.h>
+
+using std::copyable_function;
+
+static_assert( !std::is_constructible_v<std::copyable_function<void()>,
+ std::copyable_function<void()&>> );
+static_assert( !std::is_constructible_v<std::copyable_function<void()>,
+ std::copyable_function<void()&&>> );
+static_assert( !std::is_constructible_v<std::copyable_function<void()&>,
+ std::copyable_function<void()&&>> );
+static_assert( !std::is_constructible_v<std::copyable_function<void() const>,
+ std::copyable_function<void()>> );
+
+using FuncType = int(int);
+
+// Top level const qualifiers are ignored and decay is performed in parameters
+// of function_types.
+static_assert( std::is_same_v<std::copyable_function<void(int const)>,
+ std::copyable_function<void(int)>> );
+static_assert( std::is_same_v<std::copyable_function<void(int[2])>,
+ std::copyable_function<void(int*)>>);
+static_assert( std::is_same_v<std::copyable_function<void(int[])>,
+ std::copyable_function<void(int*)>>);
+static_assert( std::is_same_v<std::copyable_function<void(int const[5])>,
+ std::copyable_function<void(int const*)>>);
+static_assert( std::is_same_v<std::copyable_function<void(FuncType)>,
+ std::copyable_function<void(FuncType*)>>);
+
+// Non-trivial args, guarantess that type is not passed by copy
+struct CountedArg
+{
+ CountedArg() = default;
+ CountedArg(const CountedArg& f) noexcept : counter(f.counter) { ++counter; }
+ CountedArg& operator=(CountedArg&&) = delete;
+
+ int counter = 0;
+};
+CountedArg const c;
+
+// When copyable_function or move_only_function is constructed from other copyable_function,
+// the compiler can avoid double indirection per C++26 [func.wrap.general] p2.
+
+void
+test01()
+{
+ auto f = [](CountedArg const& arg) noexcept { return arg.counter; };
+ std::copyable_function<int(CountedArg) const noexcept> c1(f);
+ using CF = std::copyable_function<int(CountedArg) const noexcept>;
+ VERIFY( c1(c) == 1 );
+
+ std::copyable_function<int(CountedArg) const> c2a(c1);
+ VERIFY( c2a(c) == 1 );
+
+ std::copyable_function<int(CountedArg) const> c2b(static_cast<CF>(c1));
+ VERIFY( c2b(c) == 1 );
+
+ std::move_only_function<int(CountedArg) const> m2a(c1);
+ VERIFY( m2a(c) == 1 );
+
+ std::move_only_function<int(CountedArg) const> m2b(static_cast<CF>(c1));
+ VERIFY( m2b(c) == 1 );
+
+ std::copyable_function<int(CountedArg)> c3a(c1);
+ VERIFY( c3a(c) == 1 );
+
+ std::copyable_function<int(CountedArg)> c3b(static_cast<CF>(c1));
+ VERIFY( c3b(c) == 1 );
+
+ std::move_only_function<int(CountedArg)> m3a(c1);
+ VERIFY( m3a(c) == 1 );
+
+ std::move_only_function<int(CountedArg)> m3b(static_cast<CF>(c1));
+ VERIFY( m3b(c) == 1 );
+
+ // Invokers internally uses Counted&& for non-trivial types,
+ // sinature remain compatible.
+ std::copyable_function<int(CountedArg&&)> c4a(c1);
+ VERIFY( c4a({}) == 0 );
+
+ std::copyable_function<int(CountedArg&&)> c4b(static_cast<CF>(c1));
+ VERIFY( c4b({}) == 0 );
+
+ std::move_only_function<int(CountedArg&&)> m4a(c1);
+ VERIFY( m4a({}) == 0 );
+
+ std::move_only_function<int(CountedArg&&)> m4b(static_cast<CF>(c1));
+ VERIFY( m4b({}) == 0 );
+
+ std::copyable_function<int(CountedArg&&)&> c5a(c1);
+ VERIFY( c5a({}) == 0 );
+
+ std::copyable_function<int(CountedArg&&)&&> c5b(static_cast<CF>(c1));
+ VERIFY( std::move(c5b)({}) == 0 );
+
+ std::move_only_function<int(CountedArg&&)&> m5a(c1);
+ VERIFY( m5a({}) == 0 );
+
+ std::move_only_function<int(CountedArg&&)&&> m5b(static_cast<CF>(c1));
+ VERIFY( std::move(m5b)({}) == 0 );
+
+ // Incompatible signatures
+ std::copyable_function<long(CountedArg) const noexcept> c6a(c1);
+ VERIFY( c6a(c) == 2 );
+
+ std::copyable_function<long(CountedArg) const noexcept> c6b(static_cast<CF>(c1));
+ VERIFY( c6b(c) == 2 );
+
+ std::move_only_function<long(CountedArg) const noexcept> m6a(c1);
+ VERIFY( m6a(c) == 2 );
+
+ std::move_only_function<long(CountedArg) const noexcept> m6b(static_cast<CF>(c1));
+ VERIFY( m6b(c) == 2 );
+}
+
+void
+test02()
+{
+ auto f = [](CountedArg const& arg) noexcept { return arg.counter; };
+ std::copyable_function<int(CountedArg) const noexcept> c1(f);
+ using CF = std::copyable_function<int(CountedArg) const noexcept>;
+ VERIFY( c1(c) == 1 );
+
+ std::copyable_function<int(CountedArg) const> c2;
+ c2 = c1;
+ VERIFY( c2(c) == 1 );
+ c2 = static_cast<CF>(c1);
+ VERIFY( c2(c) == 1 );
+
+ std::move_only_function<int(CountedArg) const> m2;
+ m2 = c1;
+ VERIFY( m2(c) == 1 );
+ m2 = static_cast<CF>(c1);
+ VERIFY( m2(c) == 1 );
+
+ // Incompatible signatures
+ std::copyable_function<long(CountedArg) const noexcept> c3;
+ c3 = c1;
+ VERIFY( c3(c) == 2 );
+ c3 = static_cast<CF>(c1);
+ VERIFY( c3(c) == 2 );
+
+ std::move_only_function<long(CountedArg) const noexcept> m3;
+ m3 = c1;
+ VERIFY( m3(c) == 2 );
+ m3 = static_cast<CF>(c1);
+ VERIFY( m3(c) == 2 );
+}
+
+void
+test03()
+{
+ std::copyable_function<int(long) const noexcept> c1;
+ VERIFY( c1 == nullptr );
+
+ std::copyable_function<int(long) const> c2(c1);
+ VERIFY( c2 == nullptr );
+ c2 = c1;
+ VERIFY( c2 == nullptr );
+ c2 = std::move(c1);
+ VERIFY( c2 == nullptr );
+
+ std::copyable_function<bool(int) const> c3(std::move(c1));
+ VERIFY( c3 == nullptr );
+ c3 = c1;
+ VERIFY( c3 == nullptr );
+ c3 = std::move(c1);
+ VERIFY( c3 == nullptr );
+
+ // LWG4255 move_only_function constructor should recognize empty
+ // copyable_functions
+ std::move_only_function<int(long) const noexcept> m1(c1);
+ VERIFY( m1 == nullptr );
+ m1 = c1;
+ VERIFY( m1 == nullptr );
+ m1 = std::move(c1);
+ VERIFY( m1 == nullptr );
+
+ std::move_only_function<int(long) const> m2(c1);
+ VERIFY( m2 == nullptr );
+ m2 = c1;
+ VERIFY( m2 == nullptr );
+ m2 = std::move(c1);
+ VERIFY( m2 == nullptr );
+
+ std::move_only_function<bool(int) const> m3(std::move(c1));
+ VERIFY( m3 == nullptr );
+ m3 = c1;
+ VERIFY( m3 == nullptr );
+ m3 = std::move(c1);
+ VERIFY( m3 == nullptr );
+}
+
+void
+test04()
+{
+ struct F
+ {
+ int operator()(CountedArg const& arg) noexcept
+ { return arg.counter; }
+
+ int operator()(CountedArg const& arg) const noexcept
+ { return arg.counter + 1000; }
+ };
+
+ F f;
+ std::copyable_function<int(CountedArg) const> c1(f);
+ VERIFY( c1(c) == 1001 );
+
+ // Call const overload as std::copyable_function<int(CountedArg) const>
+ // inside td::copyable_function<int(CountedArg)> would do.
+ std::copyable_function<int(CountedArg)> c2(c1);
+ VERIFY( c2(c) == 1001 );
+ std::move_only_function<int(CountedArg)> m2(c1);
+ VERIFY( m2(c) == 1001 );
+
+ std::copyable_function<int(CountedArg)> m3(f);
+ VERIFY( m3(c) == 1 );
+}
+
+void
+test05()
+{
+ auto f = [](CountedArg const& arg) noexcept { return arg.counter; };
+ std::copyable_function<int(CountedArg)> w1(f);
+ // copyable_function stores copyable_function due incompatibile signatures
+ std::copyable_function<int(CountedArg const&)> w2(std::move(w1));
+ // copy is made when passing to int(CountedArg)
+ VERIFY( w2(c) == 1 );
+ // wrapped 3 times
+ w1 = std::move(w2);
+ VERIFY( w1(c) == 2 );
+ // wrapped 4 times
+ w2 = std::move(w1);
+ VERIFY( w2(c) == 2 );
+ // wrapped 5 times
+ w1 = std::move(w2);
+ VERIFY( w1(c) == 3 );
+}
+
+void
+test06()
+{
+ // No special interoperability with std::function
+ auto f = [](CountedArg const& arg) noexcept { return arg.counter; };
+ std::function<int(CountedArg)> f1(f);
+ std::copyable_function<int(CountedArg) const> c1(std::move(f1));
+ VERIFY( c1(c) == 2 );
+
+ std::copyable_function<int(CountedArg) const> c2(f);
+ std::function<int(CountedArg)> f2(c2);
+ VERIFY( f2(c) == 2 );
+}
+
+void
+test07()
+{
+ // Scalar types and small trivially move constructible types are passed
+ // by value to invoker. So int&& signature is not compatible for such types.
+ auto fi = [](CountedArg const& arg, int) noexcept { return arg.counter; };
+ std::copyable_function<int(CountedArg, int) const noexcept> ci1(fi);
+ VERIFY( ci1(c, 0) == 1 );
+ std::copyable_function<int(CountedArg, int&&) const noexcept> ci2(ci1);
+ VERIFY( ci2(c, 0) == 2 );
+
+ auto fs = [](CountedArg const& arg, std::string_view) noexcept { return arg.counter; };
+ std::copyable_function<int(CountedArg, std::string_view) const noexcept> cs1(fs);
+ VERIFY( cs1(c, "") == 1 );
+ std::copyable_function<int(CountedArg, std::string_view&&) const noexcept> cs2(cs1);
+ VERIFY( cs2(c, "") == 2 );
+}
+
+int main()
+{
+ test01();
+ test02();
+ test03();
+ test04();
+ test05();
+ test06();
+ test07();
+}
diff --git a/libstdc++-v3/testsuite/20_util/copyable_function/copy.cc b/libstdc++-v3/testsuite/20_util/copyable_function/copy.cc
new file mode 100644
index 0000000..6445a27
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/copyable_function/copy.cc
@@ -0,0 +1,154 @@
+// { dg-do run { target c++26 } }
+// { dg-require-effective-target hosted }
+
+#include <functional>
+#include <testsuite_hooks.h>
+
+using std::copyable_function;
+
+void
+test01()
+{
+ // Small type with non-throwing move constructor. Not allocated on the heap.
+ struct F
+ {
+ F() = default;
+ F(const F& f) : counters(f.counters) { ++counters.copy; }
+ F(F&& f) noexcept : counters(f.counters) { ++counters.move; }
+
+ F& operator=(F&&) = delete;
+
+ struct Counters
+ {
+ int copy = 0;
+ int move = 0;
+ } counters;
+
+ const Counters& operator()() const { return counters; }
+ };
+
+ F f;
+ std::copyable_function<const F::Counters&() const> m1(f);
+ VERIFY( m1().copy == 1 );
+ VERIFY( m1().move == 0 );
+
+ // This will copy construct a new target object
+ auto m2 = m1;
+ VERIFY( m1 != nullptr && m2 != nullptr );
+ VERIFY( m2().copy == 2 );
+ VERIFY( m2().move == 0 );
+
+ m1 = m2;
+ VERIFY( m1 != nullptr && m2 != nullptr );
+ VERIFY( m1().copy == 3 );
+ VERIFY( m1().move == 1 ); // Copies object first and then swaps
+
+ m1 = m1;
+ VERIFY( m1 != nullptr && m2 != nullptr );
+ VERIFY( m1().copy == 4 );
+ VERIFY( m1().move == 2 ); // Copies object first and then swaps
+
+ m2 = f;
+ VERIFY( m2().copy == 1 );
+ VERIFY( m2().move == 1 ); // Copy construct target object, then swap into m2.
+}
+
+void
+test02()
+{
+ // Move constructor is potentially throwing. Allocated on the heap.
+ struct F
+ {
+ F() = default;
+ F(const F& f) noexcept : counters(f.counters) { ++counters.copy; }
+ F(F&& f) noexcept(false) : counters(f.counters) { ++counters.move; }
+
+ F& operator=(F&&) = delete;
+
+ struct Counters
+ {
+ int copy = 0;
+ int move = 0;
+ } counters;
+
+ Counters operator()() const noexcept { return counters; }
+ };
+
+ F f;
+ std::copyable_function<F::Counters() const> m1(f);
+ VERIFY( m1().copy == 1 );
+ VERIFY( m1().move == 0 );
+
+ // The target object is on the heap, but we need to allocate new one
+ auto m2 = m1;
+ VERIFY( m1 != nullptr && m2 != nullptr );
+ VERIFY( m2().copy == 2 );
+ VERIFY( m2().move == 0 );
+
+ m1 = m2;
+ VERIFY( m1 != nullptr && m2 != nullptr );
+ VERIFY( m1().copy == 3 );
+ VERIFY( m1().move == 0 );
+
+ m1 = m1;
+ VERIFY( m1 != nullptr && m2 != nullptr );
+ VERIFY( m1().copy == 4 );
+ VERIFY( m1().move == 0 );
+
+ m2 = f;
+ VERIFY( m2().copy == 1 );
+ VERIFY( m2().move == 0 );
+}
+
+void
+test03()
+{
+ // Small type with non-throwing, but not non-trivial move constructor.
+ struct F
+ {
+ F(int i) noexcept : id(i) {}
+ F(const F& f) : id(f.id)
+ { if (id == 3) throw id; }
+ F(F&& f) noexcept : id(f.id) { }
+
+ int operator()() const
+ { return id; }
+
+ int id;
+ };
+
+ std::copyable_function<int() const> m1(std::in_place_type<F>, 1);
+ const std::copyable_function<int() const> m2(std::in_place_type<F>, 2);
+ const std::copyable_function<int() const> m3(std::in_place_type<F>, 3);
+
+ try
+ {
+ auto mc = m3;
+ VERIFY( false );
+ }
+ catch(int i)
+ {
+ VERIFY( i == 3 );
+ }
+
+ m1 = m2;
+ VERIFY( m1() == 2 );
+
+ try
+ {
+ m1 = m3;
+ VERIFY( false );
+ }
+ catch (int i)
+ {
+ VERIFY( i == 3 );
+ }
+ VERIFY( m1() == 2 );
+}
+
+int main()
+{
+ test01();
+ test02();
+ test03();
+}
diff --git a/libstdc++-v3/testsuite/20_util/copyable_function/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/copyable_function/incomplete_neg.cc
new file mode 100644
index 0000000..21ddde0
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/copyable_function/incomplete_neg.cc
@@ -0,0 +1,18 @@
+// { dg-do compile { target c++26 } }
+
+#include <functional>
+
+struct IncompleteClass;
+
+using T1 = std::copyable_function<int(IncompleteClass)>::result_type; // { dg-error "here" }
+using T2 = std::copyable_function<int(int, IncompleteClass)>::result_type; // { dg-error "here" }
+
+enum Enum {
+ x = [] {
+ // Enum enumeration is incomplete here
+ using T3 = std::copyable_function<int(Enum)>::result_type; // { dg-error "here" }
+ return T3(1);
+ }()
+};
+
+// { dg-error "static assertion failed" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/20_util/copyable_function/move.cc b/libstdc++-v3/testsuite/20_util/copyable_function/move.cc
new file mode 100644
index 0000000..ec9d0d1
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/copyable_function/move.cc
@@ -0,0 +1,120 @@
+// { dg-do run { target c++26 } }
+// { dg-require-effective-target hosted }
+
+#include <functional>
+#include <testsuite_hooks.h>
+
+using std::copyable_function;
+
+void
+test01()
+{
+ // Small type with non-throwing move constructor. Not allocated on the heap.
+ struct F
+ {
+ F() = default;
+ F(const F& f) : counters(f.counters) { ++counters.copy; }
+ F(F&& f) noexcept : counters(f.counters) { ++counters.move; }
+
+ F& operator=(F&&) = delete;
+
+ struct Counters
+ {
+ int copy = 0;
+ int move = 0;
+ } counters;
+
+ const Counters& operator()() const { return counters; }
+ };
+
+ F f;
+ std::copyable_function<const F::Counters&() const> m1(f);
+ VERIFY( m1().copy == 1 );
+ VERIFY( m1().move == 0 );
+
+ // Standard specifies move assigment as copy and swap
+ m1 = std::move(m1);
+ VERIFY( m1 != nullptr );
+ VERIFY( m1().copy == 1 );
+ VERIFY( m1().move == 0 );
+
+ // This will move construct a new target object and destroy the old one:
+ auto m2 = std::move(m1);
+ VERIFY( m1 == nullptr && m2 != nullptr );
+ VERIFY( m2().copy == 1 );
+ VERIFY( m2().move == 1 );
+
+ m1 = std::move(m2);
+ VERIFY( m1 != nullptr && m2 == nullptr );
+ VERIFY( m1().copy == 1 );
+ VERIFY( m1().move == 2 );
+
+ m2 = std::move(f);
+ VERIFY( m2().copy == 0 );
+ VERIFY( m2().move == 2 ); // Move construct target object, then swap into m2.
+ const int moves = m1().move + m2().move;
+ // This will do three moves:
+ swap(m1, m2);
+ VERIFY( m1().copy == 0 );
+ VERIFY( m2().copy == 1 );
+ VERIFY( (m1().move + m2().move) == (moves + 3) );
+}
+
+void
+test02()
+{
+ // Move constructor is potentially throwing. Allocated on the heap.
+ struct F
+ {
+ F() = default;
+ F(const F& f) noexcept : counters(f.counters) { ++counters.copy; }
+ F(F&& f) noexcept(false) : counters(f.counters) { ++counters.move; }
+
+ F& operator=(F&&) = delete;
+
+ struct Counters
+ {
+ int copy = 0;
+ int move = 0;
+ } counters;
+
+ Counters operator()() const noexcept { return counters; }
+ };
+
+ F f;
+ std::copyable_function<F::Counters() const> m1(f);
+ VERIFY( m1().copy == 1 );
+ VERIFY( m1().move == 0 );
+
+ m1 = std::move(m1);
+ VERIFY( m1 != nullptr );
+ VERIFY( m1().copy == 1 );
+ VERIFY( m1().move == 0 );
+
+ // The target object is on the heap so this just moves a pointer:
+ auto m2 = std::move(m1);
+ VERIFY( m1 == nullptr && m2 != nullptr );
+ VERIFY( m2().copy == 1 );
+ VERIFY( m2().move == 0 );
+
+ m1 = std::move(m2);
+ VERIFY( m1 != nullptr && m2 == nullptr );
+ VERIFY( m1().copy == 1 );
+ VERIFY( m1().move == 0 );
+
+ m2 = std::move(f);
+ VERIFY( m2().copy == 0 );
+ VERIFY( m2().move == 1 );
+ const int moves = m1().move + m2().move;
+ // This just swaps the pointers, so no moves:
+ swap(m1, m2);
+ VERIFY( m1().copy == 0 );
+ VERIFY( m2().copy == 1 );
+ VERIFY( (m1().move + m2().move) == moves );
+}
+
+int main()
+{
+ test01();
+ test02();
+}
diff --git a/libstdc++-v3/testsuite/20_util/expected/119714.cc b/libstdc++-v3/testsuite/20_util/expected/119714.cc
new file mode 100644
index 0000000..a8dc6e8
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/expected/119714.cc
@@ -0,0 +1,9 @@
+// { dg-do compile { target c++23 } }
+
+// PR libstdc++/119714 - constraint recursion with std::expected::operator==
+
+#include <expected>
+#include <vector>
+
+using I = std::vector<std::expected<int,int>>::iterator;
+static_assert(std::totally_ordered<I>);
diff --git a/libstdc++-v3/testsuite/20_util/expected/equality_constrained.cc b/libstdc++-v3/testsuite/20_util/expected/equality_constrained.cc
index 7f6cefa..a079d98 100644
--- a/libstdc++-v3/testsuite/20_util/expected/equality_constrained.cc
+++ b/libstdc++-v3/testsuite/20_util/expected/equality_constrained.cc
@@ -4,7 +4,7 @@
#ifndef __cpp_lib_constrained_equality
# error "Feature-test macro for constrained_equality missing in <expected>"
-#elif __cpp_lib_constrained_equality < 202411L // TODO: use final value
+#elif __cpp_lib_constrained_equality < 202411L
# error "Feature-test macro for constrained_equality has wrong value"
#endif
diff --git a/libstdc++-v3/testsuite/20_util/function/cons/70692.cc b/libstdc++-v3/testsuite/20_util/function/cons/70692.cc
index b15208a..f9e8fe3 100644
--- a/libstdc++-v3/testsuite/20_util/function/cons/70692.cc
+++ b/libstdc++-v3/testsuite/20_util/function/cons/70692.cc
@@ -11,4 +11,4 @@ int main()
std::function<const int&()> ff(f); // { dg-error "no matching function" }
std::function<long&&()> f2(f); // { dg-error "no matching function" }
}
-// { dg-error "std::(__8::)?enable_if" "" { target *-*-* } 0 }
+// { dg-error "std::enable_if" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/20_util/function_ref/assign.cc b/libstdc++-v3/testsuite/20_util/function_ref/assign.cc
new file mode 100644
index 0000000..9b02dc4
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/function_ref/assign.cc
@@ -0,0 +1,108 @@
+// { dg-do compile { target c++26 } }
+
+#include <functional>
+
+#ifndef __cpp_lib_function_ref
+# error "Feature-test macro for function_ref missing in <functional>"
+#elif __cpp_lib_function_ref != 202306L
+# error "Feature-test macro for function_ref has wrong value in <functional>"
+#endif
+
+using std::nontype;
+using std::nontype_t;
+using std::function_ref;
+
+using std::is_nothrow_move_assignable_v;
+using std::is_nothrow_copy_assignable_v;
+using std::is_nothrow_assignable_v;
+using std::is_assignable_v;
+using std::is_nothrow_swappable_v;
+using std::is_trivially_copyable_v;
+
+static_assert( is_nothrow_move_assignable_v<function_ref<void()>> );
+static_assert( is_nothrow_copy_assignable_v<function_ref<void()>> );
+static_assert( is_nothrow_swappable_v<function_ref<void()>> );
+
+static_assert( ! is_assignable_v<function_ref<void()>, std::nullptr_t> );
+
+static_assert( is_nothrow_assignable_v<function_ref<void()>, void()> );
+static_assert( is_nothrow_assignable_v<function_ref<void()>, void(&)()> );
+static_assert( is_nothrow_assignable_v<function_ref<void()>, void(*)()> );
+static_assert( is_nothrow_assignable_v<function_ref<void()>, int()> );
+static_assert( is_nothrow_assignable_v<function_ref<void()>, int(&)()> );
+static_assert( is_nothrow_assignable_v<function_ref<void()>, int(*)()> );
+static_assert( ! is_nothrow_assignable_v<function_ref<void()>, void(int)> );
+static_assert( is_nothrow_assignable_v<function_ref<void(int)>, void(int)> );
+
+static_assert( is_nothrow_assignable_v<function_ref<void()>,
+ void() noexcept> );
+static_assert( is_nothrow_assignable_v<function_ref<void() noexcept>,
+ void() noexcept> );
+static_assert( ! is_assignable_v<function_ref<void() noexcept>, void() > );
+
+struct S
+{
+ int x;
+ int f();
+};
+int funS(S);
+
+static_assert( is_nothrow_assignable_v<function_ref<int(S)>,
+ decltype(funS)> );
+static_assert( is_nothrow_assignable_v<function_ref<int(S)>,
+ decltype(&funS)> );
+static_assert( ! is_assignable_v<function_ref<int(S)>, decltype(&S::x)> );
+static_assert( ! is_assignable_v<function_ref<int(S)>, decltype(&S::f)> );
+
+static_assert( is_nothrow_assignable_v<function_ref<int(S)>,
+ nontype_t<funS>> );
+static_assert( is_nothrow_assignable_v<function_ref<int(S)>,
+ nontype_t<&funS>> );
+static_assert( is_nothrow_assignable_v<function_ref<int(S)>,
+ nontype_t<&S::x>> );
+static_assert( is_nothrow_assignable_v<function_ref<int(S)>,
+ nontype_t<&S::f>> );
+struct Q
+{
+ void operator()() const;
+};
+
+static_assert( ! is_assignable_v<function_ref<void()>, Q> );
+static_assert( ! is_assignable_v<function_ref<void()>, Q&> );
+static_assert( ! is_assignable_v<function_ref<void()>, const Q&> );
+static_assert( ! is_assignable_v<function_ref<void() const>, Q> );
+static_assert( ! is_assignable_v<function_ref<void() const>, Q&> );
+static_assert( ! is_assignable_v<function_ref<void() const>, const Q&> );
+
+static_assert( is_nothrow_assignable_v<function_ref<void()>,
+ nontype_t<Q{}>> );
+static_assert( is_nothrow_assignable_v<function_ref<void() const>,
+ nontype_t<Q{}>> );
+
+constexpr bool
+test_constexpr()
+{
+ function_ref<void(S)> fp(nontype<funS>);
+ fp = nontype<funS>;
+ fp = nontype<&funS>;
+ fp = nontype<&S::x>;
+ fp = nontype<&S::f>;
+
+ constexpr Q cq;
+ function_ref<void() const> fq(cq);
+ fq = nontype<cq>;
+ return true;
+}
+static_assert( test_constexpr() );
+
+void func();
+
+void
+test_instantiation()
+{
+ function_ref<void(S)> fp(funS);
+ fp = funS;
+ fp = &funS;
+
+ test_constexpr();
+}
diff --git a/libstdc++-v3/testsuite/20_util/function_ref/call.cc b/libstdc++-v3/testsuite/20_util/function_ref/call.cc
new file mode 100644
index 0000000..23253c3
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/function_ref/call.cc
@@ -0,0 +1,186 @@
+// { dg-do run { target c++26 } }
+
+#include <functional>
+#include <utility>
+#include <testsuite_hooks.h>
+
+using std::nontype;
+using std::function_ref;
+
+using std::is_same_v;
+using std::is_invocable_v;
+using std::is_nothrow_invocable_v;
+using std::invoke_result_t;
+
+// Check return types
+static_assert( is_same_v<void, invoke_result_t<function_ref<void()>>> );
+static_assert( is_same_v<int, invoke_result_t<function_ref<int()>>> );
+static_assert( is_same_v<int&, invoke_result_t<function_ref<int&()>>> );
+
+// Const qualier applies to target object
+static_assert( is_invocable_v< function_ref<void()> const > );
+static_assert( is_invocable_v< function_ref<void()> const &> );
+static_assert( is_invocable_v< function_ref<void() const> > );
+static_assert( is_invocable_v< function_ref<void() const> &> );
+static_assert( is_invocable_v< function_ref<void() const> const > );
+static_assert( is_invocable_v< function_ref<void() const> const &> );
+
+// With noexcept-specifier
+static_assert( ! is_nothrow_invocable_v< function_ref<void()> > );
+static_assert( ! is_nothrow_invocable_v< function_ref<void() noexcept(false)> > );
+static_assert( is_nothrow_invocable_v< function_ref<void() noexcept> > );
+
+void
+test01()
+{
+ struct F
+ {
+ int operator()() { return 0; }
+ int operator()() const { return 1; }
+ };
+
+ function_ref<int()> f0{F{}};
+ VERIFY( f0() == 0 );
+ VERIFY( std::move(f0)() == 0 );
+
+ function_ref<int()> f1{nontype<F{}>};
+ VERIFY( f1() == 1 );
+ VERIFY( std::move(f1)() == 1 );
+
+ function_ref<int() const> f2{F{}};
+ VERIFY( f2() == 1 );
+ VERIFY( std::as_const(f2)() == 1 );
+ VERIFY( std::move(f2)() == 1 );
+ VERIFY( std::move(std::as_const(f2))() == 1 );
+
+ function_ref<int() const> f3{nontype<F{}>};
+ VERIFY( f3() == 1 );
+ VERIFY( std::as_const(f3)() == 1 );
+ VERIFY( std::move(f3)() == 1 );
+ VERIFY( std::move(std::as_const(f3))() == 1 );
+}
+
+void
+test02()
+{
+ struct F
+ {
+ struct Arg {};
+ int operator()(Arg& arg) const { return 0; }
+ int operator()(const Arg& arg) const { return 1; }
+ };
+ F::Arg arg;
+
+ function_ref<int()> f0{std::nontype<F{}>, arg};
+ VERIFY( f0() == 0 );
+ VERIFY( std::move(f0)() == 0 );
+
+ function_ref<int() const> f1{std::nontype<F{}>, arg};
+ VERIFY( f1() == 1 );
+ VERIFY( std::as_const(f1)() == 1 );
+}
+
+void
+test03()
+{
+ struct F
+ {
+ struct Arg {};
+ int operator()(Arg* arg) const { return 0; }
+ int operator()(const Arg* arg) const { return 1; }
+ };
+ F::Arg arg;
+
+ function_ref<int()> f0{std::nontype<F{}>, &arg};
+ VERIFY( f0() == 0 );
+ VERIFY( std::move(f0)() == 0 );
+
+ function_ref<int() const> f1{std::nontype<F{}>, &arg};
+ VERIFY( f1() == 1 );
+ VERIFY( std::as_const(f1)() == 1 );
+}
+
+void
+test04()
+{
+ constexpr int (*fp)() = [] { return 0; };
+ function_ref<int()> f0{fp};
+ VERIFY( f0() == 0 );
+ VERIFY( std::move(f0)() == 0 );
+
+ function_ref<int()> f1{nontype<fp>};
+ VERIFY( f1() == 0 );
+ VERIFY( std::move(f1)() == 0 );
+
+ const function_ref<int() const> f2{fp};
+ VERIFY( f2() == 0 );
+ VERIFY( std::move(f2)() == 0 );
+
+ const function_ref<int() const> f3{nontype<fp>};
+ VERIFY( f2() == 0 );
+ VERIFY( std::move(f2)() == 0 );
+}
+
+using ftype = int(int);
+int twice(int x) { return x * 2; }
+int cube(int x) { return x * x * x; }
+int callback_ptr(ftype* f, int x) { return f(x); }
+int callback_ref(ftype& f, int x) { return f(x); }
+
+void
+test05()
+{
+
+ function_ref<int(int)> r1(nontype<&callback_ptr>, &twice);
+ VERIFY( r1(2) == 4 );
+ function_ref<int(int)> r2(nontype<&callback_ptr>, cube);
+ VERIFY( r2(2) == 8 );
+
+ function_ref<int(int)> r3(nontype<&callback_ref>, twice);
+ VERIFY( r3(3) == 6 );
+ function_ref<int(int)> r4(nontype<&callback_ref>, cube);
+ VERIFY( r4(3) == 27 );
+
+ // Checks if distinction between reference and pointer
+ // is preserved.
+ struct F
+ {
+ static
+ int operator()(ftype* f, int x)
+ { return f(x) + 1000; }
+
+ static
+ int operator()(ftype& f, int x)
+ { return f(x) + 2000; }
+ };
+ function_ref<int(int)> r5(nontype<F{}>, &twice);
+ VERIFY( r5(2) == 1004 );
+ function_ref<int(int)> r6(nontype<F{}>, twice);
+ VERIFY( r6(2) == 2008 );
+ function_ref<int(int)> r7(nontype<F{}>, &cube);
+ VERIFY( r7(3) == 1006 );
+ function_ref<int(int)> r8(nontype<F{}>, cube);
+ VERIFY( r8(3) == 2027 );
+}
+
+struct Incomplete;
+enum CompleteEnum : int;
+
+void
+test_params()
+{
+ auto f = [](auto&&) {};
+ std::function_ref<void(Incomplete&)> f1(f);
+ // See PR libstdc++/120259, this should be supported.
+ // std::function_ref<void(Incomplete&&)> f2(f);
+ std::function_ref<void(CompleteEnum)> f3(f);
+}
+
+int main()
+{
+ test01();
+ test02();
+ test03();
+ test04();
+ test_params();
+}
diff --git a/libstdc++-v3/testsuite/20_util/function_ref/cons.cc b/libstdc++-v3/testsuite/20_util/function_ref/cons.cc
new file mode 100644
index 0000000..a91f5ba
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/function_ref/cons.cc
@@ -0,0 +1,218 @@
+// { dg-do compile { target c++26 } }
+// { dg-add-options no_pch }
+
+#include <functional>
+
+#ifndef __cpp_lib_function_ref
+# error "Feature-test macro for function_ref missing in <functional>"
+#elif __cpp_lib_function_ref != 202306L
+# error "Feature-test macro for function_ref has wrong value in <functional>"
+#endif
+
+using std::nontype;
+using std::nontype_t;
+using std::function_ref;
+
+using std::is_default_constructible_v;
+using std::is_nothrow_copy_constructible_v;
+using std::is_nothrow_move_constructible_v;
+using std::is_nothrow_constructible_v;
+using std::is_constructible_v;
+using std::is_trivially_copyable_v;
+
+static_assert( ! is_default_constructible_v<function_ref<void()>> );
+static_assert( is_nothrow_move_constructible_v<function_ref<void()>> );
+static_assert( is_nothrow_copy_constructible_v<function_ref<void()>> );
+static_assert( is_trivially_copyable_v<function_ref<void()>> );
+
+static_assert( ! is_constructible_v<function_ref<void()>, std::nullptr_t> );
+
+static_assert( is_nothrow_constructible_v<function_ref<void()>, void()> );
+static_assert( is_nothrow_constructible_v<function_ref<void()>, void(&)()> );
+static_assert( is_nothrow_constructible_v<function_ref<void()>, void(*)()> );
+static_assert( is_nothrow_constructible_v<function_ref<void()>, int()> );
+static_assert( is_nothrow_constructible_v<function_ref<void()>, int(&)()> );
+static_assert( is_nothrow_constructible_v<function_ref<void()>, int(*)()> );
+static_assert( ! is_constructible_v<function_ref<void()>, void(int)> );
+static_assert( is_nothrow_constructible_v<function_ref<void(int)>, void(int)> );
+
+static_assert( is_nothrow_constructible_v<function_ref<void()>,
+ void() noexcept> );
+static_assert( is_nothrow_constructible_v<function_ref<void() noexcept>,
+ void() noexcept> );
+static_assert( ! is_constructible_v<function_ref<void() noexcept>,
+ void() > );
+
+struct S
+{
+ int x;
+ int f();
+};
+int funS(S);
+
+static_assert( is_nothrow_constructible_v<function_ref<int(S)>,
+ decltype(funS)> );
+static_assert( is_nothrow_constructible_v<function_ref<int(S)>,
+ decltype(&funS)> );
+static_assert( ! is_constructible_v<function_ref<int(S)>,
+ decltype(&S::x)> );
+static_assert( ! is_constructible_v<function_ref<int(S)>,
+ decltype(&S::f)> );
+
+static_assert( is_nothrow_constructible_v<function_ref<int(S)>,
+ nontype_t<funS>> );
+static_assert( is_nothrow_constructible_v<function_ref<int(S)>,
+ nontype_t<&funS>> );
+static_assert( is_nothrow_constructible_v<function_ref<int(S)>,
+ nontype_t<&S::x>> );
+static_assert( is_nothrow_constructible_v<function_ref<int(S)>,
+ nontype_t<&S::f>> );
+
+static_assert( is_nothrow_constructible_v<function_ref<int()>,
+ nontype_t<funS>, S&> );
+static_assert( is_nothrow_constructible_v<function_ref<int()>,
+ nontype_t<&funS>, S&> );
+static_assert( is_nothrow_constructible_v<function_ref<int()>,
+ nontype_t<&S::x>, S&> );
+static_assert( is_nothrow_constructible_v<function_ref<int()>,
+ nontype_t<&S::f>, S&> );
+
+static_assert( ! is_constructible_v<function_ref<int()>,
+ nontype_t<funS>, S*> );
+static_assert( ! is_constructible_v<function_ref<int()>,
+ nontype_t<&funS>, S*> );
+static_assert( is_nothrow_constructible_v<function_ref<int()>,
+ nontype_t<&S::x>, S*> );
+static_assert( is_nothrow_constructible_v<function_ref<int()>,
+ nontype_t<&S::f>, S*> );
+
+struct M
+{
+ void operator()();
+};
+
+
+static_assert( is_nothrow_constructible_v<function_ref<void()>, M> );
+static_assert( is_nothrow_constructible_v<function_ref<void()>, M&> );
+static_assert( ! is_constructible_v<function_ref<void()>, const M&> );
+static_assert( ! is_constructible_v<function_ref<void() const>, M> );
+static_assert( ! is_constructible_v<function_ref<void() const>, const M&> );
+static_assert( ! is_constructible_v<function_ref<void()>,
+ nontype_t<M{}>> );
+static_assert( ! is_constructible_v<function_ref<void() const>,
+ nontype_t<M{}>> );
+struct Q
+{
+ void operator()(int) const;
+ void operator()(int*) const;
+};
+
+static_assert( is_nothrow_constructible_v<function_ref<void(int)>, Q> );
+static_assert( is_nothrow_constructible_v<function_ref<void(int)>, Q&> );
+static_assert( is_nothrow_constructible_v<function_ref<void(int)>, const Q&> );
+static_assert( is_nothrow_constructible_v<function_ref<void(int) const>, Q> );
+static_assert( is_nothrow_constructible_v<function_ref<void(int) const>, Q&> );
+static_assert( is_nothrow_constructible_v<function_ref<void(int) const>, const Q&> );
+
+static_assert( is_nothrow_constructible_v<function_ref<void(int)>,
+ nontype_t<Q{}>> );
+static_assert( is_nothrow_constructible_v<function_ref<void(int) const>,
+ nontype_t<Q{}>> );
+static_assert( is_nothrow_constructible_v<function_ref<void()>,
+ nontype_t<Q{}>, int&> );
+static_assert( is_nothrow_constructible_v<function_ref<void() const>,
+ nontype_t<Q{}>, int&> );
+static_assert( ! is_constructible_v<function_ref<void()>,
+ nontype_t<Q{}>, int> );
+static_assert( ! is_constructible_v<function_ref<void() const>,
+ nontype_t<Q{}>, int> );
+
+static_assert( is_nothrow_constructible_v<function_ref<void()>,
+ nontype_t<Q{}>, int*> );
+static_assert( ! is_constructible_v<function_ref<void() const>,
+ nontype_t<Q{}>, int*> );
+
+struct L
+{
+ void operator()() &;
+};
+
+static_assert( is_nothrow_constructible_v<function_ref<void()>, L> );
+static_assert( is_nothrow_constructible_v<function_ref<void()>, L&> );
+static_assert( ! is_constructible_v<function_ref<void()>, const L&> );
+static_assert( ! is_constructible_v<function_ref<void() const>, L> );
+static_assert( ! is_constructible_v<function_ref<void() const>, const L&> );
+static_assert( ! is_constructible_v<function_ref<void()>,
+ nontype_t<L{}>> );
+static_assert( ! is_constructible_v<function_ref<void() const>,
+ nontype_t<L{}>> );
+
+struct R
+{
+ void operator()(float) const&&;
+};
+
+static_assert( ! is_constructible_v<function_ref<void(float)>, R> );
+static_assert( ! is_constructible_v<function_ref<void(float)>, R&> );
+static_assert( ! is_constructible_v<function_ref<void(float) const>, R> );
+static_assert( ! is_constructible_v<function_ref<void(float) const>, R&> );
+static_assert( ! is_constructible_v<function_ref<void(float) const>, const R&> );
+
+static_assert( ! is_constructible_v<function_ref<void(float)>,
+ nontype_t<R{}>> );
+static_assert( ! is_constructible_v<function_ref<void(float) const>,
+ nontype_t<R{}>> );
+
+constexpr bool
+test_constexpr()
+{
+ function_ref<void(S)> fp1(nontype<funS>);
+ function_ref<void(S)> fp3(nontype<&funS>);
+ function_ref<void(S)> fp4(nontype<&S::x>);
+ function_ref<void(S)> fp5(nontype<&S::f>);
+
+ S s;
+ function_ref<void()> fp6(nontype<&funS>, s);
+ function_ref<void()> fp7(nontype<&S::x>, s);
+ function_ref<void()> fp8(nontype<&S::x>, &s);
+ function_ref<void()> fp9(nontype<&S::f>, s);
+ function_ref<void()> fp10(nontype<&S::f>, &s);
+
+ M m;
+ function_ref<void()> fm1(m);
+ function_ref<void()> fm2(std::move(m));
+
+ Q q;
+ constexpr Q cq;
+ function_ref<void(int)> fq1(q);
+ function_ref<void(int) const> fq2(q);
+ function_ref<void(int) const> fq3(std::move(q));
+
+ function_ref<void(int)> fcq1(cq);
+ function_ref<void(int) const> f(cq);
+ function_ref<void(int)> fcq3(nontype<cq>);
+ function_ref<void(int) const> fcq4(nontype<cq>);
+
+ int i = 0;
+ function_ref<void()> fcq5(nontype<cq>, i);
+ function_ref<void() const> fcq6(nontype<cq>, i);
+ function_ref<void()> fcq7(nontype<cq>, &i);
+
+ L l;
+ function_ref<void()> fl1(l);
+ function_ref<void()> fl2(std::move(l));
+
+ return true;
+}
+static_assert( test_constexpr() );
+
+void func();
+
+void
+test_instantiation()
+{
+ function_ref<void(S)> fp1(funS);
+ function_ref<void(S)> fp2(&funS);
+
+ test_constexpr();
+}
diff --git a/libstdc++-v3/testsuite/20_util/function_ref/cons_neg.cc b/libstdc++-v3/testsuite/20_util/function_ref/cons_neg.cc
new file mode 100644
index 0000000..050090d
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/function_ref/cons_neg.cc
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++26 } }
+
+#include <functional>
+
+using std::nontype;
+using std::function_ref;
+
+struct S
+{
+ int x;
+ void foo();
+};
+S s;
+
+constexpr int(*fp)(S) = nullptr;
+constexpr int S::*mdp = nullptr;
+constexpr int (S::*mfp)() = nullptr;
+
+function_ref<int(S)> fd1(nontype<fp>); // { dg-error "from here" }
+function_ref<int(S)> fd2(nontype<mdp>); // { dg-error "from here" }
+function_ref<int(S)> fd3(nontype<mfp>); // { dg-error "from here" }
+
+function_ref<int()> br4(nontype<fp>, s); // { dg-error "from here" }
+function_ref<int()> br5(nontype<mdp>, s); // { dg-error "from here" }
+function_ref<int()> br6(nontype<mfp>, s); // { dg-error "from here" }
+
+function_ref<int()> bp7(nontype<mdp>, &s); // { dg-error "from here" }
+function_ref<int()> bp8(nontype<mfp>, &s); // { dg-error "from here" }
+
+// { dg-prune-output "static assertion failed" }
diff --git a/libstdc++-v3/testsuite/20_util/function_ref/conv.cc b/libstdc++-v3/testsuite/20_util/function_ref/conv.cc
new file mode 100644
index 0000000..7606d26
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/function_ref/conv.cc
@@ -0,0 +1,293 @@
+// { dg-do run { target c++26 } }
+// { dg-require-effective-target hosted }
+
+#include <functional>
+#include <string_view>
+#include <testsuite_hooks.h>
+
+using std::function_ref;
+
+static_assert( std::is_constructible_v<std::function_ref<void() const>,
+ std::function_ref<void()>> );
+
+// Non-trivial args, guarantess that type is not passed by copy
+struct CountedArg
+{
+ CountedArg() = default;
+ CountedArg(const CountedArg& f) noexcept : counter(f.counter) { ++counter; }
+ CountedArg& operator=(CountedArg&&) = delete;
+
+ int counter = 0;
+};
+CountedArg const c;
+
+using FuncType = int(int);
+
+// Top level const qualifiers are ignored in function types, and decay
+// is performed.
+static_assert( std::is_same_v<std::function_ref<void(int const)>,
+ std::function_ref<void(int)>> );
+static_assert( std::is_same_v<std::function_ref<void(int[2])>,
+ std::function_ref<void(int*)>>);
+static_assert( std::is_same_v<std::function_ref<void(int[])>,
+ std::function_ref<void(int*)>>);
+static_assert( std::is_same_v<std::function_ref<void(int const[5])>,
+ std::function_ref<void(int const*)>>);
+static_assert( std::is_same_v<std::function_ref<void(FuncType)>,
+ std::function_ref<void(FuncType*)>>);
+
+// The C++26 [func.wrap.general] p2 does not currently cover funciton_ref,
+// so we make extra copies of arguments.
+
+void
+test01()
+{
+ auto f = [](CountedArg const& arg) noexcept { return arg.counter; };
+ std::function_ref<int(CountedArg) const noexcept> r1(f);
+ std::move_only_function<int(CountedArg) const noexcept> m1(f);
+ std::copyable_function<int(CountedArg) const noexcept> c1(f);
+
+ // Complatible signatures
+ std::function_ref<int(CountedArg) const noexcept> r2m(m1);
+ VERIFY( r2m(c) == 2 );
+ std::function_ref<int(CountedArg) const noexcept> r2c(c1);
+ VERIFY( r2c(c) == 2 );
+
+ std::function_ref<int(CountedArg) const> r3r(r1);
+ VERIFY( r3r(c) == 2 );
+ std::function_ref<int(CountedArg) const> r3m(m1);
+ VERIFY( r3m(c) == 2 );
+ std::function_ref<int(CountedArg) const> r3c(c1);
+ VERIFY( r3c(c) == 2 );
+
+ std::function_ref<int(CountedArg)> r4r(r1);
+ VERIFY( r4r(c) == 2 );
+ std::function_ref<int(CountedArg)> r4m(m1);
+ VERIFY( r4m(c) == 2 );
+ std::function_ref<int(CountedArg)> r4c(c1);
+ VERIFY( r4c(c) == 2 );
+
+ // Incompatible signatures
+ std::function_ref<long(CountedArg) const noexcept> r5r(r1);
+ VERIFY( r5r(c) == 2 );
+ std::function_ref<long(CountedArg) const noexcept> r5m(m1);
+ VERIFY( r5r(c) == 2 );
+ std::function_ref<long(CountedArg) const noexcept> r5c(c1);
+ VERIFY( r5r(c) == 2 );
+}
+
+void
+test02()
+{
+ // Constructing move_only_function and copyable_function from function_ref,
+ // have not chance to restore manager, so we store function_ref inside.
+ auto f = [](CountedArg const& arg) noexcept { return arg.counter; };
+ std::function_ref<int(CountedArg) const noexcept> r1(f);
+
+ std::move_only_function<int(CountedArg) const noexcept> m1(r1);
+ VERIFY( m1(c) == 2 );
+
+ std::copyable_function<int(CountedArg) const noexcept> c1(r1);
+ VERIFY( c1(c) == 2 );
+}
+
+void
+test03()
+{
+ struct F
+ {
+ int operator()(CountedArg const& arg) noexcept
+ { return arg.counter; }
+
+ int operator()(CountedArg const& arg) const noexcept
+ { return arg.counter + 1000; }
+ };
+
+ F f;
+ std::function_ref<int(CountedArg) const> r1(f);
+ VERIFY( r1(c) == 1001 );
+
+ // Call const overload as std::function_ref<int(CountedArg) const>
+ // inside std::function_ref<int(CountedArg)> would do.
+ std::function_ref<int(CountedArg)> r2(r1);
+ VERIFY( r2(c) == 1002 );
+ std::move_only_function<int(CountedArg)> m2(r1);
+ VERIFY( m2(c) == 1002 );
+
+ // Call non-const overload as const-qualifed operator() for
+ // std::function_ref<int(CountedArg)> do.
+ std::function_ref<int(CountedArg)> r3(f);
+ VERIFY( r3(c) == 1 );
+ std::function_ref<int(CountedArg) const> r4(r3);
+ VERIFY( r4(c) == 2 );
+ std::move_only_function<int(CountedArg) const> m4(r3);
+ VERIFY( m4(c) == 2 );
+}
+
+void
+test04()
+{
+ auto f = [](CountedArg const& arg) noexcept { return arg.counter; };
+ std::function_ref<int(CountedArg)> w1(f);
+ // function_ref stores function_ref due incompatibile signatures
+ std::function_ref<int(CountedArg const&)> w2(std::move(w1));
+ // copy is made when passing to int(CountedArg)
+ VERIFY( w2(c) == 1 );
+ // wrapped 3 times
+ std::function_ref<int(CountedArg)> w3(w2);
+ VERIFY( w3(c) == 2 );
+ // wrapped 4 times
+ std::function_ref<int(CountedArg const&)> w4(w3);
+ VERIFY( w4(c) == 2 );
+ // wrapped 5 times
+ std::function_ref<int(CountedArg)> w5(w4);
+ VERIFY( w5(c) == 3 );
+}
+
+void
+test05()
+{
+ // No special interoperability with std::function
+ auto f = [](CountedArg const& arg) noexcept { return arg.counter; };
+ std::function<int(CountedArg)> f1(f);
+ std::function_ref<int(CountedArg) const> c1(std::move(f1));
+ VERIFY( c1(c) == 2 );
+
+ std::function_ref<int(CountedArg) const> c2(f);
+ std::function<int(CountedArg)> f2(c2);
+ VERIFY( f2(c) == 2 );
+}
+
+void
+test06()
+{
+ auto* func = +[]{ static int x; return &x; };
+ std::move_only_function<const void*() const> m1(func);
+ std::function_ref<const void*() const> rm1(m1);
+ VERIFY( m1() == rm1() );
+ std::copyable_function<const void*() const> c1(func);
+ std::function_ref<const void*() const> rc1(c1);
+ VERIFY( c1() == rc1() );
+
+ struct Trivial
+ {
+ void const* operator()() const
+ { return this; }
+ };
+ std::move_only_function<const void*() const> m2(Trivial{});
+ std::function_ref<const void*() const> rm2(m2);
+ VERIFY( m2() == rm2() );
+ std::copyable_function<const void*() const> c2(Trivial{});
+ std::function_ref<const void*() const> rc2(c2);
+ VERIFY( c2() == rc2() );
+
+ struct NonTrivial : Trivial
+ {
+ NonTrivial() {}
+ NonTrivial(NonTrivial&&) noexcept {}
+ NonTrivial(const NonTrivial&) {}
+ };
+ std::move_only_function<const void*() const> m3(NonTrivial{});
+ std::function_ref<const void*() const> rm3(m3);
+ VERIFY( m3() == rm3() );
+ std::copyable_function<const void*() const> c3(NonTrivial{});
+ std::function_ref<const void*() const> rc3(c3);
+ VERIFY( c3() == rc3() );
+
+ struct Large : Trivial
+ {
+ int tab[10];
+ };
+ std::move_only_function<const void*() const> m4(Large{});
+ std::function_ref<const void*() const> rm4(m4);
+ VERIFY( m4() == rm4() );
+ std::copyable_function<const void*() const> c4(Large{});
+ std::function_ref<const void*() const> rc4(c4);
+ VERIFY( c4() == rc4() );
+}
+
+void
+test07()
+{
+ int (*f1)() = [] { return 1; };
+ int (*f2)() = [] { return 2; };
+
+ std::function_ref<int() const> r1(f1);
+ std::move_only_function<int() const> m1(f1);
+ std::copyable_function<int() const> c1(f1);
+
+ std::function_ref<int() const> r2r(r1);
+ VERIFY( r2r() == 1 );
+ r1 = f2;
+ VERIFY( r2r() == 1 ); // same-siganture, copy constructor is used
+
+ std::function_ref<int() const> r2m(m1);
+ VERIFY( r2m() == 1 );
+ m1 = f2;
+ VERIFY( r2m() == 2 );
+
+ std::function_ref<int() const> r2c(c1);
+ VERIFY( r2c() == 1 );
+ c1 = f2;
+ VERIFY( r2c() == 2 );
+
+ std::function_ref<int()> r3r(r1);
+ VERIFY( r3r() == 2 );
+ r1 = f1;
+ VERIFY( r3r() == 1 ); // converting-constructor
+
+ std::function_ref<int()> r3m(m1);
+ VERIFY( r3m() == 2 );
+ m1 = f1;
+ VERIFY( r3m() == 1 );
+
+ std::function_ref<int()> r3c(c1);
+ VERIFY( r3c() == 2 );
+ c1 = f1;
+ VERIFY( r3c() == 1 );
+
+}
+
+constexpr bool
+test08()
+{
+ auto f = [](int x) noexcept { return x; };
+ std::function_ref<int(int) const noexcept> rf(f);
+
+ std::function_ref<int(int) const noexcept> rr1(rf);
+ std::function_ref<int(int)> rr2(rf);
+ std::function_ref<int(long)> rr3(rf);
+ return true;
+};
+
+void
+test09()
+{
+ // Scalar types and small trivially move constructible types are passed
+ // by value to invoker. So int&& signature is not compatible for such types.
+ auto fi = [](CountedArg const& arg, int) noexcept { return arg.counter; };
+ std::function_ref<int(CountedArg, int) const noexcept> ri1(fi);
+ VERIFY( ri1(c, 0) == 1 );
+ std::function_ref<int(CountedArg, int&&) const noexcept> ri2(ri1);
+ VERIFY( ri2(c, 0) == 2 );
+
+ auto fs = [](CountedArg const& arg, std::string_view) noexcept { return arg.counter; };
+ std::function_ref<int(CountedArg, std::string_view) const noexcept> rs1(fs);
+ VERIFY( rs1(c, "") == 1 );
+ std::function_ref<int(CountedArg, std::string_view&&) const noexcept> rs2(rs1);
+ VERIFY( rs2(c, "") == 2 );
+}
+
+int main()
+{
+ test01();
+ test02();
+ test03();
+ test04();
+ test05();
+ test06();
+ test07();
+ test09();
+
+ static_assert( test08() );
+}
diff --git a/libstdc++-v3/testsuite/20_util/function_ref/deduction.cc b/libstdc++-v3/testsuite/20_util/function_ref/deduction.cc
new file mode 100644
index 0000000..2940b87
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/function_ref/deduction.cc
@@ -0,0 +1,103 @@
+// { dg-do compile { target c++26 } }
+
+#include <functional>
+#include <type_traits>
+
+using std::is_same_v;
+using std::nontype;
+using std::nontype_t;
+using std::function_ref;
+
+int i = 0;
+
+void f0();
+void f0n() noexcept;
+
+static_assert( is_same_v<decltype(function_ref(f0)),
+ function_ref<void()>> );
+static_assert( is_same_v<decltype(function_ref(f0n)),
+ function_ref<void() noexcept>> );
+static_assert( is_same_v<decltype(function_ref(nontype<f0>)),
+ function_ref<void()>> );
+static_assert( is_same_v<decltype(function_ref(nontype<f0n>)),
+ function_ref<void() noexcept>> );
+
+void f1(int);
+void f1n(int) noexcept;
+
+static_assert( is_same_v<decltype(function_ref(f1)),
+ function_ref<void(int)>> );
+static_assert( is_same_v<decltype(function_ref(f1n)),
+ function_ref<void(int) noexcept>> );
+static_assert( is_same_v<decltype(function_ref(nontype<f1>)),
+ function_ref<void(int)>> );
+static_assert( is_same_v<decltype(function_ref(nontype<f1n>)),
+ function_ref<void(int) noexcept>> );
+static_assert( is_same_v<decltype(function_ref(nontype<f1>, i)),
+ function_ref<void()>> );
+static_assert( is_same_v<decltype(function_ref(nontype<f1n>, i)),
+ function_ref<void() noexcept>> );
+
+void f2(int*, int);
+void f2n(int*, int) noexcept;
+
+static_assert( is_same_v<decltype(function_ref(f2)),
+ function_ref<void(int*, int)>> );
+static_assert( is_same_v<decltype(function_ref(f2n)),
+ function_ref<void(int*, int) noexcept>> );
+static_assert( is_same_v<decltype(function_ref(nontype<f2>)),
+ function_ref<void(int*, int)>> );
+static_assert( is_same_v<decltype(function_ref(nontype<f2n>)),
+ function_ref<void(int*, int) noexcept>> );
+static_assert( is_same_v<decltype(function_ref(nontype<f2>, &i)),
+ function_ref<void(int)>> );
+static_assert( is_same_v<decltype(function_ref(nontype<f2n>, &i)),
+ function_ref<void(int) noexcept>> );
+
+struct S
+{
+ int mem;
+ int f();
+ int fn() noexcept;
+
+ int fc(int) const;
+ int fcn(int) const noexcept;
+
+ int fl(int) &;
+ int fln(int) & noexcept;
+
+ int fcl(float) const&;
+ int fcln(float) const& noexcept;
+};
+S s{};
+const S cs{};
+
+static_assert( is_same_v<decltype(function_ref(nontype<&S::mem>, s)),
+ function_ref<int&()>> );
+static_assert( is_same_v<decltype(function_ref(nontype<&S::mem>, cs)),
+ function_ref<const int&()>> );
+static_assert( is_same_v<decltype(function_ref(nontype<&S::mem>, &s)),
+ function_ref<int&()>> );
+static_assert( is_same_v<decltype(function_ref(nontype<&S::mem>, &cs)),
+ function_ref<const int&()>> );
+
+static_assert( is_same_v<decltype(function_ref(nontype<&S::f>, s)),
+ function_ref<int()>> );
+static_assert( is_same_v<decltype(function_ref(nontype<&S::fn>, &s)),
+ function_ref<int() noexcept>> );
+
+static_assert( is_same_v<decltype(function_ref(nontype<&S::fc>, &s)),
+ function_ref<int(int)>> );
+static_assert( is_same_v<decltype(function_ref(nontype<&S::fcn>, s)),
+ function_ref<int(int) noexcept>> );
+
+static_assert( is_same_v<decltype(function_ref(nontype<&S::fl>, &s)),
+ function_ref<int(int)>> );
+static_assert( is_same_v<decltype(function_ref(nontype<&S::fln>, s)),
+ function_ref<int(int) noexcept>> );
+
+static_assert( is_same_v<decltype(function_ref(nontype<&S::fcl>, s)),
+ function_ref<int(float)>> );
+static_assert( is_same_v<decltype(function_ref(nontype<&S::fcln>, &s)),
+ function_ref<int(float) noexcept>> );
+
diff --git a/libstdc++-v3/testsuite/20_util/function_ref/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/function_ref/incomplete_neg.cc
new file mode 100644
index 0000000..c8db1ee
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/function_ref/incomplete_neg.cc
@@ -0,0 +1,18 @@
+// { dg-do compile { target c++26 } }
+
+#include <functional>
+
+struct IncompleteClass;
+
+int a1 = alignof(std::function_ref<int(IncompleteClass)>); // { dg-error "here" }
+int a2 = alignof(std::function_ref<int(int, IncompleteClass)>); // { dg-error "here" }
+
+enum Enum {
+ x = [] {
+ // Enum enumeration is incomplete here
+ int a3 = alignof(std::function_ref<int(Enum)>); // { dg-error "here" }
+ return 1;
+ }()
+};
+
+// { dg-error "static assertion failed" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/20_util/function_ref/mutation.cc b/libstdc++-v3/testsuite/20_util/function_ref/mutation.cc
new file mode 100644
index 0000000..32c6931
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/function_ref/mutation.cc
@@ -0,0 +1,85 @@
+// { dg-do run { target c++26 } }
+
+#include <functional>
+#include <testsuite_hooks.h>
+
+using std::nontype;
+using std::function_ref;
+
+void
+test01()
+{
+ struct F {
+ int v;
+ int operator()() { return v; }
+ };
+ F f1{2}, f2{5};
+
+ function_ref<int()> r1(f1);
+ function_ref<long()> r2(f1);
+
+ VERIFY( r1() == 2 );
+ VERIFY( r2() == 2 );
+
+ f1.v = 10;
+
+ VERIFY( r1() == 10 );
+ VERIFY( r2() == 10 );
+
+ r1 = function_ref<int()>(f2);
+ r2 = function_ref<long()>(f2);
+
+ VERIFY( r1() == 5 );
+ VERIFY( r2() == 5 );
+
+ f2.v = 13;
+
+ VERIFY( r1() == 13 );
+ VERIFY( r2() == 13 );
+
+ r1 = function_ref<int()>(f1);
+ r2 = function_ref<long()>(f1);
+
+ f1.v = 20;
+ VERIFY( r1() == 20 );
+ VERIFY( r2() == 20 );
+}
+
+void
+test02()
+{
+ struct S
+ {
+ int x;
+ int f() { return x; };
+ };
+ S s{10};
+
+ function_ref<int()> r1(nontype<&S::x>, s);
+ function_ref<long()> r2(nontype<&S::x>, &s);
+
+ VERIFY( r1() == 10 );
+ VERIFY( r2() == 10 );
+
+ s.x = 20;
+
+ VERIFY( r1() == 20 );
+ VERIFY( r2() == 20 );
+
+ r1 = function_ref<int()>(nontype<&S::f>, &s);
+ r2 = function_ref<long()>(nontype<&S::f>, s);
+
+ VERIFY( r1() == 20 );
+ VERIFY( r2() == 20 );
+
+ s.x = 30;
+
+ VERIFY( r1() == 30 );
+ VERIFY( r2() == 30 );
+}
+
+int main()
+{
+ test01();
+ test02();
+}
diff --git a/libstdc++-v3/testsuite/20_util/headers/memory/version.cc b/libstdc++-v3/testsuite/20_util/headers/memory/version.cc
index c82c9a0..946955d 100644
--- a/libstdc++-v3/testsuite/20_util/headers/memory/version.cc
+++ b/libstdc++-v3/testsuite/20_util/headers/memory/version.cc
@@ -6,3 +6,7 @@
#if __cpp_lib_allocator_traits_is_always_equal != 201411L
# error "Feature-test macro __cpp_lib_allocator_traits_is_always_equal has wrong value in <version>"
#endif
+
+#if __cpp_lib_addressof_constexpr != 201603L
+# error "Feature-test macro __cpp_lib_addressof_constexpr has wrong value in <version>"
+#endif
diff --git a/libstdc++-v3/testsuite/20_util/is_complete_or_unbounded/120717.cc b/libstdc++-v3/testsuite/20_util/is_complete_or_unbounded/120717.cc
new file mode 100644
index 0000000..4c07683
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/is_complete_or_unbounded/120717.cc
@@ -0,0 +1,20 @@
+// PR libstdc++/120717
+// { dg-do compile { target c++11 } }
+// { dg-additional-options "-Wsfinae-incomplete" }
+
+#include <type_traits>
+
+// Verify __is_complete_or_unbounded doesn't try to instantiate the underlying
+// type of a reference or array of unknown bound.
+template<class T> struct A { static_assert(false, "do not instantiate"); };
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<A<int>&>{}), "");
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<A<int>&&>{}), "");
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<A<int>[]>{}), "");
+
+// Verify __is_complete_or_unbounded doesn't produce unexpected
+// -Wsfinae-incomplete warnings.
+struct B;
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<B&>{}), "");
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<B&&>{}), "");
+static_assert(std::__is_complete_or_unbounded(std::__type_identity<B[]>{}), "");
+struct B { }; // { dg-bogus "-Wsfinae-incomplete" }
diff --git a/libstdc++-v3/testsuite/20_util/is_complete_or_unbounded/memoization.cc b/libstdc++-v3/testsuite/20_util/is_complete_or_unbounded/memoization.cc
index 256b84d..59af024 100644
--- a/libstdc++-v3/testsuite/20_util/is_complete_or_unbounded/memoization.cc
+++ b/libstdc++-v3/testsuite/20_util/is_complete_or_unbounded/memoization.cc
@@ -23,7 +23,7 @@ struct X;
static_assert(
!std::__is_complete_or_unbounded(std::__type_identity<X>{}), "error");
-struct X{};
+struct X{}; // { dg-warning Wsfinae-incomplete }
static_assert(
std::__is_complete_or_unbounded(std::__type_identity<X>{}),
"Result memoized. This leads to worse diagnostics");
diff --git a/libstdc++-v3/testsuite/20_util/is_complete_or_unbounded/memoization_neg.cc b/libstdc++-v3/testsuite/20_util/is_complete_or_unbounded/memoization_neg.cc
index 8e207b5..264efa7 100644
--- a/libstdc++-v3/testsuite/20_util/is_complete_or_unbounded/memoization_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/is_complete_or_unbounded/memoization_neg.cc
@@ -25,5 +25,5 @@
struct X;
constexpr bool res_incomplete = std::is_move_constructible<X>::value; // { dg-error "required from here" }
-struct X{};
+struct X{}; // { dg-warning Wsfinae-incomplete }
constexpr bool res_complete = std::is_default_constructible<X>::value; // { dg-bogus "required from here" }
diff --git a/libstdc++-v3/testsuite/20_util/move_only_function/call.cc b/libstdc++-v3/testsuite/20_util/move_only_function/call.cc
index bfc609a..72c8118 100644
--- a/libstdc++-v3/testsuite/20_util/move_only_function/call.cc
+++ b/libstdc++-v3/testsuite/20_util/move_only_function/call.cc
@@ -190,14 +190,28 @@ test04()
VERIFY( std::move(std::as_const(f5))() == 3 );
}
+void
+test05()
+{
+ int (*fp)() = [] { return 0; };
+ move_only_function<int()> f0{fp};
+ VERIFY( f0() == 0 );
+ VERIFY( std::move(f0)() == 0 );
+
+ const move_only_function<int() const> f1{fp};
+ VERIFY( f1() == 0 );
+ VERIFY( std::move(f1)() == 0 );
+}
+
struct Incomplete;
+enum CompleteEnum : int;
void
test_params()
{
- std::move_only_function<void(Incomplete)> f1;
- std::move_only_function<void(Incomplete&)> f2;
- std::move_only_function<void(Incomplete&&)> f3;
+ std::move_only_function<void(Incomplete&)> f1;
+ std::move_only_function<void(Incomplete&&)> f2;
+ std::move_only_function<void(CompleteEnum)> f4;
}
int main()
@@ -206,5 +220,6 @@ int main()
test02();
test03();
test04();
+ test05();
test_params();
}
diff --git a/libstdc++-v3/testsuite/20_util/move_only_function/conv.cc b/libstdc++-v3/testsuite/20_util/move_only_function/conv.cc
new file mode 100644
index 0000000..ef8bb37b
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/move_only_function/conv.cc
@@ -0,0 +1,223 @@
+// { dg-do run { target c++23 } }
+// { dg-require-effective-target hosted }
+
+#include <functional>
+#include <string_view>
+#include <testsuite_hooks.h>
+
+using std::move_only_function;
+
+static_assert( !std::is_constructible_v<std::move_only_function<void()>,
+ std::move_only_function<void()&>> );
+static_assert( !std::is_constructible_v<std::move_only_function<void()>,
+ std::move_only_function<void()&&>> );
+static_assert( !std::is_constructible_v<std::move_only_function<void()&>,
+ std::move_only_function<void()&&>> );
+static_assert( !std::is_constructible_v<std::move_only_function<void() const>,
+ std::move_only_function<void()>> );
+
+using FuncType = int(int);
+
+// Top level const qualifiers are ignored in function types, and decay
+// is performed.
+static_assert( std::is_same_v<std::move_only_function<void(int const)>,
+ std::move_only_function<void(int)>> );
+static_assert( std::is_same_v<std::move_only_function<void(int[2])>,
+ std::move_only_function<void(int*)>>);
+static_assert( std::is_same_v<std::move_only_function<void(int[])>,
+ std::move_only_function<void(int*)>>);
+static_assert( std::is_same_v<std::move_only_function<void(int const[5])>,
+ std::move_only_function<void(int const*)>>);
+static_assert( std::is_same_v<std::move_only_function<void(FuncType)>,
+ std::move_only_function<void(FuncType*)>>);
+
+// Non-trivial args, guarantess that type is not passed by copy
+struct CountedArg
+{
+ CountedArg() = default;
+ CountedArg(const CountedArg& f) noexcept : counter(f.counter) { ++counter; }
+ CountedArg& operator=(CountedArg&&) = delete;
+
+ int counter = 0;
+};
+CountedArg const c;
+
+// When move_only_functions is constructed from other move_only_function,
+// the compiler can avoid double indirection per C++26 [func.wrap.general] p2.
+
+void
+test01()
+{
+ auto f = [](CountedArg const& arg) noexcept { return arg.counter; };
+ std::move_only_function<int(CountedArg) const noexcept> m1(f);
+ VERIFY( m1(c) == 1 );
+
+ std::move_only_function<int(CountedArg) const> m2(std::move(m1));
+ VERIFY( m2(c) == 1 );
+
+ std::move_only_function<int(CountedArg)> m3(std::move(m2));
+ VERIFY( m3(c) == 1 );
+
+ // Invokers internally uses Counted&& for non-trivial types,
+ // sinature remain compatible.
+ std::move_only_function<int(CountedArg&&)> m4(std::move(m3));
+ VERIFY( m4({}) == 0 );
+
+ std::move_only_function<int(CountedArg&&)&&> m5(std::move(m4));
+ VERIFY( std::move(m5)({}) == 0 );
+
+ m4 = f;
+ std::move_only_function<int(CountedArg&&)&> m7(std::move(m4));
+ VERIFY( m7({}) == 0 );
+
+ m4 = f;
+ std::move_only_function<int(CountedArg&&)&> m8(std::move(m4));
+ VERIFY( m8({}) == 0 );
+
+ // Incompatible signatures
+ m1 = f;
+ std::move_only_function<long(CountedArg) const noexcept> m9(std::move(m1));
+ VERIFY( m9(c) == 2 );
+}
+
+void
+test02()
+{
+ auto f = [](CountedArg const& arg) noexcept { return arg.counter; };
+ std::move_only_function<int(CountedArg) const noexcept> m1(f);
+ VERIFY( m1(c) == 1 );
+
+ std::move_only_function<int(CountedArg) const> m2;
+ m2 = std::move(m1);
+ VERIFY( m2(c) == 1 );
+
+ std::move_only_function<int(CountedArg)> m3;
+ m3 = std::move(m2);
+ VERIFY( m3(c) == 1 );
+
+ // Invokers internally uses Counted&& for non-trivial types,
+ // sinature remain compatible.
+ std::move_only_function<int(CountedArg&&)> m4;
+ m4 = std::move(m3);
+ VERIFY( m4({}) == 0 );
+
+ std::move_only_function<int(CountedArg&&)&&> m5;
+ m5 = std::move(m4);
+ VERIFY( std::move(m5)({}) == 0 );
+
+ m4 = f;
+ std::move_only_function<int(CountedArg&&)&> m7;
+ m7 = std::move(m4);
+ VERIFY( m7({}) == 0 );
+
+ m4 = f;
+ std::move_only_function<int(CountedArg&&)&> m8;
+ m8 = std::move(m4);
+ VERIFY( m8({}) == 0 );
+
+ m1 = f;
+ std::move_only_function<long(CountedArg) const noexcept> m9;
+ m9 = std::move(m1);
+ VERIFY( m9(c) == 2 );
+}
+
+void
+test03()
+{
+ std::move_only_function<int(long) const noexcept> e;
+ VERIFY( e == nullptr );
+
+ std::move_only_function<int(long) const> e2(std::move(e));
+ VERIFY( e2 == nullptr );
+ e2 = std::move(e);
+ VERIFY( e2 == nullptr );
+
+ std::move_only_function<bool(int) const> e3(std::move(e));
+ VERIFY( e3 == nullptr );
+ e3 = std::move(e);
+ VERIFY( e3 == nullptr );
+}
+
+void
+test04()
+{
+ struct F
+ {
+ int operator()(CountedArg const& arg) noexcept
+ { return arg.counter; }
+
+ int operator()(CountedArg const& arg) const noexcept
+ { return arg.counter + 1000; }
+ };
+
+ F f;
+ std::move_only_function<int(CountedArg) const> m1(f);
+ VERIFY( m1(c) == 1001 );
+
+ // Call const overload as std::move_only_function<int(CountedArg) const>
+ // inside std::move_only_function<int(CountedArg)> would do.
+ std::move_only_function<int(CountedArg)> m2(std::move(m1));
+ VERIFY( m2(c) == 1001 );
+
+ std::move_only_function<int(CountedArg)> m3(f);
+ VERIFY( m3(c) == 1 );
+}
+
+void
+test05()
+{
+ auto f = [](CountedArg const& arg) noexcept { return arg.counter; };
+ std::move_only_function<int(CountedArg)> w1(f);
+ // move_only_function stores move_only_function due incompatibile signatures
+ std::move_only_function<int(CountedArg const&)> w2(std::move(w1));
+ // copy is made when passing to int(CountedArg)
+ VERIFY( w2(c) == 1 );
+ // wrapped 3 times
+ w1 = std::move(w2);
+ VERIFY( w1(c) == 2 );
+ // wrapped 4 times
+ w2 = std::move(w1);
+ VERIFY( w2(c) == 2 );
+ // wrapped 5 times
+ w1 = std::move(w2);
+ VERIFY( w1(c) == 3 );
+}
+
+void
+test06()
+{
+ // No special interoperability with std::function
+ auto f = [](CountedArg const& arg) noexcept { return arg.counter; };
+ std::function<int(CountedArg)> f1(f);
+ std::move_only_function<int(CountedArg) const> m1(std::move(f1));
+ VERIFY( m1(c) == 2 );
+}
+
+void
+test07()
+{
+ // Scalar types and small trivially move constructible types are passed
+ // by value to invoker. So int&& signature is not compatible for such types.
+ auto fi = [](CountedArg const& arg, int) noexcept { return arg.counter; };
+ std::move_only_function<int(CountedArg, int) const noexcept> mi1(fi);
+ VERIFY( mi1(c, 0) == 1 );
+ std::move_only_function<int(CountedArg, int&&) const noexcept> mi2(std::move(mi1));
+ VERIFY( mi2(c, 0) == 2 );
+
+ auto fs = [](CountedArg const& arg, std::string_view) noexcept { return arg.counter; };
+ std::move_only_function<int(CountedArg, std::string_view) const noexcept> ms1(fs);
+ VERIFY( ms1(c, "") == 1 );
+ std::move_only_function<int(CountedArg, std::string_view&&) const noexcept> ms2(std::move(ms1));
+ VERIFY( ms2(c, "") == 2 );
+}
+
+int main()
+{
+ test01();
+ test02();
+ test03();
+ test04();
+ test05();
+ test06();
+ test07();
+}
diff --git a/libstdc++-v3/testsuite/20_util/move_only_function/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/move_only_function/incomplete_neg.cc
new file mode 100644
index 0000000..d025c47
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/move_only_function/incomplete_neg.cc
@@ -0,0 +1,18 @@
+// { dg-do compile { target c++23 } }
+
+#include <functional>
+
+struct IncompleteClass;
+
+using T1 = std::move_only_function<int(IncompleteClass)>::result_type; // { dg-error "here" }
+using T2 = std::move_only_function<int(int, IncompleteClass)>::result_type; // { dg-error "here" }
+
+enum Enum {
+ x = [] {
+ // Enum enumeration is incomplete here
+ using T3 = std::move_only_function<int(Enum)>::result_type; // { dg-error "here" }
+ return T3(1);
+ }()
+};
+
+// { dg-error "static assertion failed" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/20_util/move_only_function/move.cc b/libstdc++-v3/testsuite/20_util/move_only_function/move.cc
index 51e31a6..6da02c9 100644
--- a/libstdc++-v3/testsuite/20_util/move_only_function/move.cc
+++ b/libstdc++-v3/testsuite/20_util/move_only_function/move.cc
@@ -32,6 +32,12 @@ test01()
VERIFY( m1().copy == 1 );
VERIFY( m1().move == 0 );
+ // Standard specifies move assigment as copy and swap
+ m1 = std::move(m1);
+ VERIFY( m1 != nullptr );
+ VERIFY( m1().copy == 1 );
+ VERIFY( m1().move == 0 );
+
// This will move construct a new target object and destroy the old one:
auto m2 = std::move(m1);
VERIFY( m1 == nullptr && m2 != nullptr );
@@ -80,6 +86,11 @@ test02()
VERIFY( m1().copy == 1 );
VERIFY( m1().move == 0 );
+ m1 = std::move(m1);
+ VERIFY( m1 != nullptr );
+ VERIFY( m1().copy == 1 );
+ VERIFY( m1().move == 0 );
+
// The target object is on the heap so this just moves a pointer:
auto m2 = std::move(m1);
VERIFY( m1 == nullptr && m2 != nullptr );
diff --git a/libstdc++-v3/testsuite/20_util/optional/range.cc b/libstdc++-v3/testsuite/20_util/optional/range.cc
new file mode 100644
index 0000000..e77dc21
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/optional/range.cc
@@ -0,0 +1,163 @@
+// { dg-do compile { target c++26 } }
+
+#include <concepts>
+#include <format>
+#include <iterator>
+#include <optional>
+#include <ranges>
+#include <string_view>
+#include <vector>
+
+#include <testsuite_hooks.h>
+
+template<typename O>
+constexpr
+void
+test_range_concepts()
+{
+ static_assert(std::ranges::contiguous_range<O>);
+ static_assert(std::ranges::sized_range<O>);
+ static_assert(std::ranges::common_range<O>);
+ static_assert(!std::ranges::borrowed_range<O>);
+
+ // an optional<const T> is not assignable, and therefore does not satisfy ranges::view
+ using T = typename O::value_type;
+ constexpr bool is_const_opt = std::is_const_v<T>;
+ static_assert(std::ranges::view<O> == !is_const_opt);
+ static_assert(std::ranges::viewable_range<O> == !is_const_opt);
+}
+
+template<typename O>
+constexpr
+void
+test_iterator_concepts()
+{
+ using T = typename O::value_type;
+ using iterator = typename O::iterator;
+ static_assert(std::contiguous_iterator<iterator>);
+ static_assert(std::is_same_v<typename std::iterator_traits<iterator>::value_type, std::remove_cv_t<T>>);
+ static_assert(std::is_same_v<std::iter_value_t<iterator>, std::remove_cv_t<T>>);
+ static_assert(std::is_same_v<typename std::iterator_traits<iterator>::reference, T&>);
+ static_assert(std::is_same_v<std::iter_reference_t<iterator>, T&>);
+
+ using const_iterator = typename O::const_iterator;
+ static_assert(std::contiguous_iterator<const_iterator>);
+ static_assert(std::is_same_v<typename std::iterator_traits<const_iterator>::value_type, std::remove_cv_t<T>>);
+ static_assert(std::is_same_v<std::iter_value_t<const_iterator>, std::remove_cv_t<T>>);
+ static_assert(std::is_same_v<typename std::iterator_traits<const_iterator>::reference, const T&>);
+ static_assert(std::is_same_v<std::iter_reference_t<const_iterator>, const T&>);
+}
+
+template<typename O>
+constexpr
+void
+test_empty()
+{
+ O empty;
+ VERIFY(!empty);
+ VERIFY(empty.begin() == empty.end());
+ VERIFY(std::as_const(empty).begin() == std::as_const(empty).end());
+ VERIFY(std::ranges::empty(empty));
+ VERIFY(std::ranges::empty(std::as_const(empty)));
+ VERIFY(std::ranges::empty(empty | std::views::as_const));
+ VERIFY(std::ranges::size(empty) == 0);
+ VERIFY(std::ranges::size(std::as_const(empty)) == 0);
+
+ size_t count = 0;
+ for (const auto& x : empty)
+ ++count;
+ VERIFY(count == 0);
+}
+
+template<typename O, typename T>
+constexpr
+void
+test_non_empty(const T& value)
+{
+ O non_empty = std::make_optional(value);
+ VERIFY(non_empty);
+ VERIFY(*non_empty == value);
+ VERIFY(non_empty.begin() != non_empty.end());
+ VERIFY(non_empty.begin() < non_empty.end());
+ VERIFY(std::as_const(non_empty).begin() != std::as_const(non_empty).end());
+ VERIFY(std::as_const(non_empty).begin() < std::as_const(non_empty).end());
+ VERIFY(!std::ranges::empty(non_empty));
+ VERIFY(!std::ranges::empty(std::as_const(non_empty)));
+ VERIFY(!std::ranges::empty(non_empty | std::views::as_const));
+ VERIFY(std::ranges::size(non_empty) == 1);
+ VERIFY(std::ranges::size(std::as_const(non_empty)) == 1);
+
+ size_t count = 0;
+ for (const auto& x : non_empty)
+ ++count;
+ VERIFY(count == 1);
+
+ if constexpr (!std::is_const_v<typename O::value_type>) {
+ for (auto& x : non_empty)
+ x = T{};
+ VERIFY(non_empty);
+ VERIFY(*non_empty == T{});
+ }
+}
+
+template<typename T>
+constexpr
+void
+test(const T& value)
+{
+ using O = std::optional<T>;
+ test_range_concepts<O>();
+ test_iterator_concepts<O>();
+ test_empty<O>();
+ test_non_empty<O>(value);
+ static_assert(!std::formattable<O, char>);
+ static_assert(!std::formattable<O, wchar_t>);
+ static_assert(std::format_kind<O> == std::range_format::disabled);
+}
+
+constexpr
+void
+range_chain_example() // from P3168
+{
+ std::vector<int> v{2, 3, 4, 5, 6, 7, 8, 9, 1};
+ auto test = [](int i) -> std::optional<int> {
+ switch(i) {
+ case 1:
+ case 3:
+ case 7:
+ case 9:
+ return i * 2;
+ default:
+ return {};
+ }
+ };
+
+ auto result = v
+ | std::views::transform(test)
+ | std::views::filter([](auto x) { return bool(x); })
+ | std::views::transform([](auto x){ return *x; })
+ | std::ranges::to<std::vector>();
+
+ bool ok = result == std::vector<int>{6, 14, 18, 2};
+ VERIFY(ok);
+}
+
+constexpr
+bool
+all_tests()
+{
+ test(42);
+ int i = 42;
+ test(&i);
+ test(std::string_view("test"));
+ test(std::vector<int>{1, 2, 3, 4});
+ test(std::optional<int>(42));
+ test<const int>(42);
+
+ range_chain_example();
+
+ return true;
+}
+
+static_assert(all_tests());
+
diff --git a/libstdc++-v3/testsuite/20_util/optional/version.cc b/libstdc++-v3/testsuite/20_util/optional/version.cc
index 657a399..ba44aa5 100644
--- a/libstdc++-v3/testsuite/20_util/optional/version.cc
+++ b/libstdc++-v3/testsuite/20_util/optional/version.cc
@@ -21,8 +21,17 @@
#endif
#endif
+#if __cplusplus > 202302L
+# ifndef __cpp_lib_optional_range_support
+# error "Feature test macro for optional range support is missing in <version>"
+# elif __cpp_lib_optional_range_support != 202406L
+# error "Feature test macro for optional range support has wrong value for C++26 in <version>"
+# endif
+#endif
+
#undef __cpp_lib_optional
#undef __cpp_lib_freestanding_optional
+#undef __cpp_lib_optional_range_support
#include <optional>
#if __cplusplus >= 202302L
@@ -32,3 +41,12 @@
# error "Feature test macro for freestanding std::optional has wrong value in <optional>"
#endif
#endif
+
+#if __cplusplus > 202302L
+# ifndef __cpp_lib_optional_range_support
+# error "Feature test macro for optional range support is missing in <optional>"
+# endif
+# if __cpp_lib_optional_range_support != 202406L
+# error "Feature test macro for optional range support has wrong value for C++26 in <optional>"
+# endif
+#endif
diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/requirements/1.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/requirements/1.cc
index 8ddb5d2..19090d1 100644
--- a/libstdc++-v3/testsuite/20_util/shared_ptr/requirements/1.cc
+++ b/libstdc++-v3/testsuite/20_util/shared_ptr/requirements/1.cc
@@ -3,31 +3,122 @@
#include <memory>
#include <testsuite_tr1.h>
+#include <type_traits>
using namespace __gnu_test;
+template<template<class> class SmartPtr>
void
test01()
{
- std::shared_ptr<ClassType> ptr;
- std::shared_ptr<const ClassType> ptr2 = ptr;
+ SmartPtr<ClassType> ptr;
+ SmartPtr<const ClassType> ptr2 = ptr;
#if __cpp_lib_shared_ptr_arrays >= 201611L
- std::shared_ptr<ClassType[10]> ptr_array;
- std::shared_ptr<ClassType[]> ptr_array2 = ptr_array;
- std::shared_ptr<ClassType const []> ptr_array3 = ptr_array;
+ SmartPtr<ClassType[10]> ptr_array;
+ SmartPtr<ClassType[]> ptr_array2 = ptr_array;
+ SmartPtr<ClassType const []> ptr_array3 = ptr_array;
#endif
}
+template<template<class> class SmartPtr>
void
test02()
{
- std::shared_ptr<IncompleteClass> ptr;
- std::shared_ptr<const IncompleteClass> ptr2 = ptr;
+ SmartPtr<IncompleteClass> ptr;
+ SmartPtr<const IncompleteClass> ptr2 = ptr;
#if __cpp_lib_shared_ptr_arrays >= 201611L
- std::shared_ptr<IncompleteClass[10]> ptr_array;
- std::shared_ptr<IncompleteClass[]> ptr_array2 = ptr_array;
- std::shared_ptr<IncompleteClass const []> ptr_array3 = ptr_array;
+ SmartPtr<IncompleteClass[10]> ptr_array;
+ SmartPtr<IncompleteClass[]> ptr_array2 = ptr_array;
+ SmartPtr<IncompleteClass const []> ptr_array3 = ptr_array;
#endif
}
+
+template<template<class> class SmartPtr>
+void
+test03()
+{
+ static_assert( std::is_convertible<SmartPtr<int>, SmartPtr<const int>>::value);
+ static_assert(!std::is_convertible<SmartPtr<const int>, SmartPtr<int>>::value);
+ static_assert( std::is_convertible<SmartPtr<ClassType>, SmartPtr<const ClassType>>::value);
+ static_assert(!std::is_convertible<SmartPtr<const ClassType>, SmartPtr<ClassType>>::value);
+ static_assert( std::is_convertible<SmartPtr<IncompleteClass>, SmartPtr<const IncompleteClass>>::value);
+ static_assert(!std::is_convertible<SmartPtr<const IncompleteClass>, SmartPtr<IncompleteClass>>::value);
+ static_assert( std::is_convertible<SmartPtr<void>, SmartPtr<const void>>::value);
+ static_assert(!std::is_convertible<SmartPtr<const void>, SmartPtr<void>>::value);
+
+ static_assert( std::is_convertible<SmartPtr<int>, SmartPtr<void>>::value);
+ static_assert(!std::is_convertible<SmartPtr<void>, SmartPtr<int>>::value);
+ static_assert( std::is_convertible<SmartPtr<int>, SmartPtr<const void>>::value);
+ static_assert( std::is_convertible<SmartPtr<const int>, SmartPtr<const void>>::value);
+ static_assert(!std::is_convertible<SmartPtr<const int>, SmartPtr<void>>::value);
+ static_assert(!std::is_convertible<SmartPtr<const void>, SmartPtr<const int>>::value);
+ static_assert( std::is_convertible<SmartPtr<ClassType>, SmartPtr<void>>::value);
+ static_assert( std::is_convertible<SmartPtr<ClassType>, SmartPtr<const void>>::value);
+
+ static_assert(!std::is_convertible<SmartPtr<int*>, SmartPtr<const int*>>::value);
+ static_assert( std::is_convertible<SmartPtr<int*>, SmartPtr<const int* const>>::value);
+ static_assert(!std::is_convertible<SmartPtr<const int*>, SmartPtr<int*>>::value);
+ static_assert(!std::is_convertible<SmartPtr<const int* const>, SmartPtr<int*>>::value);
+
+ static_assert(!std::is_convertible<SmartPtr<ClassType*>, SmartPtr<const ClassType*>>::value);
+ static_assert( std::is_convertible<SmartPtr<ClassType*>, SmartPtr<const ClassType* const>>::value);
+ static_assert(!std::is_convertible<SmartPtr<const ClassType*>, SmartPtr<ClassType*>>::value);
+ static_assert(!std::is_convertible<SmartPtr<const ClassType* const>, SmartPtr<ClassType*>>::value);
+
+ static_assert(!std::is_convertible<SmartPtr<void*>, SmartPtr<const void*>>::value);
+ static_assert( std::is_convertible<SmartPtr<void*>, SmartPtr<const void* const>>::value);
+ static_assert(!std::is_convertible<SmartPtr<const void*>, SmartPtr<void*>>::value);
+ static_assert(!std::is_convertible<SmartPtr<const void* const>, SmartPtr<void*>>::value);
+
+#if __cpp_lib_shared_ptr_arrays >= 201611L
+ static_assert( std::is_convertible<SmartPtr<int[10]>, SmartPtr<int[]>>::value);
+ static_assert(!std::is_convertible<SmartPtr<int[]>, SmartPtr<int[10]>>::value);
+ static_assert( std::is_convertible<SmartPtr<int[10]>, SmartPtr<int const[]>>::value);
+ static_assert( std::is_convertible<SmartPtr<int[10]>, SmartPtr<int const[10]>>::value);
+ static_assert( std::is_convertible<SmartPtr<int[]>, SmartPtr<int const[]>>::value);
+ static_assert(!std::is_convertible<SmartPtr<int const[]>, SmartPtr<int[]>>::value);
+ static_assert( std::is_convertible<SmartPtr<int const[10]>, SmartPtr<int const[]>>::value);
+ static_assert(!std::is_convertible<SmartPtr<int const[]>, SmartPtr<int const[10]>>::value);
+
+ static_assert( std::is_convertible<SmartPtr<ClassType[10]>, SmartPtr<ClassType[]>>::value);
+ static_assert(!std::is_convertible<SmartPtr<ClassType[]>, SmartPtr<ClassType[10]>>::value);
+ static_assert( std::is_convertible<SmartPtr<ClassType[10]>, SmartPtr<ClassType const[]>>::value);
+ static_assert( std::is_convertible<SmartPtr<ClassType[10]>, SmartPtr<ClassType const[10]>>::value);
+ static_assert( std::is_convertible<SmartPtr<ClassType[]>, SmartPtr<ClassType const[]>>::value);
+ static_assert(!std::is_convertible<SmartPtr<ClassType const[]>, SmartPtr<ClassType[]>>::value);
+ static_assert( std::is_convertible<SmartPtr<ClassType const[10]>, SmartPtr<ClassType const[]>>::value);
+ static_assert(!std::is_convertible<SmartPtr<ClassType const[]>, SmartPtr<ClassType const[10]>>::value);
+
+ static_assert( std::is_convertible<SmartPtr<IncompleteClass[10]>, SmartPtr<IncompleteClass[]>>::value);
+ static_assert(!std::is_convertible<SmartPtr<IncompleteClass[]>, SmartPtr<IncompleteClass[10]>>::value);
+ static_assert( std::is_convertible<SmartPtr<IncompleteClass[10]>, SmartPtr<IncompleteClass const[]>>::value);
+ static_assert( std::is_convertible<SmartPtr<IncompleteClass[10]>, SmartPtr<IncompleteClass const[10]>>::value);
+ static_assert( std::is_convertible<SmartPtr<IncompleteClass[]>, SmartPtr<IncompleteClass const[]>>::value);
+ static_assert(!std::is_convertible<SmartPtr<IncompleteClass const[]>, SmartPtr<IncompleteClass[]>>::value);
+ static_assert( std::is_convertible<SmartPtr<IncompleteClass const[10]>, SmartPtr<IncompleteClass const[]>>::value);
+ static_assert(!std::is_convertible<SmartPtr<IncompleteClass const[]>, SmartPtr<IncompleteClass const[10]>>::value);
+
+ static_assert( std::is_convertible<SmartPtr<int*[10]>, SmartPtr<int*[]>>::value);
+ static_assert(!std::is_convertible<SmartPtr<int*[]>, SmartPtr<int*[10]>>::value);
+ static_assert( std::is_convertible<SmartPtr<int*[10]>, SmartPtr<int* const[10]>>::value);
+ static_assert( std::is_convertible<SmartPtr<int*[10]>, SmartPtr<int* const[]>>::value);
+
+ static_assert(!std::is_convertible<SmartPtr<int*[]>, SmartPtr<void*[]>>::value);
+ static_assert(!std::is_convertible<SmartPtr<int*[]>, SmartPtr<void const *[]>>::value);
+#endif
+}
+
+int
+main()
+{
+ test01<std::shared_ptr>();
+ test01<std::weak_ptr>();
+
+ test02<std::shared_ptr>();
+ test02<std::weak_ptr>();
+
+ test03<std::shared_ptr>();
+ test03<std::weak_ptr>();
+}
diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/memory_management_tools/destroy_n_neg.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/memory_management_tools/destroy_n_neg.cc
new file mode 100644
index 0000000..12c0dc5
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/memory_management_tools/destroy_n_neg.cc
@@ -0,0 +1,59 @@
+// Copyright (C) 2017-2025 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do compile { target c++17 } }
+
+#include <memory>
+
+// This has a trivial destructor, but should not be destructible!
+struct DeletedDtor {
+ ~DeletedDtor() = delete;
+};
+
+void
+test01()
+{
+ alignas(DeletedDtor) unsigned char buf[sizeof(DeletedDtor)];
+ auto p = ::new (buf) DeletedDtor();
+ std::destroy_n(p, 1);
+}
+
+class PrivateDtor {
+ ~PrivateDtor() { }
+};
+
+void
+test02()
+{
+ alignas(PrivateDtor) unsigned char buf[sizeof(PrivateDtor)];
+ auto p = ::new (buf) PrivateDtor();
+ std::destroy_n(p, 1);
+}
+
+#if __cpp_constexpr_dynamic_alloc // >= C++20
+consteval bool
+test03()
+{
+ DeletedDtor* p = nullptr;
+ std::destroy_n(p, 0);
+ return true;
+}
+static_assert(test03());
+#endif
+
+// { dg-error "deleted function .*DeletedDtor" "" { target *-*-* } 0 }
+// { dg-error "PrivateDtor.* is private" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/memory_management_tools/destroy_neg.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/memory_management_tools/destroy_neg.cc
index 5946a82..096f218 100644
--- a/libstdc++-v3/testsuite/20_util/specialized_algorithms/memory_management_tools/destroy_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/memory_management_tools/destroy_neg.cc
@@ -29,8 +29,7 @@ test01()
{
alignas(DeletedDtor) unsigned char buf[sizeof(DeletedDtor)];
auto p = ::new (buf) DeletedDtor();
- std::destroy(p, p + 1); // { dg-error "here" }
- std::destroy_n(p, 1); // { dg-error "here" }
+ std::destroy(p, p + 1);
}
class PrivateDtor {
@@ -42,8 +41,19 @@ test02()
{
alignas(PrivateDtor) unsigned char buf[sizeof(PrivateDtor)];
auto p = ::new (buf) PrivateDtor();
- std::destroy(p, p + 1); // { dg-error "here" }
- std::destroy_n(p, 1); // { dg-error "here" }
+ std::destroy(p, p + 1);
}
-// { dg-error "value type is destructible" "" { target *-*-* } 0 }
+#if __cpp_constexpr_dynamic_alloc // >= C++20
+consteval bool
+test03()
+{
+ DeletedDtor* p = nullptr;
+ std::destroy(p, p);
+ return true;
+}
+static_assert(test03());
+#endif
+
+// { dg-error "deleted function .*DeletedDtor" "" { target *-*-* } 0 }
+// { dg-error "PrivateDtor.* is private" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/constrained.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/constrained.cc
index af3b733..5dff0da 100644
--- a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/constrained.cc
+++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/constrained.cc
@@ -178,12 +178,40 @@ test03()
void
test_pr101587()
{
- short in[1];
+ short in[1]{};
__gnu_test::test_contiguous_range r(in); // difference_type is integer-like
long out[1];
std::span<long> o(out); // difference_type is ptrdiff_t
ranges::uninitialized_copy(r, o);
ranges::uninitialized_copy_n(ranges::begin(r), 0, o.begin(), o.end());
+
+ // iterator that has an integer-like class type for difference_type
+ struct Iter
+ {
+ using value_type = long;
+ using difference_type = std::ranges::__detail::__max_diff_type;
+
+ long& operator*() const { return *p; }
+
+ Iter& operator++() { ++p; return *this; }
+ Iter operator++(int) { return Iter{p++}; }
+
+ difference_type operator-(Iter i) const { return p - i.p; }
+ bool operator==(const Iter&) const = default;
+
+ long* p = nullptr;
+ };
+ static_assert(std::sized_sentinel_for<Iter, Iter>);
+
+ std::ranges::subrange<Iter> rmax(Iter{out+0}, Iter{out+1});
+ // Check with integer-like class type for output range:
+ std::ranges::uninitialized_copy(in, rmax);
+ std::ranges::uninitialized_copy_n(in+0, 1, rmax.begin(), rmax.end());
+
+ int to[1];
+ // And for input range:
+ std::ranges::uninitialized_copy(rmax, to);
+ std::ranges::uninitialized_copy_n(rmax.begin(), 1, to+0, to+1);
}
int
diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_default_construct/120397.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_default_construct/120397.cc
new file mode 100644
index 0000000..7aa05d7
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_default_construct/120397.cc
@@ -0,0 +1,19 @@
+// { dg-do compile { target c++17 } }
+
+#include <memory>
+
+// PR libstdc++/120397
+// std::uninitialized_value_construct cannot create arrays of non-trivially
+// destructible types
+
+struct X { X() { } ~X() { } };
+
+void def(X (*x)[1])
+{
+ std::uninitialized_default_construct(x, x+1);
+}
+
+void def_n(X (*x)[1])
+{
+ std::uninitialized_default_construct_n(x, 1);
+}
diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill/120931.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill/120931.cc
new file mode 100644
index 0000000..766fac0
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill/120931.cc
@@ -0,0 +1,16 @@
+// { dg-options "-std=gnu++98" }
+// { dg-do compile { target c++98_only } }
+// std::deque<character types>::resize() method fails with -std=c++98
+
+#include <memory>
+#include <testsuite_iterators.h>
+
+void
+test_pr120931()
+{
+ using __gnu_test::test_container;
+ using __gnu_test::forward_iterator_wrapper;
+ unsigned char c[1];
+ test_container<unsigned char, forward_iterator_wrapper> f(c);
+ std::uninitialized_fill(f.begin(), f.end(), 0);
+}
diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_move/constrained.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_move/constrained.cc
index fe82d1f1..3e81244 100644
--- a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_move/constrained.cc
+++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_move/constrained.cc
@@ -188,12 +188,39 @@ test03()
void
test_pr101587()
{
- short in[1];
+ short in[1]{};
__gnu_test::test_contiguous_range r(in); // difference_type is integer-like
long out[1];
std::span<long> o(out); // difference_type is ptrdiff_t
ranges::uninitialized_move(r, o);
ranges::uninitialized_move_n(ranges::begin(r), 0, o.begin(), o.end());
+
+ struct Iter
+ {
+ using value_type = long;
+ using difference_type = std::ranges::__detail::__max_diff_type;
+
+ long& operator*() const { return *p; }
+
+ Iter& operator++() { ++p; return *this; }
+ Iter operator++(int) { return Iter{p++}; }
+
+ difference_type operator-(Iter i) const { return p - i.p; }
+ bool operator==(const Iter&) const = default;
+
+ long* p = nullptr;
+ };
+ static_assert(std::sized_sentinel_for<Iter, Iter>);
+
+ std::ranges::subrange<Iter> rmax(Iter{out+0}, Iter{out+1});
+ // Check with integer-like class type for output range:
+ std::ranges::uninitialized_move(in, rmax);
+ std::ranges::uninitialized_move_n(in+0, 1, rmax.begin(), rmax.end());
+
+ int to[1];
+ // And for input range:
+ std::ranges::uninitialized_copy(rmax, to);
+ std::ranges::uninitialized_copy_n(rmax.begin(), 1, to+0, to+1);
}
int
diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_value_construct/120397.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_value_construct/120397.cc
new file mode 100644
index 0000000..f4d9fce
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_value_construct/120397.cc
@@ -0,0 +1,19 @@
+// { dg-do compile { target c++17 } }
+
+#include <memory>
+
+// PR libstdc++/120397
+// std::uninitialized_value_construct cannot create arrays of non-trivially
+// destructible types
+
+struct X { X() { } ~X() { } };
+
+void val(X (*x)[1])
+{
+ std::uninitialized_value_construct(x, x+1);
+}
+
+void val_n(X (*x)[1])
+{
+ std::uninitialized_value_construct_n(x, 1);
+}
diff --git a/libstdc++-v3/testsuite/20_util/system_clock/99832.cc b/libstdc++-v3/testsuite/20_util/system_clock/99832.cc
new file mode 100644
index 0000000..693d4d6
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/system_clock/99832.cc
@@ -0,0 +1,14 @@
+// { dg-options "-O0 -g0" }
+// { dg-do compile { target c++20 } }
+// { dg-final { scan-assembler-not "system_clock9to_time_t" } }
+
+// Bug libstdc++/99832
+// std::chrono::system_clock::to_time_t needs ABI tag for 32-bit time_t
+
+#include <chrono>
+
+std::time_t
+test_pr99832(std::chrono::system_clock::time_point t)
+{
+ return std::chrono::system_clock::to_time_t(t);
+}
diff --git a/libstdc++-v3/testsuite/20_util/tuple/dr3528.cc b/libstdc++-v3/testsuite/20_util/tuple/dr3528.cc
new file mode 100644
index 0000000..c20ff95
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/tuple/dr3528.cc
@@ -0,0 +1,46 @@
+// { dg-do compile { target c++17 } }
+
+// LWG 3528. make_from_tuple can perform (the equivalent of) a C-style cast
+
+#include <tuple>
+#include <array>
+#include <utility>
+
+template<typename T, typename Tuple>
+using make_t = decltype(std::make_from_tuple<T>(std::declval<Tuple>()));
+
+template<typename T, typename Tuple, typename = void>
+constexpr bool can_make = false;
+template<typename T, typename Tuple>
+constexpr bool can_make<T, Tuple, std::void_t<make_t<T, Tuple>>> = true;
+
+static_assert( can_make<int, std::tuple<int>> );
+static_assert( can_make<int, std::tuple<int>&> );
+static_assert( can_make<int, const std::tuple<int>&> );
+static_assert( can_make<int, std::array<short, 1>> );
+static_assert( can_make<int, const std::array<short, 1>&&> );
+static_assert( can_make<std::tuple<int, int>, std::pair<unsigned, long>> );
+static_assert( can_make<std::pair<int, int>, std::array<int, 2>> );
+static_assert( can_make<const int*, std::tuple<int*>> );
+static_assert( can_make<void*, std::tuple<int*>> );
+static_assert( can_make<int, std::tuple<>> );
+static_assert( ! can_make<int, std::tuple<int, int>> );
+static_assert( ! can_make<int, std::pair<short, char>> );
+static_assert( ! can_make<int, std::pair<short, char>&> );
+static_assert( ! can_make<int, std::tuple<const char*>> );
+static_assert( ! can_make<int*, std::tuple<const int*>> );
+static_assert( ! can_make<int*, std::tuple<void*>> );
+static_assert( ! can_make<int, std::array<int, 2>> );
+static_assert( ! can_make<void, std::tuple<>> );
+static_assert( ! can_make<void, std::array<int, 1>> );
+
+struct Two
+{
+ Two(const char*, int);
+};
+
+static_assert( can_make<Two, std::tuple<char*, unsigned>> );
+static_assert( ! can_make<Two, std::tuple<const char*, int, int>> );
+static_assert( can_make<Two, std::pair<const char*, long>> );
+static_assert( ! can_make<Two, std::pair<int*, long>> );
+static_assert( ! can_make<std::pair<int, int>, std::array<int, 3>> );
diff --git a/libstdc++-v3/testsuite/20_util/tuple/element_access/get_neg.cc b/libstdc++-v3/testsuite/20_util/tuple/element_access/get_neg.cc
index 48628a9..18d47d2 100644
--- a/libstdc++-v3/testsuite/20_util/tuple/element_access/get_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/tuple/element_access/get_neg.cc
@@ -61,4 +61,4 @@ test03()
// { dg-error "tuple index must be in range" "" { target *-*-* } 0 }
// { dg-prune-output "no type named 'type' in .*_Nth_type" }
-// { dg-prune-output "pack index is out of range" }
+// { dg-prune-output "pack index '.' is out of range" }
diff --git a/libstdc++-v3/testsuite/20_util/weak_ptr/requirements/1.cc b/libstdc++-v3/testsuite/20_util/weak_ptr/requirements/1.cc
deleted file mode 100644
index 04ea837..0000000
--- a/libstdc++-v3/testsuite/20_util/weak_ptr/requirements/1.cc
+++ /dev/null
@@ -1,33 +0,0 @@
-// { dg-do compile { target c++11 } }
-// { dg-require-effective-target hosted }
-
-#include <memory>
-#include <testsuite_tr1.h>
-
-using namespace __gnu_test;
-
-void
-test01()
-{
- std::weak_ptr<ClassType> ptr;
- std::weak_ptr<const ClassType> ptr2 = ptr;
-
-#if __cpp_lib_shared_ptr_arrays >= 201611L
- std::weak_ptr<ClassType[10]> ptr_array;
- std::weak_ptr<ClassType[]> ptr_array2 = ptr_array;
- std::weak_ptr<ClassType const []> ptr_array3 = ptr_array;
-#endif
-}
-
-void
-test02()
-{
- std::weak_ptr<IncompleteClass> ptr;
- std::weak_ptr<const IncompleteClass> ptr2 = ptr;
-
-#if __cpp_lib_shared_ptr_arrays >= 201611L
- std::weak_ptr<IncompleteClass[10]> ptr_array;
- std::weak_ptr<IncompleteClass[]> ptr_array2 = ptr_array;
- std::weak_ptr<IncompleteClass const []> ptr_array3 = ptr_array;
-#endif
-}
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/allocator/char/operator_plus.cc b/libstdc++-v3/testsuite/21_strings/basic_string/allocator/char/operator_plus.cc
index 571f853..92e0569 100644
--- a/libstdc++-v3/testsuite/21_strings/basic_string/allocator/char/operator_plus.cc
+++ b/libstdc++-v3/testsuite/21_strings/basic_string/allocator/char/operator_plus.cc
@@ -17,8 +17,6 @@
// <http://www.gnu.org/licenses/>.
// { dg-do run { target c++11 } }
-// COW strings don't support C++11 allocator propagation:
-// { dg-require-effective-target cxx11_abi }
#include <string>
#include <testsuite_hooks.h>
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/allocator/wchar_t/operator_plus.cc b/libstdc++-v3/testsuite/21_strings/basic_string/allocator/wchar_t/operator_plus.cc
index 0da6843..b75b26a 100644
--- a/libstdc++-v3/testsuite/21_strings/basic_string/allocator/wchar_t/operator_plus.cc
+++ b/libstdc++-v3/testsuite/21_strings/basic_string/allocator/wchar_t/operator_plus.cc
@@ -17,8 +17,6 @@
// <http://www.gnu.org/licenses/>.
// { dg-do run { target c++11 } }
-// COW strings don't support C++11 allocator propagation:
-// { dg-require-effective-target cxx11_abi }
#include <string>
#include <testsuite_hooks.h>
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/cons/char/119748.cc b/libstdc++-v3/testsuite/21_strings/basic_string/cons/char/119748.cc
new file mode 100644
index 0000000..301ca5d
--- /dev/null
+++ b/libstdc++-v3/testsuite/21_strings/basic_string/cons/char/119748.cc
@@ -0,0 +1,35 @@
+// { dg-do compile }
+
+// Bug 119748
+// string(InputIterator, InputIterator) rejects volatile charT* as iterator
+
+#ifndef TEST_CHAR_TYPE
+#define TEST_CHAR_TYPE char
+#endif
+
+#include <string>
+#include <testsuite_iterators.h>
+
+typedef TEST_CHAR_TYPE C;
+
+volatile C vs[42] = {};
+std::basic_string<C> s(vs+0, vs+42);
+#ifdef __cpp_lib_containers_ranges
+std::basic_string<C> s2(std::from_range, vs);
+#endif
+
+using namespace __gnu_test;
+
+test_container<volatile C, input_iterator_wrapper> input_cont(vs);
+std::basic_string<C> s3(input_cont.begin(), input_cont.end());
+
+test_container<volatile C, forward_iterator_wrapper> fwd_cont(vs);
+std::basic_string<C> s4(fwd_cont.begin(), fwd_cont.end());
+
+#ifdef __cpp_lib_containers_ranges
+test_input_range<volatile C> input_range(vs);
+std::basic_string<C> s5(std::from_range, input_range);
+
+test_forward_range<volatile C> fwd_range(vs);
+std::basic_string<C> s6(std::from_range, fwd_range);
+#endif
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/cons/from_range.cc b/libstdc++-v3/testsuite/21_strings/basic_string/cons/from_range.cc
new file mode 100644
index 0000000..6331050
--- /dev/null
+++ b/libstdc++-v3/testsuite/21_strings/basic_string/cons/from_range.cc
@@ -0,0 +1,129 @@
+// { dg-do run { target c++23 } }
+
+#include <string>
+
+#if __cpp_lib_containers_ranges != 202202L
+# error "Feature-test macro __cpp_lib_containers_ranges has wrong value in <string>"
+#endif
+
+#include <span>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+#include <testsuite_allocator.h>
+
+void
+test_deduction_guide(char* p)
+{
+ __gnu_test::test_input_range<char> r(nullptr, nullptr);
+ std::basic_string v(std::from_range, r);
+ static_assert(std::is_same_v<decltype(v), std::string>);
+
+ using Alloc = __gnu_test::SimpleAllocator<char>;
+ Alloc alloc;
+ std::basic_string v2(std::from_range, r, alloc);
+ static_assert(std::is_same_v<decltype(v2), std::basic_string<char, std::char_traits<char>, Alloc>>);
+
+ __gnu_test::test_input_range<wchar_t> wr(nullptr, nullptr);
+ std::basic_string w(std::from_range, wr);
+ static_assert(std::is_same_v<decltype(w), std::wstring>);
+
+ using WAlloc = __gnu_test::SimpleAllocator<wchar_t>;
+ WAlloc walloc;
+ std::basic_string w2(std::from_range, wr, walloc);
+ static_assert(std::is_same_v<decltype(w2), std::basic_string<wchar_t, std::char_traits<wchar_t>, WAlloc>>);
+}
+
+template<typename Range, typename Alloc>
+constexpr void
+do_test(Alloc alloc)
+{
+ // The basic_string's value_type.
+ using V = typename std::allocator_traits<Alloc>::value_type;
+ using CT = std::char_traits<V>;
+
+ // The range's value_type.
+ using T = std::ranges::range_value_t<Range>;
+ T a[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'};
+
+ auto eq = [](const std::basic_string<V, CT, Alloc>& l, std::span<T> r) {
+ if (l.size() != r.size())
+ return false;
+ for (auto i = 0u; i < l.size(); ++i)
+ if (l[i] != r[i])
+ return false;
+ return true;
+ };
+
+ std::basic_string<V, CT, Alloc> v0(std::from_range, Range(a, a+0));
+ VERIFY( v0.empty() );
+ VERIFY( v0.get_allocator() == Alloc() );
+
+ std::basic_string<V, CT, Alloc> v4(std::from_range, Range(a, a+4));
+ VERIFY( eq(v4, {a, 4}) );
+ VERIFY( v4.get_allocator() == Alloc() );
+
+ std::basic_string<V, CT, Alloc> v9(std::from_range, Range(a, a+9), alloc);
+ VERIFY( eq(v9, {a, 9}) );
+ VERIFY( v9.get_allocator() == alloc );
+
+ std::basic_string<V, CT, Alloc> v20(std::from_range, Range(a, a+20), alloc);
+ VERIFY( eq(v20, {a, 20}) );
+ VERIFY( v20.get_allocator() == alloc );
+}
+
+template<typename Range>
+void
+do_test_a()
+{
+ do_test<Range>(std::allocator<char>());
+ do_test<Range>(__gnu_test::uneq_allocator<char>(42));
+ do_test<Range>(std::allocator<wchar_t>());
+ do_test<Range>(__gnu_test::uneq_allocator<wchar_t>(42));
+}
+
+bool
+test_ranges()
+{
+ using namespace __gnu_test;
+
+ do_test_a<test_forward_range<char>>();
+ do_test_a<test_forward_sized_range<char>>();
+ do_test_a<test_sized_range_sized_sent<char, forward_iterator_wrapper>>();
+
+ do_test_a<test_input_range<char>>();
+ do_test_a<test_input_sized_range<char>>();
+ do_test_a<test_sized_range_sized_sent<char, input_iterator_wrapper>>();
+
+ do_test_a<test_range<char, input_iterator_wrapper_nocopy>>();
+ do_test_a<test_sized_range<char, input_iterator_wrapper_nocopy>>();
+ do_test_a<test_sized_range_sized_sent<char, input_iterator_wrapper_nocopy>>();
+
+ // Not lvalue-convertible to char
+ struct C {
+ C(char v) : val(v) { }
+ operator char() && { return val; }
+ bool operator==(char b) const { return b == val; }
+ char val;
+ };
+ using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>;
+ do_test<rvalue_input_range>(std::allocator<char>());
+
+ return true;
+}
+
+constexpr bool
+test_constexpr()
+{
+#if _GLIBCXX_USE_CXX11_ABI
+ // XXX: this doesn't test the non-forward_range code paths are constexpr.
+ do_test<std::string_view>(std::allocator<char>());
+#endif // _GLIBCXX_USE_CXX11_ABI
+ return true;
+}
+
+int main()
+{
+ test_ranges();
+ static_assert( test_constexpr() );
+}
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/cons/wchar_t/119748.cc b/libstdc++-v3/testsuite/21_strings/basic_string/cons/wchar_t/119748.cc
new file mode 100644
index 0000000..7d3ba10
--- /dev/null
+++ b/libstdc++-v3/testsuite/21_strings/basic_string/cons/wchar_t/119748.cc
@@ -0,0 +1,7 @@
+// { dg-do compile }
+
+// Bug 119748
+// string(InputIterator, InputIterator) rejects volatile charT* as iterator
+
+#define TEST_CHAR_TYPE wchar_t
+#include "../char/119748.cc"
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/append/append_range.cc b/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/append/append_range.cc
new file mode 100644
index 0000000..6c0bc0c
--- /dev/null
+++ b/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/append/append_range.cc
@@ -0,0 +1,125 @@
+// { dg-do run { target c++23 } }
+
+#include <span>
+#include <string>
+#include <testsuite_allocator.h>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+template<typename Range, typename Alloc>
+constexpr void
+do_test()
+{
+ // The vector's value_type.
+ using V = typename std::allocator_traits<Alloc>::value_type;
+ using CT = std::char_traits<V>;
+
+ // The range's value_type.
+ using T = std::ranges::range_value_t<Range>;
+ T a[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'};
+
+ auto eq = [](const std::basic_string<V, CT, Alloc>& l, std::span<T> r) {
+ if (l.size() != r.size())
+ return false;
+ for (auto i = 0u; i < l.size(); ++i)
+ if (l[i] != r[i])
+ return false;
+ return true;
+ };
+
+ Range r4(a, a+4);
+ Range r5(a+4, a+9);
+ Range r11(a+9, a+20);
+
+ std::basic_string<V, CT, Alloc> v;
+ v.append_range(r4);
+ VERIFY( eq(v, {a, 4}) );
+ v.append_range(r5);
+ VERIFY( eq(v, {a, 9}) );
+
+ std::basic_string<V, CT, Alloc> const s = v;
+ v.append_range(r11);
+ VERIFY( eq(v, a) );
+ v.append_range(Range(a, a));
+ VERIFY( eq(v, a) );
+ v.clear();
+ v.append_range(Range(a, a));
+ VERIFY( v.empty() );
+}
+
+template<typename Range>
+void
+do_test_a()
+{
+ do_test<Range, std::allocator<char>>();
+ do_test<Range, __gnu_test::SimpleAllocator<char>>();
+ do_test<Range, std::allocator<wchar_t>>();
+ do_test<Range, __gnu_test::SimpleAllocator<wchar_t>>();
+}
+
+bool
+test_ranges()
+{
+ using namespace __gnu_test;
+
+ do_test_a<test_forward_range<char>>();
+ do_test_a<test_forward_sized_range<char>>();
+ do_test_a<test_sized_range_sized_sent<char, forward_iterator_wrapper>>();
+
+ do_test_a<test_input_range<char>>();
+ do_test_a<test_input_sized_range<char>>();
+ do_test_a<test_sized_range_sized_sent<char, input_iterator_wrapper>>();
+
+ do_test_a<test_range<char, input_iterator_wrapper_nocopy>>();
+ do_test_a<test_sized_range<char, input_iterator_wrapper_nocopy>>();
+ do_test_a<test_sized_range_sized_sent<char, input_iterator_wrapper_nocopy>>();
+
+ // Not lvalue-convertible to char
+ struct C {
+ C(char v) : val(v) { }
+ operator char() && { return val; }
+ bool operator==(char b) const { return b == val; }
+ char val;
+ };
+ using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>;
+ do_test<rvalue_input_range, std::allocator<char>>();
+
+ return true;
+}
+
+void
+test_overlapping()
+{
+ std::string const s = "1234abcd";
+
+ std::string c = s;
+ c.append_range(std::string_view(c));
+ VERIFY( c == "1234abcd1234abcd" );
+
+ c = s;
+ c.append_range(std::string_view(c).substr(4, 4));
+ VERIFY( c == "1234abcdabcd" );
+
+ c = s;
+ c.reserve(12);
+ c.append_range(std::string_view(c).substr(0, 4));
+ VERIFY( c == "1234abcd1234" );
+}
+
+constexpr bool
+test_constexpr()
+{
+#if _GLIBCXX_USE_CXX11_ABI
+ // XXX: this doesn't test the non-forward_range code paths are constexpr.
+ do_test<std::string_view, std::allocator<char>>();
+#endif // _GLIBCXX_USE_CXX11_ABI
+ return true;
+}
+
+int main()
+{
+ test_ranges();
+ test_overlapping();
+ static_assert( test_constexpr() );
+}
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/assign/assign_range.cc b/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/assign/assign_range.cc
new file mode 100644
index 0000000..310c8bc
--- /dev/null
+++ b/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/assign/assign_range.cc
@@ -0,0 +1,116 @@
+// { dg-do run { target c++23 } }
+
+#include <vector>
+#include <span>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+#include <testsuite_allocator.h>
+
+template<typename Range, typename Alloc>
+constexpr void
+do_test()
+{
+ // The vector's value_type.
+ using V = typename std::allocator_traits<Alloc>::value_type;
+ using CT = std::char_traits<V>;
+
+ // The range's value_type.
+ using T = std::ranges::range_value_t<Range>;
+ T a[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'};
+
+ auto eq = [](const std::basic_string<V, CT, Alloc>& l, std::span<T> r) {
+ if (l.size() != r.size())
+ return false;
+ for (auto i = 0u; i < l.size(); ++i)
+ if (l[i] != r[i])
+ return false;
+ return true;
+ };
+
+ std::basic_string<V, CT, Alloc> v;
+ v.assign_range(Range(a, a));
+ VERIFY( v.empty() );
+ v.assign_range(Range(a, a+4));
+ VERIFY( eq(v, {a, 4}) );
+ v.assign_range(Range(a, a+9));
+ VERIFY( eq(v, {a, 9}) );
+ std::basic_string<V, CT, Alloc> const s = v;
+ v.assign_range(Range(a, a+20));
+ VERIFY( eq(v, {a, 20}) );
+}
+
+template<typename Range>
+void
+do_test_a()
+{
+ do_test<Range, std::allocator<char>>();
+ do_test<Range, __gnu_test::SimpleAllocator<char>>();
+ do_test<Range, std::allocator<wchar_t>>();
+ do_test<Range, __gnu_test::SimpleAllocator<wchar_t>>();
+}
+
+bool
+test_ranges()
+{
+ using namespace __gnu_test;
+
+ do_test_a<test_forward_range<char>>();
+ do_test_a<test_forward_sized_range<char>>();
+ do_test_a<test_sized_range_sized_sent<char, forward_iterator_wrapper>>();
+
+ do_test_a<test_input_range<char>>();
+ do_test_a<test_input_sized_range<char>>();
+ do_test_a<test_sized_range_sized_sent<char, input_iterator_wrapper>>();
+
+ do_test_a<test_range<char, input_iterator_wrapper_nocopy>>();
+ do_test_a<test_sized_range<char, input_iterator_wrapper_nocopy>>();
+ do_test_a<test_sized_range_sized_sent<char, input_iterator_wrapper_nocopy>>();
+
+ // Not lvalue-convertible to char
+ struct C {
+ C(char v) : val(v) { }
+ operator char() && { return val; }
+ bool operator==(char b) const { return b == val; }
+ char val;
+ };
+ using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>;
+ do_test<rvalue_input_range, std::allocator<char>>();
+
+ return true;
+}
+
+void
+test_overlapping()
+{
+ std::string const s = "1234abcd";
+
+ std::string c = s;
+ c.assign_range(std::string_view(c));
+ VERIFY( c == "1234abcd" );
+
+ c = s;
+ c.assign_range(std::string_view(c).substr(4, 4));
+ VERIFY( c == "abcd" );
+
+ c = s;
+ c.assign_range(std::string_view(c).substr(0, 4));
+ VERIFY( c == "1234" );
+}
+
+constexpr bool
+test_constexpr()
+{
+#if _GLIBCXX_USE_CXX11_ABI
+ // XXX: this doesn't test the non-forward_range code paths are constexpr.
+ do_test<std::string_view, std::allocator<char>>();
+#endif // _GLIBCXX_USE_CXX11_ABI
+ return true;
+}
+
+int main()
+{
+ test_ranges();
+ test_overlapping();
+ static_assert( test_constexpr() );
+}
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/insert/insert_range.cc b/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/insert/insert_range.cc
new file mode 100644
index 0000000..4fead32
--- /dev/null
+++ b/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/insert/insert_range.cc
@@ -0,0 +1,130 @@
+// { dg-do run { target c++23 } }
+
+#include <span>
+#include <string>
+#include <testsuite_allocator.h>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+template<typename Range, typename Alloc>
+constexpr void
+do_test()
+{
+ // The vector's value_type.
+ using V = typename std::allocator_traits<Alloc>::value_type;
+ using CT = std::char_traits<V>;
+
+ // The range's value_type.
+ using T = std::ranges::range_value_t<Range>;
+ T a[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'};
+
+ auto eq = [](const std::basic_string<V, CT, Alloc>& l, std::span<T> r) {
+ if (l.size() != r.size())
+ return false;
+ for (auto i = 0u; i < l.size(); ++i)
+ if (l[i] != r[i])
+ return false;
+ return true;
+ };
+
+ std::basic_string<V, CT, Alloc> v;
+ auto it = v.insert_range(v.end(), Range(a, a));
+ VERIFY( v.empty() );
+ VERIFY( it == v.begin() );
+ it = v.insert_range(v.end(), Range(a, a+4));
+ VERIFY( eq(v, {a, 4}) );
+ VERIFY( it == v.begin() );
+ it = v.insert_range(v.end(), Range(a+4, a+9));
+ VERIFY( eq(v, {a, 9}) );
+ VERIFY( it == v.begin()+4 );
+
+ std::basic_string<V, CT, Alloc> s = v;
+ it = v.insert_range(v.end(), Range(a+9, a+20));
+ VERIFY( eq(v, {a, 20}) );
+ VERIFY( it == v.begin()+9 );
+
+ v = std::basic_string<V, CT, Alloc>();
+ it = v.insert_range(v.begin(), Range(a, a+5));
+ VERIFY( it == v.begin() );
+ s = v;
+ it = v.insert_range(v.begin() + 5, Range(a+5, a+20));
+ VERIFY( eq(v, {a, 20}) );
+ VERIFY( it == v.begin()+5 );
+}
+
+template<typename Range>
+void
+do_test_a()
+{
+ do_test<Range, std::allocator<char>>();
+ do_test<Range, __gnu_test::SimpleAllocator<char>>();
+ do_test<Range, std::allocator<wchar_t>>();
+ do_test<Range, __gnu_test::SimpleAllocator<wchar_t>>();
+}
+
+bool
+test_ranges()
+{
+ using namespace __gnu_test;
+
+ do_test_a<test_forward_range<char>>();
+ do_test_a<test_forward_sized_range<char>>();
+ do_test_a<test_sized_range_sized_sent<char, forward_iterator_wrapper>>();
+
+ do_test_a<test_input_range<char>>();
+ do_test_a<test_input_sized_range<char>>();
+ do_test_a<test_sized_range_sized_sent<char, input_iterator_wrapper>>();
+
+ do_test_a<test_range<char, input_iterator_wrapper_nocopy>>();
+ do_test_a<test_sized_range<char, input_iterator_wrapper_nocopy>>();
+ do_test_a<test_sized_range_sized_sent<char, input_iterator_wrapper_nocopy>>();
+
+ // Not lvalue-convertible to char
+ struct C {
+ C(char v) : val(v) { }
+ operator char() && { return val; }
+ bool operator==(char b) const { return b == val; }
+ char val;
+ };
+ using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>;
+ do_test<rvalue_input_range, std::allocator<char>>();
+
+ return true;
+}
+
+void
+test_overlapping()
+{
+ std::string const s = "1234abcd";
+
+ std::string c = s;
+ c.insert_range(c.end(), std::string_view(c));
+ VERIFY( c == "1234abcd1234abcd" );
+
+ c = s;
+ c.insert_range(c.begin()+4, std::string_view(c).substr(4, 4));
+ VERIFY( c == "1234abcdabcd" );
+
+ c = s;
+ c.reserve(12);
+ c.insert_range(c.begin()+2, std::string_view(c).substr(0, 4));
+ VERIFY( c == "12123434abcd" );
+}
+
+constexpr bool
+test_constexpr()
+{
+#if _GLIBCXX_USE_CXX11_ABI
+ // XXX: this doesn't test the non-forward_range code paths are constexpr.
+ do_test<std::string_view, std::allocator<char>>();
+#endif // _GLIBCXX_USE_CXX11_ABI
+ return true;
+}
+
+int main()
+{
+ test_ranges();
+ test_overlapping();
+ static_assert( test_constexpr() );
+}
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/replace/replace_with_range.cc b/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/replace/replace_with_range.cc
new file mode 100644
index 0000000..9acf11a
--- /dev/null
+++ b/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/replace/replace_with_range.cc
@@ -0,0 +1,133 @@
+// { dg-do run { target c++23 } }
+
+#include <span>
+#include <string>
+#include <testsuite_allocator.h>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+template<typename Range, typename Alloc>
+constexpr void
+do_test()
+{
+ // The vector's value_type.
+ using V = typename std::allocator_traits<Alloc>::value_type;
+ using CT = std::char_traits<V>;
+
+ // The range's value_type.
+ using T = std::ranges::range_value_t<Range>;
+ T a[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'};
+
+ auto eq = [](const std::basic_string<V, CT, Alloc>& l, std::span<T> r) {
+ if (l.size() != r.size())
+ return false;
+ for (auto i = 0u; i < l.size(); ++i)
+ if (l[i] != r[i])
+ return false;
+ return true;
+ };
+
+ std::basic_string<V, CT, Alloc> v;
+ v.replace_with_range(v.end(), v.end(), Range(a, a));
+ VERIFY( v.empty() );
+ v.replace_with_range(v.end(), v.end(), Range(a, a+4));
+ VERIFY( eq(v, {a, 4}) );
+ v.replace_with_range(v.end(), v.end(), Range(a+4, a+9));
+ VERIFY( eq(v, {a, 9}) );
+ std::basic_string<V, CT, Alloc> s = v;
+ v.replace_with_range(v.end(), v.end(), Range(a+9, a+20));
+ VERIFY( eq(v, {a, 20}) );
+
+ v.replace_with_range(v.begin()+10, v.begin()+20, Range(a+5, a+10));
+ VERIFY( v.size() == 15 );
+ v.replace_with_range(v.begin(), v.begin()+10, Range(a, a+5));
+ VERIFY( eq(v, {a, 10}) );
+
+ s = v;
+ v.replace_with_range(v.begin(), v.begin()+4, Range(a, a+8));
+ VERIFY( v.size() == 14 );
+ v.replace_with_range(v.begin()+8, v.begin()+12, Range(a+8, a+16));
+ VERIFY( v.size() == 18 );
+ v.replace_with_range(v.begin()+16, v.begin()+18, Range(a+16, a+20));
+ VERIFY( eq(v, {a, 20}) );
+}
+
+template<typename Range>
+void
+do_test_a()
+{
+ do_test<Range, std::allocator<char>>();
+ do_test<Range, __gnu_test::SimpleAllocator<char>>();
+ do_test<Range, std::allocator<wchar_t>>();
+ do_test<Range, __gnu_test::SimpleAllocator<wchar_t>>();
+}
+
+bool
+test_ranges()
+{
+ using namespace __gnu_test;
+
+ do_test_a<test_forward_range<char>>();
+ do_test_a<test_forward_sized_range<char>>();
+ do_test_a<test_sized_range_sized_sent<char, forward_iterator_wrapper>>();
+
+ do_test_a<test_input_range<char>>();
+ do_test_a<test_input_sized_range<char>>();
+ do_test_a<test_sized_range_sized_sent<char, input_iterator_wrapper>>();
+
+ do_test_a<test_range<char, input_iterator_wrapper_nocopy>>();
+ do_test_a<test_sized_range<char, input_iterator_wrapper_nocopy>>();
+ do_test_a<test_sized_range_sized_sent<char, input_iterator_wrapper_nocopy>>();
+
+ // Not lvalue-convertible to char
+ struct C {
+ C(char v) : val(v) { }
+ operator char() && { return val; }
+ bool operator==(char b) const { return b == val; }
+ char val;
+ };
+ using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>;
+ do_test<rvalue_input_range, std::allocator<char>>();
+
+ return true;
+}
+
+void
+test_overlapping()
+{
+ std::string const s = "1234abcd";
+
+ std::string c = s;
+ c.replace_with_range(c.end(), c.end(), std::string_view(c));
+ VERIFY( c == "1234abcd1234abcd" );
+
+ c = s;
+ c.replace_with_range(c.begin(), c.begin()+4, std::string_view(c).substr(4, 4));
+ VERIFY( c == "abcdabcd" );
+
+ c = s;
+ c.replace_with_range(c.begin()+2, c.begin()+4, std::string_view(c).substr(0, 4));
+ VERIFY( c == "121234abcd" );
+
+ c = s;
+ c.replace_with_range(c.begin()+2, c.begin()+2, std::string_view(c).substr(0, 4));
+ VERIFY( c == "12123434abcd" );
+}
+
+constexpr bool
+test_constexpr()
+{
+#if _GLIBCXX_USE_CXX11_ABI
+ // XXX: this doesn't test the non-forward_range code paths are constexpr.
+ do_test<std::string_view, std::allocator<char>>();
+#endif // _GLIBCXX_USE_CXX11_ABI
+ return true;
+}
+
+int main()
+{
+ test_ranges();
+ test_overlapping();
+ static_assert( test_constexpr() );
+}
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/stold.cc b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/stold.cc
index b64ad0c..dd777c4 100644
--- a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/stold.cc
+++ b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/stold.cc
@@ -31,6 +31,11 @@
void
test01()
{
+ /* If these conditions are not met, basic_string.h doesn't define
+ std::stold(const string&, size_t* = 0), and then the test would
+ fail to compile. */
+#if (_GLIBCXX_HAVE_STRTOLD && ! _GLIBCXX_HAVE_BROKEN_STRTOLD) \
+ || __DBL_MANT_DIG__ == __LDBL_MANT_DIG__
bool test = false;
using namespace std;
@@ -106,6 +111,7 @@ test01()
test = false;
}
VERIFY( test );
+#endif
}
int main()
diff --git a/libstdc++-v3/testsuite/22_locale/ctype/is/string/89728_neg.cc b/libstdc++-v3/testsuite/22_locale/ctype/is/string/89728_neg.cc
index a34b2ae..24aba99 100644
--- a/libstdc++-v3/testsuite/22_locale/ctype/is/string/89728_neg.cc
+++ b/libstdc++-v3/testsuite/22_locale/ctype/is/string/89728_neg.cc
@@ -18,7 +18,6 @@
// <http://www.gnu.org/licenses/>.
// { dg-error "invalid use of incomplete type" "" { target *-*-* } 0 }
-// { dg-error "invalid 'static_cast'" "" { target c++98_only } 0 }
#include <locale>
diff --git a/libstdc++-v3/testsuite/22_locale/num_put/put/char/lwg4084.cc b/libstdc++-v3/testsuite/22_locale/num_put/put/char/lwg4084.cc
index b7c7da1..6ce4e8f 100644
--- a/libstdc++-v3/testsuite/22_locale/num_put/put/char/lwg4084.cc
+++ b/libstdc++-v3/testsuite/22_locale/num_put/put/char/lwg4084.cc
@@ -20,7 +20,11 @@ test_nan()
out << ' ' << nan << ' ' << -nan;
out << std::showpos;
out << ' ' << nan << ' ' << -nan;
+#ifdef _AIX // non-conforming
+ VERIFY( out.str() == " NaNQ -NaNQ NaNQ -NaNQ NaNQ -NaNQ +NaNQ -NaNQ" );
+#else
VERIFY( out.str() == " nan -nan NAN -NAN NAN -NAN +NAN -NAN" );
+#endif
}
void
@@ -36,7 +40,11 @@ test_inf()
out << ' ' << inf << ' ' << -inf;
out << std::showpos;
out << ' ' << inf << ' ' << -inf;
+#ifdef _AIX // non-conforming
+ VERIFY( out.str() == " INF -INF INF -INF INF -INF +INF -INF" );
+#else
VERIFY( out.str() == " inf -inf INF -INF INF -INF +INF -INF" );
+#endif
}
int main()
diff --git a/libstdc++-v3/testsuite/23_containers/deque/capacity/shrink_to_fit.cc b/libstdc++-v3/testsuite/23_containers/deque/capacity/shrink_to_fit.cc
index 7cb6707..6371755 100644
--- a/libstdc++-v3/testsuite/23_containers/deque/capacity/shrink_to_fit.cc
+++ b/libstdc++-v3/testsuite/23_containers/deque/capacity/shrink_to_fit.cc
@@ -1,4 +1,5 @@
// { dg-do run { target c++11 } }
+// { dg-require-effective-target std_allocator_new }
// 2010-01-08 Paolo Carlini <paolo.carlini@oracle.com>
@@ -19,18 +20,42 @@
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
-#include <vector>
+#include <deque>
#include <testsuite_hooks.h>
+#include <replacement_memory_operators.h>
// libstdc++/42573
void test01()
{
- std::vector<int> d(100);
- d.push_back(1);
- d.push_back(1);
- // VERIFY( d.size() < d.capacity() );
+ using namespace std;
+ __gnu_test::counter::reset();
+
+ const size_t buf_size = _GLIBCXX_STD_C::__deque_buf_size(sizeof(size_t));
+ deque<size_t> d;
+ for (size_t i = 0; i != buf_size; ++i)
+ d.push_back(i);
+
+ // No shrink if 1st buffer is full, create some front capacity.
+ d.pop_front();
+
+ // 1 node array allocation + 2 node allocation = 3.
+ VERIFY( __gnu_test::counter::count() == 3 );
+ VERIFY( __gnu_test::counter::get()._M_increments == 3 );
+
d.shrink_to_fit();
- // VERIFY( d.size() == d.capacity() );
+
+ // No reallocation if no exception support, shrink_to_fit is then a
+ // no-op.
+#if __cpp_exceptions
+ // 1 node array allocation + 1 node allocation = 2.
+ const int expected_count = 2;
+ const int expected_increments = 2;
+#else
+ const int expected_count = 3;
+ const int expected_increments = 0;
+#endif
+ VERIFY( __gnu_test::counter::count() == expected_count );
+ VERIFY( __gnu_test::counter::get()._M_increments == 3 + expected_increments );
}
int main()
diff --git a/libstdc++-v3/testsuite/23_containers/deque/cons/from_range.cc b/libstdc++-v3/testsuite/23_containers/deque/cons/from_range.cc
index 96e994d..48fd196 100644
--- a/libstdc++-v3/testsuite/23_containers/deque/cons/from_range.cc
+++ b/libstdc++-v3/testsuite/23_containers/deque/cons/from_range.cc
@@ -1,6 +1,11 @@
// { dg-do run { target c++23 } }
#include <deque>
+
+#if __cpp_lib_containers_ranges != 202202L
+# error "Feature-test macro __cpp_lib_containers_ranges has wrong value in <deque>"
+#endif
+
#include <span>
#include <testsuite_hooks.h>
#include <testsuite_iterators.h>
diff --git a/libstdc++-v3/testsuite/23_containers/flat_map/1.cc b/libstdc++-v3/testsuite/23_containers/flat_map/1.cc
index d9d88c4..01278d7 100644
--- a/libstdc++-v3/testsuite/23_containers/flat_map/1.cc
+++ b/libstdc++-v3/testsuite/23_containers/flat_map/1.cc
@@ -1,4 +1,5 @@
// { dg-do run { target c++23 } }
+// { dg-timeout-factor 2 }
#include <flat_map>
@@ -55,16 +56,17 @@ test_deduction_guide()
std::vector<long, __gnu_test::SimpleAllocator<long>>,
std::vector<float, __gnu_test::SimpleAllocator<float>>>>);
- // LWG4223: deduces flat_map<long, float const>, which in turn instantiates
- // std::vector<cosnt float> that is ill-formed.
- // __gnu_test::test_input_range<std::pair<const long, const float>> r2(0, 0);
- // std::flat_map it5(r2.begin(), r2.begin());
- // std::flat_map fr5(std::from_range, r2);
+ __gnu_test::test_input_range<std::pair<const long, const float>> r2(0, 0);
+ std::flat_map it5(r2.begin(), r2.begin());
+ static_assert(std::is_same_v<decltype(it5), std::flat_map<long, float>>);
+ std::flat_map fr5(std::from_range, r2);
+ static_assert(std::is_same_v<decltype(fr5), std::flat_map<long, float>>);
- // LWG4223: deduces flat_map<const long&, float&>
- //__gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, 0);
- // std::flat_map it6(r3.begin(), r3.begin());
- // std::flat_map fr6(std::from_range, r3);
+ __gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, 0);
+ std::flat_map it6(r3.begin(), r3.begin());
+ static_assert(std::is_same_v<decltype(it6), std::flat_map<long, float>>);
+ std::flat_map fr6(std::from_range, r3);
+ static_assert(std::is_same_v<decltype(fr6), std::flat_map<long, float>>);
__gnu_test::test_input_range<std::tuple<long, float>> r4(0, 0);
std::flat_map it7(r4.begin(), r4.begin());
@@ -241,6 +243,26 @@ test06()
VERIFY( std::ranges::equal(m | std::views::values, (int[]){2, 3, 4, 5, 6}) );
}
+void
+test07()
+{
+ // PR libstdc++/119427 - std::erase_if(std::flat_foo) does not work
+ // PR libstdc++/120465 - erase_if for flat_map calls predicate with incorrect type
+ std::flat_map<int, int> m = {std::pair{1, 2}, {3, 4}, {5, 6}};
+ auto n = std::erase_if(m, [](auto x) { return x.first == 1 || x.second == 6; });
+ VERIFY( n == 2 );
+ VERIFY( std::ranges::equal(m, (std::pair<int,int>[]){{3,4}}) );
+}
+
+void
+test08()
+{
+ // PR libstdc++/120432 - flat_map operator[] is broken for const lvalue keys
+ std::flat_map<int, int> m;
+ const int k = 42;
+ m[k] = 0;
+}
+
int
main()
{
@@ -253,4 +275,6 @@ main()
test04();
test05();
test06();
+ test07();
+ test08();
}
diff --git a/libstdc++-v3/testsuite/23_containers/flat_multimap/1.cc b/libstdc++-v3/testsuite/23_containers/flat_multimap/1.cc
index ff180bf..d746614 100644
--- a/libstdc++-v3/testsuite/23_containers/flat_multimap/1.cc
+++ b/libstdc++-v3/testsuite/23_containers/flat_multimap/1.cc
@@ -1,4 +1,5 @@
// { dg-do run { target c++23 } }
+// { dg-timeout-factor 2 }
#include <flat_map>
#include <deque>
@@ -53,16 +54,17 @@ test_deduction_guide()
std::vector<long, __gnu_test::SimpleAllocator<long>>,
std::vector<float, __gnu_test::SimpleAllocator<float>>>>);
- // LWG4223: deduces flat_multimap<long, float const>, which in turn instantiates
- // std::vector<cosnt float> that is ill-formed.
- // __gnu_test::test_input_range<std::pair<const long, const float>> r2(0, 0);
- // std::flat_multimap it5(r2.begin(), r2.begin());
- // std::flat_multimap fr5(std::from_range, r2);
+ __gnu_test::test_input_range<std::pair<const long, const float>> r2(0, 0);
+ std::flat_multimap it5(r2.begin(), r2.begin());
+ static_assert(std::is_same_v<decltype(it5), std::flat_multimap<long, float>>);
+ std::flat_multimap fr5(std::from_range, r2);
+ static_assert(std::is_same_v<decltype(fr5), std::flat_multimap<long, float>>);
- // LWG4223: deduces flat_multimap<const long&, float&>
- //__gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, 0);
- // std::flat_multimap it6(r3.begin(), r3.begin());
- // std::flat_multimap fr6(std::from_range, r3);
+ __gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, 0);
+ std::flat_multimap it6(r3.begin(), r3.begin());
+ static_assert(std::is_same_v<decltype(it6), std::flat_multimap<long, float>>);
+ std::flat_multimap fr6(std::from_range, r3);
+ static_assert(std::is_same_v<decltype(fr6), std::flat_multimap<long, float>>);
__gnu_test::test_input_range<std::tuple<long, float>> r4(0, 0);
std::flat_multimap it7(r4.begin(), r4.begin());
@@ -219,6 +221,17 @@ test06()
VERIFY( std::ranges::equal(m | std::views::values, (int[]){2, 3, 4, 5, 6}) );
}
+void
+test07()
+{
+ // PR libstdc++/119427 - std::erase_if(std::flat_foo) does not work
+ // PR libstdc++/120465 - erase_if for flat_map calls predicate with incorrect type
+ std::flat_multimap<int, int> m = {std::pair{1, 2}, {3, 4}, {3, 3}, {5, 6}, {6, 6}};
+ auto n = std::erase_if(m, [](auto x) { return x.first == 1 || x.second == 6; });
+ VERIFY( n == 3 );
+ VERIFY( std::ranges::equal(m, (std::pair<int,int>[]){{3,4},{3,3}}) );
+}
+
int
main()
{
@@ -231,4 +244,5 @@ main()
test04();
test05();
test06();
+ test07();
}
diff --git a/libstdc++-v3/testsuite/23_containers/flat_multiset/1.cc b/libstdc++-v3/testsuite/23_containers/flat_multiset/1.cc
index dc3cecd..63855e0 100644
--- a/libstdc++-v3/testsuite/23_containers/flat_multiset/1.cc
+++ b/libstdc++-v3/testsuite/23_containers/flat_multiset/1.cc
@@ -214,6 +214,37 @@ void test07()
#endif
}
+void
+test08()
+{
+ // PR libstdc++/119620 -- flat_set::emplace always constructs element on the stack
+ static int copy_counter;
+ struct A {
+ A() { }
+ A(const A&) { ++copy_counter; }
+ A& operator=(const A&) { ++copy_counter; return *this; }
+ auto operator<=>(const A&) const = default;
+ };
+ std::vector<A> v;
+ v.reserve(2);
+ std::flat_multiset<A> s(std::move(v));
+ A a;
+ s.emplace(a);
+ VERIFY( copy_counter == 1 );
+ s.emplace(a);
+ VERIFY( copy_counter == 2 );
+}
+
+void
+test09()
+{
+ // PR libstdc++/119427 - std::erase_if(std::flat_foo) does not work
+ std::flat_multiset<int> s = {1,1,2,2,3,4,5};
+ auto n = std::erase_if(s, [](int x) { return x % 2 != 0; });
+ VERIFY( n == 4 );
+ VERIFY( std::ranges::equal(s, (int[]){2,2,4}) );
+}
+
int
main()
{
@@ -225,4 +256,6 @@ main()
test05();
test06();
test07();
+ test08();
+ test09();
}
diff --git a/libstdc++-v3/testsuite/23_containers/flat_set/1.cc b/libstdc++-v3/testsuite/23_containers/flat_set/1.cc
index 90f5855..b1d9002 100644
--- a/libstdc++-v3/testsuite/23_containers/flat_set/1.cc
+++ b/libstdc++-v3/testsuite/23_containers/flat_set/1.cc
@@ -229,6 +229,35 @@ void test07()
#endif
}
+void
+test08()
+{
+ // PR libstdc++/119620 -- flat_set::emplace always constructs element on the stack
+ static int copy_counter;
+ struct A {
+ A() { }
+ A(const A&) { ++copy_counter; }
+ A& operator=(const A&) { ++copy_counter; return *this; }
+ auto operator<=>(const A&) const = default;
+ };
+ std::flat_set<A> s;
+ A a;
+ s.emplace(a);
+ VERIFY( copy_counter == 1 );
+ s.emplace(a);
+ VERIFY( copy_counter == 1 );
+}
+
+void
+test09()
+{
+ // PR libstdc++/119427 - std::erase_if(std::flat_foo) does not work
+ std::flat_set<int> s = {1,2,3,4,5};
+ auto n = std::erase_if(s, [](int x) { return x % 2 != 0; });
+ VERIFY( n == 3 );
+ VERIFY( std::ranges::equal(s, (int[]){2,4}) );
+}
+
int
main()
{
@@ -240,4 +269,6 @@ main()
test05();
test06();
test07();
+ test08();
+ test09();
}
diff --git a/libstdc++-v3/testsuite/23_containers/forward_list/48101_neg.cc b/libstdc++-v3/testsuite/23_containers/forward_list/48101_neg.cc
index 2f2ea2a..d18195e 100644
--- a/libstdc++-v3/testsuite/23_containers/forward_list/48101_neg.cc
+++ b/libstdc++-v3/testsuite/23_containers/forward_list/48101_neg.cc
@@ -26,6 +26,5 @@ test01()
}
// { dg-error "non-const, non-volatile value_type" "" { target *-*-* } 0 }
-// { dg-prune-output "std::allocator<.* has no member named " }
// { dg-prune-output "must have the same value_type as its allocator" }
// { dg-prune-output "rebind_alloc" }
diff --git a/libstdc++-v3/testsuite/23_containers/forward_list/cons/from_range.cc b/libstdc++-v3/testsuite/23_containers/forward_list/cons/from_range.cc
index 65b378e..aa70105 100644
--- a/libstdc++-v3/testsuite/23_containers/forward_list/cons/from_range.cc
+++ b/libstdc++-v3/testsuite/23_containers/forward_list/cons/from_range.cc
@@ -1,11 +1,15 @@
// { dg-do run { target c++23 } }
#include <forward_list>
+
+#if __cpp_lib_containers_ranges != 202202L
+# error "Feature-test macro __cpp_lib_containers_ranges has wrong value in <forward_list>"
+#endif
+
#include <span>
#include <testsuite_hooks.h>
#include <testsuite_iterators.h>
#include <testsuite_allocator.h>
-
void
test_deduction_guide(long* p)
{
diff --git a/libstdc++-v3/testsuite/23_containers/list/48101_neg.cc b/libstdc++-v3/testsuite/23_containers/list/48101_neg.cc
index 8b2e075..cc51705 100644
--- a/libstdc++-v3/testsuite/23_containers/list/48101_neg.cc
+++ b/libstdc++-v3/testsuite/23_containers/list/48101_neg.cc
@@ -26,5 +26,4 @@ test01()
}
// { dg-error "non-const, non-volatile value_type" "" { target *-*-* } 0 }
-// { dg-prune-output "std::allocator<.* has no member named " }
// { dg-prune-output "must have the same value_type as its allocator" }
diff --git a/libstdc++-v3/testsuite/23_containers/list/cons/from_range.cc b/libstdc++-v3/testsuite/23_containers/list/cons/from_range.cc
index 31448b9..107ad74 100644
--- a/libstdc++-v3/testsuite/23_containers/list/cons/from_range.cc
+++ b/libstdc++-v3/testsuite/23_containers/list/cons/from_range.cc
@@ -1,6 +1,11 @@
// { dg-do run { target c++23 } }
#include <list>
+
+#if __cpp_lib_containers_ranges != 202202L
+# error "Feature-test macro __cpp_lib_containers_ranges has wrong value in <list>"
+#endif
+
#include <span>
#include <testsuite_hooks.h>
#include <testsuite_iterators.h>
diff --git a/libstdc++-v3/testsuite/23_containers/map/48101_neg.cc b/libstdc++-v3/testsuite/23_containers/map/48101_neg.cc
index 0661eeb..251beee 100644
--- a/libstdc++-v3/testsuite/23_containers/map/48101_neg.cc
+++ b/libstdc++-v3/testsuite/23_containers/map/48101_neg.cc
@@ -28,8 +28,8 @@ test01()
c2.find(2); // { dg-error "here" }
}
-// { dg-error "_Compare = std::(__8::)?less<int.>" "" { target *-*-* } 0 }
-// { dg-error "_Compare = std::(__8::)?allocator<int>" "" { target *-*-* } 0 }
+// { dg-error "_Compare = std::less<int.>" "" { target *-*-* } 0 }
+// { dg-error "_Compare = std::allocator<int>" "" { target *-*-* } 0 }
// { dg-error "comparison object must be invocable" "" { target *-*-* } 0 }
// { dg-prune-output "no match for call" }
// { dg-prune-output "invalid conversion" }
diff --git a/libstdc++-v3/testsuite/23_containers/map/cons/deduction.cc b/libstdc++-v3/testsuite/23_containers/map/cons/deduction.cc
index f8e6e6e..8645988 100644
--- a/libstdc++-v3/testsuite/23_containers/map/cons/deduction.cc
+++ b/libstdc++-v3/testsuite/23_containers/map/cons/deduction.cc
@@ -258,3 +258,49 @@ test_p1518r2()
std::map s2(std::move(m), p);
check_type<Map>(s2);
}
+
+struct MyPred
+{
+ template<typename T, typename U>
+ bool operator()(T const&, U const&) const;
+};
+
+template<typename K, typename V>
+constexpr bool test_lwg4223()
+{
+ using KD = std::remove_cv_t<std::remove_reference_t<K>>;
+ using VD = std::remove_cv_t<std::remove_reference_t<V>>;
+ using Alloc = __gnu_test::SimpleAllocator<std::pair<const KD, VD>>;
+
+ std::initializer_list<std::pair<K, V>> il = {};
+ Alloc a;
+ MyPred p;
+
+ // The remove_cvref_t is not applied here.
+ // static_assert(std::is_same_v<
+ // decltype(std::map(il)),
+ // std::map<KD, VD>>);
+
+ static_assert(std::is_same_v<
+ decltype(std::map(il.begin(), il.end())),
+ std::map<KD, VD>>);
+
+ static_assert(std::is_same_v<
+ decltype(std::map(il.begin(), il.end(), p)),
+ std::map<KD, VD, MyPred>>);
+
+ static_assert(std::is_same_v<
+ decltype(std::map(il.begin(), il.end(), a)),
+ std::map<KD, VD, std::less<KD>, Alloc>>);
+
+ static_assert(std::is_same_v<
+ decltype(std::map(il.begin(), il.end(), p, a)),
+ std::map<KD, VD, MyPred, Alloc>>);
+
+ return true;
+}
+
+static_assert(test_lwg4223<const int, const float>());
+static_assert(test_lwg4223<int&, float&>());
+static_assert(test_lwg4223<int&&, float&&>());
+static_assert(test_lwg4223<const int&, const float&>());
diff --git a/libstdc++-v3/testsuite/23_containers/map/cons/from_range.cc b/libstdc++-v3/testsuite/23_containers/map/cons/from_range.cc
index c740471..3a9fede 100644
--- a/libstdc++-v3/testsuite/23_containers/map/cons/from_range.cc
+++ b/libstdc++-v3/testsuite/23_containers/map/cons/from_range.cc
@@ -1,7 +1,12 @@
// { dg-do run { target c++23 } }
-#include <algorithm>
#include <map>
+
+#if __cpp_lib_containers_ranges != 202202L
+# error "Feature-test macro __cpp_lib_containers_ranges has wrong value in <map>"
+#endif
+
+#include <algorithm>
#include <ranges>
#include <span>
#include <testsuite_allocator.h>
@@ -38,11 +43,11 @@ test_deduction_guide()
__gnu_test::test_input_range<std::pair<const long, const float>> r2(0, 0);
std::map m5(std::from_range, r2);
- static_assert(std::is_same_v<decltype(m5), std::map<long, const float>>);
+ static_assert(std::is_same_v<decltype(m5), std::map<long, float>>);
- // LWG4223: deduces map<const long&, float&>
- //__gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, 0);
- // std::map m6(std::from_range, r3);
+ __gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, 0);
+ std::map m6(std::from_range, r3);
+ static_assert(std::is_same_v<decltype(m6), std::map<long, float>>);
__gnu_test::test_input_range<std::tuple<long, float>> r4(0, 0);
std::map m7(std::from_range, r4);
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/accessors/default.cc b/libstdc++-v3/testsuite/23_containers/mdspan/accessors/default.cc
new file mode 100644
index 0000000..c036f8a
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/accessors/default.cc
@@ -0,0 +1,99 @@
+// { dg-do run { target c++23 } }
+#include <mdspan>
+
+#include <testsuite_hooks.h>
+
+constexpr size_t dyn = std::dynamic_extent;
+
+template<typename Accessor>
+ constexpr void
+ test_accessor_policy()
+ {
+ static_assert(std::copyable<Accessor>);
+ static_assert(std::is_nothrow_move_constructible_v<Accessor>);
+ static_assert(std::is_nothrow_move_assignable_v<Accessor>);
+ static_assert(std::is_nothrow_swappable_v<Accessor>);
+ }
+
+constexpr bool
+test_access()
+{
+ std::default_accessor<double> accessor;
+ std::array<double, 5> a{10, 11, 12, 13, 14};
+ VERIFY(accessor.access(a.data(), 0) == 10);
+ VERIFY(accessor.access(a.data(), 4) == 14);
+ return true;
+}
+
+constexpr bool
+test_offset()
+{
+ std::default_accessor<double> accessor;
+ std::array<double, 5> a{10, 11, 12, 13, 14};
+ VERIFY(accessor.offset(a.data(), 0) == a.data());
+ VERIFY(accessor.offset(a.data(), 4) == a.data() + 4);
+ return true;
+}
+
+class Base
+{ };
+
+class Derived : public Base
+{ };
+
+constexpr void
+test_ctor()
+{
+ // T -> T
+ static_assert(std::is_nothrow_constructible_v<std::default_accessor<double>,
+ std::default_accessor<double>>);
+ static_assert(std::is_convertible_v<std::default_accessor<double>,
+ std::default_accessor<double>>);
+
+ // T -> const T
+ static_assert(std::is_convertible_v<std::default_accessor<double>,
+ std::default_accessor<const double>>);
+ static_assert(std::is_convertible_v<std::default_accessor<Derived>,
+ std::default_accessor<const Derived>>);
+
+ // const T -> T
+ static_assert(!std::is_constructible_v<std::default_accessor<double>,
+ std::default_accessor<const double>>);
+ static_assert(!std::is_constructible_v<std::default_accessor<Derived>,
+ std::default_accessor<const Derived>>);
+
+ // T <-> volatile T
+ static_assert(std::is_convertible_v<std::default_accessor<int>,
+ std::default_accessor<volatile int>>);
+ static_assert(!std::is_constructible_v<std::default_accessor<int>,
+ std::default_accessor<volatile int>>);
+
+ // size difference
+ static_assert(!std::is_constructible_v<std::default_accessor<char>,
+ std::default_accessor<int>>);
+
+ // signedness
+ static_assert(!std::is_constructible_v<std::default_accessor<int>,
+ std::default_accessor<unsigned int>>);
+ static_assert(!std::is_constructible_v<std::default_accessor<unsigned int>,
+ std::default_accessor<int>>);
+
+ // Derived <-> Base
+ static_assert(!std::is_constructible_v<std::default_accessor<Base>,
+ std::default_accessor<Derived>>);
+ static_assert(!std::is_constructible_v<std::default_accessor<Derived>,
+ std::default_accessor<Base>>);
+
+}
+
+int
+main()
+{
+ test_accessor_policy<std::default_accessor<double>>();
+ test_access();
+ static_assert(test_access());
+ test_offset();
+ static_assert(test_offset());
+ test_ctor();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/accessors/default_neg.cc b/libstdc++-v3/testsuite/23_containers/mdspan/accessors/default_neg.cc
new file mode 100644
index 0000000..f8da2b5
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/accessors/default_neg.cc
@@ -0,0 +1,23 @@
+// { dg-do compile { target c++23 } }
+#include<mdspan>
+
+std::default_accessor<int[3]> a; // { dg-error "required from here" }
+
+class AbstractBase
+{
+ virtual void
+ foo() const = 0;
+};
+
+class Derived : public AbstractBase
+{
+ void
+ foo() const override
+ { }
+};
+
+std::default_accessor<Derived> b_ok;
+std::default_accessor<AbstractBase> b_err; // { dg-error "required from here"}
+
+// { dg-prune-output "ElementType must not be an array type" }
+// { dg-prune-output "ElementType must not be an abstract" }
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/extents/class_mandates_neg.cc b/libstdc++-v3/testsuite/23_containers/mdspan/extents/class_mandates_neg.cc
new file mode 100644
index 0000000..f9c1c01
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/class_mandates_neg.cc
@@ -0,0 +1,12 @@
+// { dg-do compile { target c++23 } }
+#include<mdspan>
+
+#include <cstdint>
+
+std::extents<uint8_t, size_t(1) << 9> e1; // { dg-error "from here" }
+std::extents<char, 1> e2; // { dg-error "from here" }
+std::extents<bool, 1> e3; // { dg-error "from here" }
+std::extents<double, 1> e4; // { dg-error "from here" }
+// { dg-prune-output "dynamic or representable as IndexType" }
+// { dg-prune-output "signed or unsigned integer" }
+// { dg-prune-output "invalid use of incomplete type" }
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy.cc b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy.cc
new file mode 100644
index 0000000..a7b3a169
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy.cc
@@ -0,0 +1,82 @@
+// { dg-do run { target c++23 } }
+#include <mdspan>
+
+#include <testsuite_hooks.h>
+
+// Test the copy ctor and the ctor from other extents.
+
+constexpr auto dyn = std::dynamic_extent;
+
+// Not constructible
+static_assert(!std::is_constructible_v<std::extents<int>,
+ std::extents<int, 1>>);
+
+static_assert(!std::is_constructible_v<std::extents<int, 1, 1>,
+ std::extents<int, 1>>);
+
+static_assert(!std::is_constructible_v<std::extents<int, dyn>,
+ std::extents<int, dyn, dyn>>);
+
+static_assert(!std::is_constructible_v<std::extents<int, 2, 2>,
+ std::extents<int, 1, 2>>);
+
+// Nothrow constructible
+static_assert(std::is_nothrow_constructible_v<std::extents<int, 1>,
+ std::extents<unsigned int, dyn>>);
+static_assert(std::is_nothrow_constructible_v<std::extents<unsigned int, dyn>,
+ std::extents<int, 1>>);
+
+// Implicit conversion
+static_assert(!std::is_convertible_v<std::extents<unsigned int>,
+ std::extents<int>>);
+static_assert(std::is_convertible_v<std::extents<int>,
+ std::extents<unsigned int>>);
+
+static_assert(!std::is_convertible_v<std::extents<unsigned int, 1>,
+ std::extents<int, 1>>);
+static_assert(std::is_convertible_v<std::extents<int, 1>,
+ std::extents<unsigned int, 1>>);
+
+static_assert(!std::is_convertible_v<std::extents<int, dyn>,
+ std::extents<int, 1>>);
+static_assert(std::is_convertible_v<std::extents<int, 1>,
+ std::extents<int, dyn>>);
+
+static_assert(!std::is_convertible_v<std::extents<unsigned int, 1>,
+ std::extents<int, dyn>>);
+static_assert(std::is_convertible_v<std::extents<int, 1>,
+ std::extents<unsigned int, dyn>>);
+
+template<typename T, size_t... Extents, typename Other>
+ constexpr void
+ test_ctor(const Other& other)
+ {
+ auto e = std::extents<T, Extents...>(other);
+ VERIFY(e == other);
+ }
+
+constexpr int
+test_all()
+{
+ auto e0 = std::extents<int>();
+ test_ctor<int>(e0);
+
+ auto e1 = std::extents<int, 1, 2, 3>();
+ test_ctor<int, 1, 2, 3>(e1);
+ test_ctor<int, 1, dyn, 3>(e1);
+ test_ctor<unsigned int, 1, dyn, 3>(e1);
+
+ auto e2 = std::extents<unsigned int, 1, dyn, 3>{1, 2, 3};
+ test_ctor<int, 1, 2, 3>(e2);
+ test_ctor<int, 1, dyn, 3>(e2);
+ test_ctor<int, 1, dyn, dyn>(e2);
+ return true;
+}
+
+int
+main()
+{
+ test_all();
+ static_assert(test_all());
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_default.cc b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_default.cc
new file mode 100644
index 0000000..f45d3e5
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_default.cc
@@ -0,0 +1,41 @@
+// { dg-do run { target c++23 } }
+#include <mdspan>
+
+#include <cstdint>
+#include <testsuite_hooks.h>
+
+constexpr auto dyn = std::dynamic_extent;
+
+template<typename Extents>
+ constexpr void
+ test_default_ctor()
+ {
+ Extents exts;
+ for(size_t i = 0; i < Extents::rank(); ++i)
+ if(exts.static_extent(i) == std::dynamic_extent)
+ VERIFY(exts.extent(i) == 0);
+ else
+ VERIFY(std::cmp_equal(exts.extent(i), Extents::static_extent(i)));
+ }
+
+constexpr bool
+test_default_ctor_all()
+{
+ test_default_ctor<std::extents<int, 1>>();
+ test_default_ctor<std::extents<int, dyn>>();
+ test_default_ctor<std::extents<int, 1, 2>>();
+ test_default_ctor<std::extents<int, dyn, 2>>();
+ test_default_ctor<std::extents<int, dyn, dyn>>();
+ test_default_ctor<std::extents<int, 1, 2, 3>>();
+ test_default_ctor<std::extents<int, dyn, 2, dyn>>();
+ test_default_ctor<std::extents<int, dyn, dyn, dyn>>();
+ return true;
+}
+
+int
+main()
+{
+ test_default_ctor_all();
+ static_assert(test_default_ctor_all());
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints.cc b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints.cc
new file mode 100644
index 0000000..3a70efd
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints.cc
@@ -0,0 +1,62 @@
+// { dg-do run { target c++23 } }
+#include <mdspan>
+
+#include <testsuite_hooks.h>
+
+constexpr auto dyn = std::dynamic_extent;
+
+class A {};
+
+// Not constructible if the number of integer-like arguments isn't either
+// rank() or rank_dynamic().
+static_assert(!std::is_constructible_v<std::extents<int>, int>);
+static_assert(!std::is_constructible_v<std::extents<int, dyn, dyn>, int>);
+static_assert(!std::is_constructible_v<std::extents<int, 1, dyn, 3>, int, int>);
+
+// Not constructible from non integer-like objects.
+static_assert(!std::is_constructible_v<std::extents<int, 1>, int, A>);
+
+// No implicit conversion from integer-like objects.
+template<typename Extent, typename... OExtents>
+ constexpr bool
+ is_explicit()
+ {
+ return std::is_nothrow_constructible_v<Extent, OExtents...>
+ && !std::is_convertible_v<Extent, OExtents...>;
+ }
+
+static_assert(is_explicit<std::extents<int, 1>, int>());
+static_assert(is_explicit<std::extents<int, 1>, unsigned int>());
+static_assert(is_explicit<std::extents<unsigned int, 1>, int>());
+
+constexpr bool
+test_all()
+{
+ auto expected = std::extents<int, 1, 2, 3>(1, 2, 3);
+
+ // From all extents.
+ VERIFY((std::extents<int, 1, 2, 3>(1, 2, 3)) == expected);
+ VERIFY((std::extents<int, dyn, 2, 3>(1, 2, 3)) == expected);
+ VERIFY((std::extents<int, dyn, 2, dyn>(1, 2, 3)) == expected);
+
+ VERIFY((std::extents<int, 1, 2, 3>{1, 2, 3}) == expected);
+ VERIFY((std::extents<int, dyn, 2, 3>{1, 2, 3}) == expected);
+ VERIFY((std::extents<int, dyn, 2, dyn>{1, 2, 3}) == expected);
+
+ // From only dynamic extents.
+ VERIFY((std::extents<int, dyn, 2, 3>(1)) == expected);
+ VERIFY((std::extents<int, dyn, 2, dyn>(1, 3)) == expected);
+
+ VERIFY((std::extents<int, dyn, 2, 3>{1}) == expected);
+ VERIFY((std::extents<int, dyn, 2, dyn>{1, 3}) == expected);
+
+ return true;
+}
+
+int
+main()
+{
+ test_all();
+ static_assert(test_all());
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape.cc b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape.cc
new file mode 100644
index 0000000..01624f2
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape.cc
@@ -0,0 +1,160 @@
+// { dg-do run { target c++23 } }
+#include <mdspan>
+
+#include <testsuite_hooks.h>
+
+constexpr auto dyn = std::dynamic_extent;
+
+template<typename Extent, typename T, size_t N>
+ constexpr bool
+ constructible()
+ {
+ return std::is_nothrow_constructible_v<Extent, std::array<T, N>>
+ && std::is_nothrow_constructible_v<Extent, std::span<T, N>>;
+ }
+
+template<typename Extent, typename T, size_t N>
+ constexpr bool
+ not_constructible()
+ {
+ return !std::is_constructible_v<Extent, std::array<T, N>>
+ && !std::is_constructible_v<Extent, std::span<T, N>>;
+ }
+
+template<typename Extent, typename T, size_t N>
+ constexpr bool
+ convertible()
+ {
+ return std::is_convertible_v<std::array<T, N>, Extent>
+ && std::is_convertible_v<std::span<T, N>, Extent>;
+ }
+
+template<typename Extent, typename T, size_t N>
+ constexpr bool
+ not_convertible()
+ {
+ return !std::is_convertible_v<std::array<T, N>, Extent>
+ && !std::is_convertible_v<std::span<T, N>, Extent>;
+ }
+
+static_assert(constructible<std::extents<int, 1, 2>, int, 2>());
+static_assert(not_constructible<std::extents<int, 1, 2>, int, 1>());
+
+static_assert(constructible<std::extents<int>, int, 0>());
+static_assert(convertible<std::extents<int>, int, 0>());
+static_assert(convertible<std::extents<unsigned int>, int, 0>());
+static_assert(convertible<std::extents<int>, unsigned int, 0>());
+
+static_assert(constructible<std::extents<int, 1, dyn>, int, 1>());
+static_assert(convertible<std::extents<int, 1, dyn>, int, 1>());
+static_assert(convertible<std::extents<unsigned int, 1, dyn>, int, 1>());
+static_assert(convertible<std::extents<int, 1, dyn>, unsigned int, 1>());
+
+static_assert(constructible<std::extents<int, 1, dyn>, int, 2>());
+static_assert(not_convertible<std::extents<int, 1, dyn>, int, 2>());
+static_assert(not_convertible<std::extents<unsigned int, 1, dyn>, int, 2>());
+static_assert(not_convertible<std::extents<int, 1, dyn>, unsigned int, 2>());
+
+// Non-integer, but convertible.
+static_assert(constructible<std::extents<int, dyn>, double, 1>());
+static_assert(convertible<std::extents<int, dyn>, double, 1>());
+
+namespace all_extents
+{
+ template<typename Shape>
+ constexpr void
+ test_ctor(Shape shape)
+ {
+ auto expected = std::extents<int, 1, 2, 3>();
+ VERIFY((std::extents<int, 1, dyn, 3>(shape)) == expected);
+ VERIFY((std::extents<int, dyn, dyn, dyn>(shape)) == expected);
+ VERIFY((std::extents<int, 1, 2, 3>(shape)) == expected);
+ }
+
+ constexpr void
+ test_common_shapes()
+ {
+ auto array = std::array<int, 3>{1, 2, 3};
+ auto span_const = std::span<const int, 3>(array);
+ auto span = std::span<int, 3>(array);
+
+ test_ctor(array);
+ test_ctor(span);
+ test_ctor(span_const);
+ }
+
+ constexpr void
+ test_empty_shapes()
+ {
+ auto shape = std::array<int, 0>();
+ auto span = std::span<int, 0>(shape);
+
+ auto expected = std::extents<int>();
+ VERIFY((std::extents<int>(shape)) == expected);
+ VERIFY((std::extents<int>(span)) == expected);
+ }
+
+ constexpr bool
+ test_all()
+ {
+ test_common_shapes();
+ test_empty_shapes();
+ return true;
+ }
+}
+
+namespace only_dynamic_extents
+{
+ template<typename Extents, typename Shape>
+ constexpr void
+ test_ctor(const Shape& shape)
+ {
+ Extents e = shape;
+
+ VERIFY(e.rank_dynamic() == shape.size());
+
+ size_t di = 0;
+ for(size_t i = 0; i < e.rank(); ++i)
+ if(e.static_extent(i) == dyn)
+ VERIFY(e.extent(i) == shape[di++]);
+ }
+
+ template<typename Extents, typename T, size_t N>
+ constexpr void
+ test_all_shape_types(std::array<T, N> shape)
+ {
+ test_ctor<Extents>(shape);
+ test_ctor<Extents>(std::span<T, N>(shape));
+ test_ctor<Extents>(std::span<const T, N>(shape));
+ }
+
+ constexpr void
+ test_common_shapes()
+ {
+ auto s = std::array<int, 0>{};
+ auto s2 = std::array<int, 1>{2};
+ auto s123 = std::array<int, 3>{1, 2, 3};
+
+ test_all_shape_types<std::extents<int, 1, dyn, 3>>(s2);
+ test_all_shape_types<std::extents<int, dyn, dyn, dyn>>(s123);
+ test_all_shape_types<std::extents<int, 1, 2, 3>>(s);
+ }
+
+ constexpr bool
+ test_all()
+ {
+ test_common_shapes();
+ return true;
+ }
+}
+
+int
+main()
+{
+ all_extents::test_all();
+ static_assert(all_extents::test_all());
+
+ only_dynamic_extents::test_all();
+ static_assert(only_dynamic_extents::test_all());
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/extents/custom_integer.cc b/libstdc++-v3/testsuite/23_containers/mdspan/extents/custom_integer.cc
new file mode 100644
index 0000000..2907ad1
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/custom_integer.cc
@@ -0,0 +1,87 @@
+// { dg-do run { target c++23 } }
+#include <mdspan>
+
+#include <testsuite_hooks.h>
+
+// Test construction from a custom integer-like object, that has
+// no copy/move ctor or copy/move assignment operator.
+
+constexpr size_t dyn = std::dynamic_extent;
+
+class IntLike
+{
+public:
+ explicit
+ IntLike(int i)
+ : _M_i(i)
+ { }
+
+ IntLike() = delete;
+ IntLike(const IntLike&) = delete;
+ IntLike(IntLike&&) = delete;
+
+ const IntLike&
+ operator=(const IntLike&) = delete;
+
+ const IntLike&
+ operator=(IntLike&&) = delete;
+
+ constexpr
+ operator int() const noexcept
+ { return _M_i; }
+
+private:
+ int _M_i;
+};
+
+static_assert(std::is_convertible_v<IntLike, int>);
+static_assert(std::is_nothrow_constructible_v<int, IntLike>);
+
+void
+test_shape(const auto& s2, const auto& s23)
+{
+ std::extents<int, 2, 3> expected;
+
+ std::extents<int, 2, 3> e1(s23);
+ VERIFY(e1 == expected);
+
+ std::extents<int, dyn, 3> e2(s2);
+ VERIFY(e2 == expected);
+
+ std::extents<int, dyn, 3> e3(s23);
+ VERIFY(e3 == expected);
+
+ std::extents<int, dyn, dyn> e4(s23);
+ VERIFY(e4 == expected);
+}
+
+void
+test_pack()
+{
+ std::extents<int, 2, 3> expected;
+
+ std::extents<int, dyn, 3> e1(IntLike(2));
+ VERIFY(e1 == expected);
+
+ std::extents<int, dyn, 3> e2(IntLike(2), IntLike(3));
+ VERIFY(e2 == expected);
+
+ std::extents<int, dyn, dyn> e3(IntLike(2), IntLike(3));
+ VERIFY(e3 == expected);
+}
+
+int
+main()
+{
+ auto a2 = std::array<IntLike, 1>{IntLike(2)};
+ auto s2 = std::span<IntLike, 1>(a2);
+
+ auto a23 = std::array<IntLike, 2>{IntLike(2), IntLike(3)};
+ auto s23 = std::span<IntLike, 2>(a23);
+
+ test_shape(a2, a23);
+ test_shape(s2, s23);
+ test_pack();
+
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/extents/misc.cc b/libstdc++-v3/testsuite/23_containers/mdspan/extents/misc.cc
new file mode 100644
index 0000000..e71fdc5
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/misc.cc
@@ -0,0 +1,224 @@
+// { dg-do run { target c++23 } }
+#include <mdspan>
+
+#include <cstdint>
+#include <testsuite_hooks.h>
+
+constexpr size_t dyn = std::dynamic_extent;
+
+// Check class traits.
+static_assert(std::regular<std::extents<int>>);
+static_assert(std::regular<std::extents<int, 1>>);
+static_assert(std::regular<std::extents<int, dyn>>);
+
+static_assert(std::is_trivially_copyable_v<std::extents<int>>);
+static_assert(std::is_trivially_copyable_v<std::extents<int, 1>>);
+static_assert(std::is_trivially_copyable_v<std::extents<int, dyn>>);
+
+// Check member typedefs.
+static_assert(std::is_same_v<std::extents<int, 1, 2>::rank_type, size_t>);
+
+static_assert(std::is_unsigned_v<std::extents<int, 2>::size_type>);
+static_assert(std::is_unsigned_v<std::extents<unsigned int, 2>::size_type>);
+
+static_assert(std::is_same_v<std::extents<int, 2>::index_type, int>);
+static_assert(std::is_same_v<std::extents<unsigned int, 2>::index_type,
+ unsigned int>);
+
+// Check `rank`.
+static_assert(std::extents<int, 1>::rank() == 1);
+static_assert(std::extents<int, dyn>::rank() == 1);
+static_assert(std::extents<int, 2, dyn>::rank() == 2);
+
+// Check `rank_dynamic`.
+static_assert(std::extents<int, 1>::rank_dynamic() == 0);
+static_assert(std::extents<int, dyn>::rank_dynamic() == 1);
+static_assert(std::extents<int, 2, dyn>::rank_dynamic() == 1);
+static_assert(std::extents<int, dyn, dyn>::rank_dynamic() == 2);
+
+template<typename T, size_t... Extents>
+ constexpr bool
+ check_rank_return_types()
+ {
+ auto e = std::extents<T, Extents...>();
+ return std::is_same_v<decltype(e.rank()), size_t>
+ && std::is_same_v<decltype(e.rank_dynamic()), size_t>;
+ }
+
+static_assert(check_rank_return_types<int, 1>());
+
+// Check that the static extents don't take up space.
+static_assert(sizeof(std::extents<int, 1, dyn>) == sizeof(int));
+static_assert(sizeof(std::extents<short, 1, dyn>) == sizeof(short));
+
+template<typename Extents>
+class Container
+{
+ int dummy;
+ [[no_unique_address]] std::extents<size_t> b0;
+};
+
+static_assert(sizeof(Container<std::extents<short, 1, 2>>) == sizeof(int));
+static_assert(sizeof(Container<std::extents<size_t, 1, 2>>) == sizeof(int));
+
+// operator=
+static_assert(std::is_nothrow_assignable_v<std::extents<int, dyn, 2>,
+ std::extents<int, 1, 2>>);
+
+constexpr bool
+test_assign()
+{
+ auto e1 = std::extents<int, 1, 2>();
+ auto e2 = std::extents<int, 1, 2>();
+
+ e2 = e1;
+ VERIFY(e2 == e1);
+
+ auto e5 = std::extents<int, 1, dyn>();
+ e5 = e1;
+ VERIFY(e5 == e1);
+
+ auto e3 = std::extents<int, dyn, dyn>(1, 2);
+ auto e4 = std::extents<int, dyn, dyn>(3, 4);
+ e3 = e4;
+ VERIFY(e3 == e4);
+ return true;
+}
+
+// Deduction guide
+template<size_t Rank, typename... Extents>
+constexpr void
+test_deduction(Extents... exts)
+{
+ std::array<size_t, sizeof...(exts)> shape{static_cast<size_t>(exts)...};
+ std::dextents<size_t, Rank> expected(shape);
+ std::extents e(exts...);
+ static_assert(std::is_same_v<decltype(e), std::dextents<size_t, Rank>>);
+ VERIFY(e == expected);
+}
+
+constexpr bool
+test_deduction_all()
+{
+ test_deduction<0>();
+ test_deduction<1>(1);
+ test_deduction<2>(1.0, 2.0f);
+ test_deduction<3>(int(1), short(2), size_t(3));
+ return true;
+}
+
+class A {};
+
+template<typename... Extents>
+ concept deducible = requires
+ {
+ { std::extents(Extents{}...) }
+ -> std::convertible_to<std::dextents<size_t, sizeof...(Extents)>>;
+ };
+
+static_assert(deducible<int>);
+static_assert(!deducible<A, A>);
+
+// dextents
+static_assert(std::is_same_v<std::dextents<int, 0>, std::extents<int>>);
+static_assert(std::is_same_v<std::dextents<int, 1>, std::extents<int, dyn>>);
+static_assert(std::is_same_v<std::dextents<int, 5>,
+ std::extents<int, dyn, dyn, dyn, dyn, dyn>>);
+
+static_assert(std::dextents<int, 5>::rank() == 5);
+static_assert(std::dextents<int, 5>::rank_dynamic() == 5);
+static_assert(std::is_same_v<typename std::dextents<int, 5>::index_type, int>);
+
+// static_extent
+static_assert(std::extents<int, 1, 2>::static_extent(0) == 1);
+static_assert(std::extents<int, 1, 2>::static_extent(1) == 2);
+
+static_assert(std::extents<int, 1, dyn>::static_extent(0) == 1);
+static_assert(std::extents<int, 1, dyn>::static_extent(1) == dyn);
+
+static_assert(std::extents<int, dyn, dyn>::static_extent(0) == dyn);
+static_assert(std::extents<int, dyn, dyn>::static_extent(1) == dyn);
+
+// extent
+template<typename Extent>
+ constexpr void
+ test_extent(const Extent& e,
+ const std::array<typename Extent::index_type, Extent::rank()>& shape)
+ {
+ for(size_t i = 0; i < e.rank(); ++i)
+ VERIFY(e.extent(i) == shape[i]);
+ }
+
+constexpr bool
+test_extent_all()
+{
+ test_extent(std::extents<int, 1, 2>{}, {1, 2});
+ test_extent(std::extents<int, 1, dyn>{2}, {1, 2});
+ test_extent(std::extents<int, dyn, dyn>{1, 2}, {1, 2});
+ return true;
+}
+
+// operator==
+template<typename Lhs, typename Rhs>
+ constexpr void
+ test_ops_eq(const Lhs& lhs, const Rhs& rhs, bool expected)
+ {
+ VERIFY((lhs == rhs) == expected);
+ VERIFY((lhs != rhs) == !expected);
+ }
+
+constexpr void
+test_op_eq_rank_zero()
+{
+ auto e1 = std::extents<int>();
+ auto e2 = std::extents<int>();
+ auto e3 = std::extents<unsigned int>();
+
+ test_ops_eq(e1, e2, true);
+ test_ops_eq(e1, e3, true);
+}
+
+constexpr void
+test_op_eq_common()
+{
+ auto e1 = std::extents<int, 1, 2, 3>();
+ auto e2 = std::extents<int, 1, 2, 3>();
+ auto e3 = std::extents<int, 1, dyn, 3>(2);
+ auto e4 = std::extents<int, 1, dyn, 3>(3);
+
+ auto e5 = std::extents<int, 1>();
+ auto e6 = std::extents<int, 1, 3, 3>();
+
+ test_ops_eq(e1, e2, true);
+ test_ops_eq(e1, e3, true);
+ test_ops_eq(e1, e4, false);
+
+ test_ops_eq(e1, e5, false);
+ test_ops_eq(e1, e6, false);
+ test_ops_eq(e3, e6, false);
+}
+
+constexpr bool
+test_op_eq_all()
+{
+ test_op_eq_rank_zero();
+ test_op_eq_common();
+ return true;
+}
+
+int
+main()
+{
+ test_assign();
+ static_assert(test_assign());
+
+ test_deduction_all();
+ static_assert(test_deduction_all());
+
+ test_extent_all();
+ static_assert(test_extent_all());
+
+ test_op_eq_all();
+ static_assert(test_op_eq_all());
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/class_mandate_neg.cc b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/class_mandate_neg.cc
new file mode 100644
index 0000000..7091153
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/class_mandate_neg.cc
@@ -0,0 +1,48 @@
+// { dg-do compile { target c++23 } }
+#include<mdspan>
+
+#include <cstdint>
+
+constexpr size_t dyn = std::dynamic_extent;
+static constexpr size_t n = std::numeric_limits<uint8_t>::max() / 2;
+
+template<typename Layout>
+ struct A
+ {
+ typename Layout::mapping<std::extents<uint8_t, n, 2>> m0;
+ typename Layout::mapping<std::extents<uint8_t, n, 2, dyn>> m1;
+ typename Layout::mapping<std::extents<uint8_t, n, 2, 0>> m2;
+
+ using extents_type = std::extents<uint8_t, n, 4>;
+ typename Layout::mapping<extents_type> m3; // { dg-error "required from" }
+ };
+
+template<size_t Count, typename Layout, typename OLayout>
+ bool
+ B()
+ {
+ using Extents = std::extents<uint8_t, dyn, dyn, Count>;
+ using OExtents = std::extents<uint16_t, n, 4, Count>;
+
+ using Mapping = typename Layout::mapping<Extents>;
+ using OMapping = typename OLayout::mapping<OExtents>;
+
+ Mapping m{OMapping{}};
+ return true;
+ };
+
+A<std::layout_left> a_left; // { dg-error "required from" }
+A<std::layout_right> a_right; // { dg-error "required from" }
+A<std::layout_stride> a_stride; // { dg-error "required from" }
+
+auto b1 = B<1, std::layout_left, std::layout_left>(); // { dg-error "required from" }
+auto b2 = B<2, std::layout_left, std::layout_stride>(); // { dg-error "required from" }
+
+auto b3 = B<3, std::layout_right, std::layout_right>(); // { dg-error "required from" }
+auto b4 = B<4, std::layout_right, std::layout_stride>(); // { dg-error "required from" }
+
+auto b5 = B<5, std::layout_stride, std::layout_right>(); // { dg-error "required from" }
+auto b6 = B<6, std::layout_stride, std::layout_left>(); // { dg-error "required from" }
+auto b7 = B<7, std::layout_stride, std::layout_stride>(); // { dg-error "required from" }
+
+// { dg-prune-output "must be representable as index_type" }
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/ctors.cc b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/ctors.cc
new file mode 100644
index 0000000..23c0a55
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/ctors.cc
@@ -0,0 +1,436 @@
+// { dg-do run { target c++23 } }
+#include <mdspan>
+
+#include <cstdint>
+#include <testsuite_hooks.h>
+
+constexpr size_t dyn = std::dynamic_extent;
+
+template<typename Mapping, typename IndexType, size_t... Extents>
+ constexpr void
+ verify(std::extents<IndexType, Extents...> oexts)
+ {
+ auto m = Mapping(oexts);
+ VERIFY(m.extents() == oexts);
+ }
+
+template<typename Mapping, typename OMapping>
+ requires (requires { typename OMapping::layout_type; })
+ constexpr void
+ verify(OMapping other)
+ {
+ constexpr auto rank = Mapping::extents_type::rank();
+ auto m = Mapping(other);
+ VERIFY(m.extents() == other.extents());
+ if constexpr (rank > 0)
+ for(size_t i = 0; i < rank; ++i)
+ VERIFY(std::cmp_equal(m.stride(i), other.stride(i)));
+ }
+
+
+template<typename To, typename From>
+ constexpr void
+ verify_convertible(From from)
+ {
+ static_assert(std::is_convertible_v<From, To>);
+ verify<To>(from);
+ }
+
+template<typename To, typename From>
+ constexpr void
+ verify_nothrow_convertible(From from)
+ {
+ static_assert(std::is_nothrow_constructible_v<To, From>);
+ verify_convertible<To>(from);
+ }
+
+template<typename To, typename From>
+ constexpr void
+ verify_constructible(From from)
+ {
+ static_assert(!std::is_convertible_v<From, To>);
+ static_assert(std::is_constructible_v<To, From>);
+ verify<To>(from);
+ }
+
+template<typename To, typename From>
+ constexpr void
+ verify_nothrow_constructible(From from)
+ {
+ static_assert(std::is_nothrow_constructible_v<To, From>);
+ verify_constructible<To>(from);
+ }
+
+template<typename Mapping, typename OExtents>
+ constexpr void
+ assert_not_constructible()
+ {
+ static_assert(!std::is_constructible_v<Mapping, OExtents>);
+ }
+
+// ctor: mapping()
+namespace default_ctor
+{
+ template<typename Layout, typename Extents>
+ constexpr void
+ test_default_ctor()
+ {
+ using Mapping = typename Layout::mapping<Extents>;
+
+ Mapping m;
+ for(size_t i = 0; i < Extents::rank(); ++i)
+ if (Extents::static_extent(i) == std::dynamic_extent)
+ VERIFY(m.extents().extent(i) == 0);
+ else
+ VERIFY(m.extents().static_extent(i) == Extents::static_extent(i));
+ }
+
+ template<typename Layout>
+ constexpr bool
+ test_default_ctor_all()
+ {
+ test_default_ctor<Layout, std::extents<int, dyn>>();
+ test_default_ctor<Layout, std::extents<int, 1, 2>>();
+ test_default_ctor<Layout, std::extents<int, dyn, 2>>();
+ test_default_ctor<Layout, std::extents<int, dyn, dyn>>();
+ test_default_ctor<Layout, std::extents<int, dyn, 2, dyn>>();
+ test_default_ctor<Layout, std::extents<int, dyn, dyn, dyn>>();
+ return true;
+ }
+
+ template<typename Layout>
+ constexpr void
+ test_all()
+ {
+ test_default_ctor_all<Layout>();
+ static_assert(test_default_ctor_all<Layout>());
+ }
+}
+
+// ctor: mapping(const extents&)
+namespace from_extents
+{
+ template<typename Layout, typename Extents, typename OExtents>
+ constexpr void
+ verify_nothrow_convertible(OExtents oexts)
+ {
+ using Mapping = typename Layout::mapping<Extents>;
+ ::verify_nothrow_convertible<Mapping>(oexts);
+ }
+
+ template<typename Layout, typename Extents, typename OExtents>
+ constexpr void
+ verify_nothrow_constructible(OExtents oexts)
+ {
+ using Mapping = typename Layout::mapping<Extents>;
+ ::verify_nothrow_constructible<Mapping>(oexts);
+ }
+
+ template<typename Layout, typename Extents, typename OExtents>
+ constexpr void
+ assert_not_constructible()
+ {
+ using Mapping = typename Layout::mapping<Extents>;
+ ::assert_not_constructible<Mapping, OExtents>();
+ }
+
+ template<typename Layout>
+ constexpr bool
+ test_ctor()
+ {
+ verify_nothrow_convertible<Layout, std::extents<int>>(
+ std::extents<int>{});
+
+ verify_nothrow_convertible<Layout, std::extents<int, 2>>(
+ std::extents<int, 2>{});
+
+ verify_nothrow_convertible<Layout, std::extents<int, dyn, 3>>(
+ std::extents<int, dyn, 3>{2});
+
+ verify_nothrow_constructible<Layout, std::extents<unsigned int>>(
+ std::extents<int>{});
+
+ verify_nothrow_constructible<Layout, std::extents<int, dyn>>(
+ std::extents<int, 2>{});
+
+ verify_nothrow_constructible<Layout, std::extents<int, dyn, 3>>(
+ std::extents<int, 2, 3>{});
+
+ assert_not_constructible<Layout, std::extents<int>,
+ std::extents<unsigned int>>();
+ assert_not_constructible<Layout, std::extents<int, 2>,
+ std::extents<int, dyn>>();
+ assert_not_constructible<Layout, std::extents<int, 2, 3>,
+ std::extents<int, dyn, 3>>();
+ return true;
+ }
+
+ template<typename Layout, typename Extents>
+ constexpr void
+ assert_deducible(Extents exts)
+ {
+ typename Layout::mapping m(exts);
+ static_assert(std::same_as<decltype(m),
+ typename Layout::mapping<Extents>>);
+ }
+
+ template<typename Layout>
+ constexpr void
+ test_deducible()
+ {
+ assert_deducible<Layout>(std::extents<int>());
+ assert_deducible<Layout>(std::extents<int, 1>());
+ assert_deducible<Layout>(std::extents<int, 1, 2, dyn>(3));
+ }
+
+ template<typename Layout>
+ constexpr void
+ test_all()
+ {
+ test_ctor<Layout>();
+ static_assert(test_ctor<Layout>());
+ test_deducible<Layout>();
+ }
+}
+
+// ctor: mapping(mapping<OExtents>)
+namespace from_same_layout
+{
+ template<typename Layout, typename Extents, typename OExtents>
+ constexpr void
+ verify_nothrow_convertible(OExtents exts)
+ {
+ using Mapping = typename Layout::mapping<Extents>;
+ using OMapping = typename Layout::mapping<OExtents>;
+
+ ::verify_nothrow_convertible<Mapping>(OMapping(exts));
+ }
+
+ template<typename Layout, typename Extents, typename OExtents>
+ constexpr void
+ verify_nothrow_constructible(OExtents exts)
+ {
+ using Mapping = typename Layout::mapping<Extents>;
+ using OMapping = typename Layout::mapping<OExtents>;
+
+ ::verify_nothrow_constructible<Mapping>(OMapping(exts));
+ }
+
+ template<typename Layout>
+ constexpr bool
+ test_ctor()
+ {
+ verify_nothrow_convertible<Layout, std::extents<unsigned int>>(
+ std::extents<int>{});
+
+ verify_nothrow_constructible<Layout, std::extents<int>>(
+ std::extents<unsigned int>{});
+
+ assert_not_constructible<
+ typename Layout::mapping<std::extents<int>>,
+ typename Layout::mapping<std::extents<int, 1>>>();
+
+ assert_not_constructible<
+ typename Layout::mapping<std::extents<int, 1>>,
+ typename Layout::mapping<std::extents<int>>>();
+
+ verify_nothrow_constructible<Layout, std::extents<int, 1>>(
+ std::extents<int, dyn>{1});
+
+ verify_nothrow_convertible<Layout, std::extents<int, dyn>>(
+ std::extents<int, 1>{});
+
+ assert_not_constructible<
+ typename Layout::mapping<std::extents<int, 1, 2>>,
+ typename Layout::mapping<std::extents<int, 1>>>();
+
+ verify_nothrow_constructible<Layout, std::extents<int, 1, 2>>(
+ std::extents<int, dyn, 2>{1});
+
+ verify_nothrow_convertible<Layout, std::extents<int, dyn, 2>>(
+ std::extents<int, 1, 2>{});
+ return true;
+ }
+
+ template<typename Layout>
+ constexpr void
+ test_all()
+ {
+ test_ctor<Layout>();
+ static_assert(test_ctor<Layout>());
+ }
+}
+
+// ctor: mapping(layout_{right,left}::mapping<OExtents>)
+namespace from_left_or_right
+{
+ template<typename SLayout, typename OLayout, typename SExtents,
+ typename OExtents>
+ constexpr void
+ verify_ctor(OExtents oexts)
+ {
+ using SMapping = typename SLayout::mapping<SExtents>;
+ using OMapping = typename OLayout::mapping<OExtents>;
+
+ constexpr bool expected = std::is_convertible_v<OExtents, SExtents>;
+ if constexpr (expected)
+ verify_nothrow_convertible<SMapping>(OMapping(oexts));
+ else
+ verify_nothrow_constructible<SMapping>(OMapping(oexts));
+ }
+
+ template<typename SLayout, typename OLayout>
+ constexpr bool
+ test_ctor()
+ {
+ assert_not_constructible<
+ typename SLayout::mapping<std::extents<int>>,
+ typename OLayout::mapping<std::extents<int, 1>>>();
+
+ verify_ctor<OLayout, SLayout, std::extents<int>>(
+ std::extents<unsigned int>{});
+
+ verify_ctor<OLayout, SLayout, std::extents<unsigned int>>(
+ std::extents<int>{});
+
+ assert_not_constructible<
+ typename SLayout::mapping<std::extents<int, 1>>,
+ typename OLayout::mapping<std::extents<int>>>();
+
+ verify_ctor<OLayout, SLayout, std::extents<int, 1>>(
+ std::extents<int, 1>{});
+
+ verify_ctor<OLayout, SLayout, std::extents<int, 1>>(
+ std::extents<unsigned int, 1>{});
+
+ verify_ctor<OLayout, SLayout, std::extents<unsigned int, 1>>(
+ std::extents<int, 1>{});
+
+ assert_not_constructible<
+ typename SLayout::mapping<std::extents<int, 1, 2>>,
+ typename OLayout::mapping<std::extents<int, 1, 2>>>();
+ return true;
+ }
+
+ template<typename SLayout, typename OLayout>
+ constexpr void
+ test_all()
+ {
+ test_ctor<SLayout, OLayout>();
+ static_assert(test_ctor<SLayout, OLayout>());
+ }
+}
+
+// ctor: mapping(layout_stride::mapping<OExtents>)
+namespace from_stride
+{
+ template<typename Mapping>
+ constexpr auto
+ strides(Mapping m)
+ {
+ constexpr auto rank = Mapping::extents_type::rank();
+ std::array<typename Mapping::index_type, rank> s;
+
+ if constexpr (rank > 0)
+ for(size_t i = 0; i < rank; ++i)
+ s[i] = m.stride(i);
+ return s;
+ }
+
+ template<typename Layout, typename Extents, typename OExtents>
+ constexpr void
+ verify_nothrow_convertible(OExtents oexts)
+ {
+ using Mapping = typename Layout::mapping<Extents>;
+ using OMapping = std::layout_stride::mapping<OExtents>;
+
+ constexpr auto other = OMapping(oexts, strides(Mapping(Extents(oexts))));
+ ::verify_nothrow_convertible<Mapping>(other);
+ }
+
+ template<typename Layout, typename Extents, typename OExtents>
+ constexpr void
+ verify_nothrow_constructible(OExtents oexts)
+ {
+ using Mapping = typename Layout::mapping<Extents>;
+ using OMapping = std::layout_stride::mapping<OExtents>;
+
+ constexpr auto other = OMapping(oexts, strides(Mapping(Extents(oexts))));
+ ::verify_nothrow_constructible<Mapping>(other);
+ }
+
+ template<typename Layout>
+ constexpr bool
+ test_ctor()
+ {
+ assert_not_constructible<
+ typename Layout::mapping<std::extents<int>>,
+ std::layout_stride::mapping<std::extents<int, 1>>>();
+
+ assert_not_constructible<
+ typename Layout::mapping<std::extents<int, 1>>,
+ std::layout_stride::mapping<std::extents<int>>>();
+
+ assert_not_constructible<
+ typename Layout::mapping<std::extents<int, 2>>,
+ std::layout_stride::mapping<std::extents<int, 1>>>();
+
+ verify_nothrow_convertible<Layout, std::extents<int>>(
+ std::extents<int>{});
+
+ verify_nothrow_convertible<Layout, std::extents<unsigned int>>(
+ std::extents<int>{});
+
+ // Rank == 0 doesn't check IndexType for convertibility.
+ verify_nothrow_convertible<Layout, std::extents<int>>(
+ std::extents<unsigned int>{});
+
+ verify_nothrow_constructible<Layout, std::extents<int, 3>>(
+ std::extents<int, 3>{});
+
+ verify_nothrow_constructible<Layout, std::extents<unsigned int, 3>>(
+ std::extents<int, 3>{});
+
+ verify_nothrow_constructible<Layout, std::extents<int, 3>>(
+ std::extents<unsigned int, 3>{});
+
+ verify_nothrow_constructible<Layout, std::extents<int, 3, 5>>(
+ std::extents<int, 3, 5>{});
+
+ verify_nothrow_constructible<Layout, std::extents<unsigned int, 3, 5>>(
+ std::extents<int, 3, 5>{});
+
+ verify_nothrow_constructible<Layout, std::extents<int, 3, 5>>(
+ std::extents<unsigned int, 3, 5>{});
+ return true;
+ }
+
+ template<typename Layout>
+ constexpr void
+ test_all()
+ {
+ test_ctor<Layout>();
+ static_assert(test_ctor<Layout>());
+ }
+}
+
+template<typename Layout>
+ constexpr void
+ test_all()
+ {
+ default_ctor::test_all<Layout>();
+ from_extents::test_all<Layout>();
+ from_same_layout::test_all<Layout>();
+ from_stride::test_all<Layout>();
+ }
+
+int
+main()
+{
+ test_all<std::layout_left>();
+ test_all<std::layout_right>();
+
+ from_left_or_right::test_all<std::layout_left, std::layout_right>();
+ from_left_or_right::test_all<std::layout_right, std::layout_left>();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/empty.cc b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/empty.cc
new file mode 100644
index 0000000..655b9b6
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/empty.cc
@@ -0,0 +1,131 @@
+// { dg-do run { target c++23 } }
+#include <mdspan>
+
+#include <cstdint>
+#include <algorithm>
+#include <testsuite_hooks.h>
+
+constexpr size_t dyn = std::dynamic_extent;
+
+template<typename Mapping>
+ constexpr void
+ invoke_stride(Mapping m)
+ {
+ // Only checking for UB, e.g. signed overflow.
+ for(size_t i = 0; i < Mapping::extents_type::rank(); ++i)
+ m.stride(i);
+ }
+
+template<typename Mapping>
+ constexpr void
+ verify_required_span_size(Mapping m)
+ { VERIFY(m.required_span_size() == 0); }
+
+template<typename Mapping>
+ constexpr void
+ verify_all(Mapping m)
+ {
+ verify_required_span_size(m);
+ invoke_stride(m);
+ }
+
+template<typename Layout, typename Int>
+constexpr void
+test_static_overflow()
+{
+ constexpr Int n1 = std::numeric_limits<Int>::max();
+ constexpr size_t n2 = std::dynamic_extent - 1;
+ constexpr size_t n = std::cmp_less(n1, n2) ? size_t(n1) : n2;
+
+ verify_all(typename Layout::mapping<std::extents<Int, n, n, 0, n, n>>{});
+ verify_all(typename Layout::mapping<std::extents<Int, 0, n, n, n>>{});
+ verify_all(typename Layout::mapping<std::extents<Int, dyn, n, n, n>>{});
+ verify_all(typename Layout::mapping<std::extents<Int, n, n, n, 0>>{});
+ verify_all(typename Layout::mapping<std::extents<Int, n, n, n, dyn>>{});
+}
+
+template<typename Int, size_t N>
+constexpr std::array<Int, N>
+make_strides()
+{
+ std::array<Int, N> strides;
+ std::ranges::fill(strides, Int(1));
+ return strides;
+}
+
+template<typename Layout, typename Extents>
+constexpr typename Layout::mapping<Extents>
+make_mapping(Extents exts)
+{
+ using IndexType = typename Extents::index_type;
+ constexpr auto rank = Extents::rank();
+ constexpr auto strides = make_strides<IndexType, rank>();
+
+ if constexpr (std::same_as<Layout, std::layout_stride>)
+ return typename Layout::mapping(exts, strides);
+ else
+ return typename Layout::mapping(exts);
+}
+
+template<typename Layout, typename Int>
+constexpr void
+test_dynamic_overflow()
+{
+ constexpr Int n1 = std::numeric_limits<Int>::max();
+ constexpr size_t n2 = std::dynamic_extent - 1;
+ constexpr Int n = std::cmp_less(n1, n2) ? n1 : Int(n2);
+
+ verify_all(make_mapping<Layout>(
+ std::extents<Int, dyn, dyn, 0, dyn, dyn>{n, n, n, n}));
+
+ verify_all(make_mapping<Layout>(
+ std::extents<Int, dyn, dyn, dyn, dyn, dyn>{n, n, 0, n, n}));
+
+ verify_all(make_mapping<Layout>(
+ std::extents<Int, dyn, dyn, dyn, 0>{n, n, n}));
+
+ verify_all(make_mapping<Layout>(
+ std::extents<Int, dyn, dyn, dyn, dyn>{n, n, n, 0}));
+
+ verify_all(make_mapping<Layout>(
+ std::extents<Int, 0, dyn, dyn, dyn>{n, n, n}));
+
+ verify_all(make_mapping<Layout>(
+ std::extents<Int, dyn, dyn, dyn, dyn>{0, n, n, n}));
+}
+
+template<typename Layout, typename Int>
+constexpr void
+test_overflow()
+{
+ test_static_overflow<Layout, Int>();
+ test_dynamic_overflow<Layout, Int>();
+}
+
+template<typename Layout>
+constexpr bool
+test_all()
+{
+ test_overflow<Layout, signed char>();
+ test_overflow<Layout, short int>();
+ test_overflow<Layout, int>();
+ test_overflow<Layout, long int>();
+ test_overflow<Layout, long long int>();
+
+ test_overflow<Layout, unsigned char>();
+ test_overflow<Layout, unsigned short int>();
+ test_overflow<Layout, unsigned int>();
+ test_overflow<Layout, unsigned long int>();
+ test_overflow<Layout, unsigned long long int>();
+ test_overflow<Layout, size_t>();
+ return true;
+}
+
+int
+main()
+{
+ static_assert(test_all<std::layout_left>());
+ static_assert(test_all<std::layout_right>());
+ static_assert(test_all<std::layout_stride>());
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/mapping.cc b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/mapping.cc
new file mode 100644
index 0000000..963c804
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/mapping.cc
@@ -0,0 +1,568 @@
+// { dg-do run { target c++23 } }
+#include <mdspan>
+
+#include <cstdint>
+#include <testsuite_hooks.h>
+
+constexpr size_t dyn = std::dynamic_extent;
+
+template<typename Layout, typename Extents>
+ constexpr bool
+ test_mapping_properties()
+ {
+ using M = typename Layout::mapping<Extents>;
+ static_assert(std::__mdspan::__is_extents<typename M::extents_type>);
+ static_assert(std::__mdspan::__mapping_alike<M>);
+ static_assert(std::copyable<M>);
+ static_assert(std::is_nothrow_move_constructible_v<M>);
+ static_assert(std::is_nothrow_move_assignable_v<M>);
+ static_assert(std::is_nothrow_swappable_v<M>);
+ static_assert(std::is_same_v<typename M::extents_type, Extents>);
+ static_assert(std::is_same_v<typename M::index_type,
+ typename M::extents_type::index_type>);
+ static_assert(std::is_same_v<typename M::size_type,
+ typename M::extents_type::size_type>);
+ static_assert(std::is_same_v<typename M::rank_type,
+ typename M::extents_type::rank_type>);
+ static_assert(std::is_same_v<typename M::layout_type, Layout>);
+
+ static_assert(std::is_trivially_copyable_v<M>);
+ static_assert(std::regular<M>);
+
+ static_assert(M::is_always_unique() && M::is_unique());
+ static_assert(M::is_always_strided() && M::is_strided());
+ if constexpr (!std::is_same_v<Layout, std::layout_stride>)
+ static_assert(M::is_always_exhaustive() && M::is_exhaustive());
+ return true;
+ }
+
+template<typename Layout>
+ constexpr bool
+ test_mapping_properties_all()
+ {
+ test_mapping_properties<Layout, std::extents<int>>();
+ test_mapping_properties<Layout, std::extents<int, 1>>();
+ test_mapping_properties<Layout, std::extents<int, dyn>>();
+ test_mapping_properties<Layout, std::extents<int, dyn, dyn>>();
+ return true;
+ }
+
+// Check operator()(Indices...)
+template<typename Mapping, size_t N>
+ constexpr typename Mapping::index_type
+ linear_index(const Mapping& mapping,
+ const std::array<typename Mapping::index_type, N>& indices)
+ {
+ typename Mapping::index_type ret = 0;
+ for(size_t r = 0; r < indices.size(); ++r)
+ ret += indices[r] * mapping.stride(r);
+ return ret;
+ }
+
+template<typename Mapping, typename... Indices>
+ constexpr void
+ test_linear_index(const Mapping& m, Indices... i)
+ {
+ using index_type = typename Mapping::index_type;
+ index_type expected = linear_index(m, std::array{index_type(i)...});
+ VERIFY(m(i...) == expected);
+ VERIFY(m(uint8_t(i)...) == expected);
+ }
+
+template<typename Layout>
+ constexpr void
+ test_linear_index_0d()
+ {
+ constexpr typename Layout::mapping<std::extents<int>> m;
+ VERIFY(m() == 0);
+ }
+
+template<typename Layout>
+ constexpr void
+ test_linear_index_1d()
+ {
+ typename Layout::mapping<std::extents<int, 5>> m;
+ test_linear_index(m, 0);
+ test_linear_index(m, 1);
+ test_linear_index(m, 4);
+ }
+
+template<typename Layout>
+ constexpr void
+ test_linear_index_2d()
+ {
+ typename Layout::mapping<std::extents<int, 3, 256>> m;
+ test_linear_index(m, 0, 0);
+ test_linear_index(m, 1, 0);
+ test_linear_index(m, 0, 1);
+ test_linear_index(m, 1, 1);
+ test_linear_index(m, 2, 4);
+ }
+
+template<typename Layout>
+ struct MappingFactory
+ {
+ template<typename Extents>
+ static constexpr typename Layout::mapping<Extents>
+ create(Extents exts)
+ { return exts; }
+ };
+
+template<>
+ struct MappingFactory<std::layout_stride>
+ {
+ template<typename Extents>
+ static constexpr std::layout_stride::mapping<Extents>
+ create(Extents exts)
+ {
+ if constexpr (Extents::rank() == 0)
+ {
+ auto strides = std::array<size_t, 0>{};
+ return std::layout_stride::mapping(exts, strides);
+ }
+ else if constexpr (Extents::rank() == 1)
+ {
+ auto strides = std::array<size_t, 1>{2};
+ return std::layout_stride::mapping(exts, strides);
+ }
+ else if constexpr (Extents::rank() == 2)
+ {
+ size_t m = exts.extent(1);
+ auto strides = std::array<size_t, 2>{3*m, 2};
+ return std::layout_stride::mapping(exts, strides);
+ }
+ else if constexpr (Extents::rank() == 3)
+ {
+ size_t n = exts.extent(0);
+ size_t m = exts.extent(1);
+ auto strides = std::array<size_t, 3>{3*m, 2, 11*m*n};
+ return std::layout_stride::mapping(exts, strides);
+ }
+ }
+ };
+
+template<typename Layout>
+ constexpr void
+ test_linear_index_3d()
+ {
+ auto m = MappingFactory<Layout>::create(std::extents(3, 5, 7));
+ test_linear_index(m, 0, 0, 0);
+ test_linear_index(m, 1, 0, 0);
+ test_linear_index(m, 0, 1, 0);
+ test_linear_index(m, 0, 0, 1);
+ test_linear_index(m, 1, 1, 0);
+ test_linear_index(m, 2, 4, 6);
+ }
+
+struct IntLikeA
+{
+ operator int()
+ { return 0; }
+};
+
+struct IntLikeB
+{
+ operator int() noexcept
+ { return 0; }
+};
+
+struct NotIntLike
+{ };
+
+template<typename Layout>
+ constexpr void
+ test_has_linear_index_0d()
+ {
+ using Mapping = typename Layout::mapping<std::extents<int>>;
+ static_assert(std::invocable<Mapping>);
+ static_assert(!std::invocable<Mapping, int>);
+ static_assert(!std::invocable<Mapping, IntLikeA>);
+ static_assert(!std::invocable<Mapping, IntLikeB>);
+ static_assert(!std::invocable<Mapping, NotIntLike>);
+ }
+
+template<typename Layout>
+ constexpr void
+ test_has_linear_index_1d()
+ {
+ using Mapping = typename Layout::mapping<std::extents<int, 3>>;
+ static_assert(std::invocable<Mapping, int>);
+ static_assert(!std::invocable<Mapping>);
+ static_assert(!std::invocable<Mapping, IntLikeA>);
+ static_assert(std::invocable<Mapping, IntLikeB>);
+ static_assert(!std::invocable<Mapping, NotIntLike>);
+ static_assert(std::invocable<Mapping, double>);
+ }
+
+template<typename Layout>
+ constexpr void
+ test_has_linear_index_2d()
+ {
+ using Mapping = typename Layout::mapping<std::extents<int, 3, 5>>;
+ static_assert(std::invocable<Mapping, int, int>);
+ static_assert(!std::invocable<Mapping, int>);
+ static_assert(!std::invocable<Mapping, IntLikeA, int>);
+ static_assert(std::invocable<Mapping, IntLikeB, int>);
+ static_assert(!std::invocable<Mapping, NotIntLike, int>);
+ static_assert(std::invocable<Mapping, double, double>);
+ }
+
+template<typename Layout>
+ constexpr bool
+ test_linear_index_all()
+ {
+ test_linear_index_0d<Layout>();
+ test_linear_index_1d<Layout>();
+ test_linear_index_2d<Layout>();
+ test_linear_index_3d<Layout>();
+ test_has_linear_index_0d<Layout>();
+ test_has_linear_index_1d<Layout>();
+ test_has_linear_index_2d<Layout>();
+ return true;
+ }
+
+template<typename Mapping>
+ constexpr typename Mapping::index_type
+ linear_index_end(Mapping m)
+ {
+ using index_type = typename Mapping::index_type;
+ constexpr size_t rank = Mapping::extents_type::rank();
+
+ auto impl = [m]<index_type... Counts>(
+ std::integer_sequence<index_type, Counts...>) -> index_type
+ {
+ auto exts = m.extents();
+ if(((exts.extent(Counts) == 0) || ...))
+ return 0;
+ return m((exts.extent(Counts) - 1)...) + 1;
+ };
+
+ return impl(std::make_integer_sequence<index_type, rank>());
+ }
+
+// Check required_span_size
+template<typename Mapping>
+ constexpr void
+ test_required_span_size(Mapping m)
+ { VERIFY(m.required_span_size() == linear_index_end(m)); }
+
+template<typename Layout>
+ constexpr void
+ test_required_span_size_0d()
+ {
+ typename Layout::mapping<std::extents<int>> m;
+ test_required_span_size(m);
+ }
+
+template<typename Layout>
+ constexpr void
+ test_required_span_size_1d()
+ {
+ auto m = MappingFactory<Layout>::create(std::extents(3));
+ test_required_span_size(m);
+ }
+
+template<typename Layout>
+ constexpr void
+ test_required_span_size_2d()
+ {
+ auto m = MappingFactory<Layout>::create(std::extents(3, 5));
+ test_required_span_size(m);
+ }
+
+template<typename Layout>
+ constexpr void
+ test_required_span_size_3d()
+ {
+ auto m = MappingFactory<Layout>::create(std::extents(3, 5, 7));
+ test_required_span_size(m);
+ }
+
+template<typename Layout>
+ constexpr void
+ test_required_span_size_zero_1d()
+ {
+ auto m = MappingFactory<Layout>::create(std::extents(3, 0));
+ test_required_span_size(m);
+ }
+
+template<typename Layout>
+ constexpr void
+ test_required_span_size_zero_3d()
+ {
+ auto m = MappingFactory<Layout>::create(std::extents(3, 0, 7));
+ test_required_span_size(m);
+ }
+
+template<typename Layout>
+ constexpr bool
+ test_required_span_size_all()
+ {
+ test_required_span_size_0d<Layout>();
+ test_required_span_size_1d<Layout>();
+ test_required_span_size_2d<Layout>();
+ test_required_span_size_3d<Layout>();
+ test_required_span_size_zero_1d<Layout>();
+ test_required_span_size_zero_3d<Layout>();
+ return true;
+ }
+
+// Check stride
+template<typename Layout>
+ constexpr void
+ test_stride_1d()
+ {
+ std::layout_left::mapping<std::extents<int, 3>> m;
+ VERIFY(m.stride(0) == 1);
+ }
+
+template<>
+ constexpr void
+ test_stride_1d<std::layout_stride>()
+ {
+ std::array<int, 1> strides{13};
+ std::layout_stride::mapping m(std::extents<int, 3>{}, strides);
+ VERIFY(m.stride(0) == strides[0]);
+ VERIFY(m.strides() == strides);
+ }
+
+template<typename Layout>
+ constexpr void
+ test_stride_2d();
+
+template<>
+ constexpr void
+ test_stride_2d<std::layout_left>()
+ {
+ std::layout_left::mapping<std::extents<int, 3, 5>> m;
+ VERIFY(m.stride(0) == 1);
+ VERIFY(m.stride(1) == 3);
+ }
+
+template<>
+ constexpr void
+ test_stride_2d<std::layout_right>()
+ {
+ std::layout_right::mapping<std::extents<int, 3, 5>> m;
+ VERIFY(m.stride(0) == 5);
+ VERIFY(m.stride(1) == 1);
+ }
+
+template<>
+ constexpr void
+ test_stride_2d<std::layout_stride>()
+ {
+ std::array<int, 2> strides{13, 2};
+ std::layout_stride::mapping m(std::extents<int, 3, 5>{}, strides);
+ VERIFY(m.stride(0) == strides[0]);
+ VERIFY(m.stride(1) == strides[1]);
+ VERIFY(m.strides() == strides);
+ }
+
+template<typename Layout>
+ constexpr void
+ test_stride_3d();
+
+template<>
+ constexpr void
+ test_stride_3d<std::layout_left>()
+ {
+ std::layout_left::mapping m(std::dextents<int, 3>(3, 5, 7));
+ VERIFY(m.stride(0) == 1);
+ VERIFY(m.stride(1) == 3);
+ VERIFY(m.stride(2) == 3*5);
+ }
+
+template<>
+ constexpr void
+ test_stride_3d<std::layout_right>()
+ {
+ std::layout_right::mapping m(std::dextents<int, 3>(3, 5, 7));
+ VERIFY(m.stride(0) == 5*7);
+ VERIFY(m.stride(1) == 7);
+ VERIFY(m.stride(2) == 1);
+ }
+
+template<>
+ constexpr void
+ test_stride_3d<std::layout_stride>()
+ {
+ std::dextents<int, 3> exts(3, 5, 7);
+ std::array<int, 3> strides{11, 2, 41};
+ std::layout_stride::mapping<std::dextents<int, 3>> m(exts, strides);
+ VERIFY(m.stride(0) == strides[0]);
+ VERIFY(m.stride(1) == strides[1]);
+ VERIFY(m.stride(2) == strides[2]);
+ VERIFY(m.strides() == strides);
+ }
+
+template<typename Layout>
+ constexpr bool
+ test_stride_all()
+ {
+ test_stride_1d<Layout>();
+ test_stride_2d<Layout>();
+ test_stride_3d<Layout>();
+ return true;
+ }
+
+template<typename Mapping>
+ concept has_stride = requires (Mapping m)
+ {
+ { m.stride(0) } -> std::same_as<typename Mapping::index_type>;
+ };
+
+template<typename Layout>
+ constexpr void
+ test_has_stride_0d()
+ {
+ using Mapping = typename Layout::mapping<std::extents<int>>;
+ constexpr bool expected = std::is_same_v<Layout, std::layout_stride>;
+ static_assert(has_stride<Mapping> == expected);
+ }
+
+template<typename Layout>
+ constexpr void
+ test_has_stride_1d()
+ { static_assert(has_stride<typename Layout::mapping<std::extents<int, 1>>>); }
+
+template<typename Layout>
+ constexpr void
+ test_has_stride_2d()
+ {
+ using Extents = std::extents<int, 1, 2>;
+ static_assert(has_stride<typename Layout::mapping<Extents>>);
+ }
+
+// Check operator==
+template<typename Layout>
+ constexpr void
+ test_eq()
+ {
+ typename Layout::mapping<std::extents<int, 1, 2>> m1;
+ typename Layout::mapping<std::extents<int, 2, 2>> m2;
+ typename Layout::mapping<std::dextents<int, 2>> m3(m1);
+
+ VERIFY(m1 == m1);
+ VERIFY(m1 != m2);
+ VERIFY(m1 == m3);
+ VERIFY(m2 != m3);
+ }
+
+template<typename Layout>
+ constexpr void
+ test_eq_zero()
+ {
+ typename Layout::mapping<std::extents<int, 0, 2>> m1;
+ typename Layout::mapping<std::extents<int, 0, 2>> m2;
+ typename Layout::mapping<std::extents<int, 2, 0>> m3;
+
+ VERIFY(m1 == m2);
+ VERIFY(m1 != m3);
+ }
+
+template<typename M1, typename M2>
+ concept has_op_eq = requires (M1 m1, M2 m2)
+ {
+ { m1 == m2 } -> std::same_as<bool>;
+ { m2 == m1 } -> std::same_as<bool>;
+ { m1 != m2 } -> std::same_as<bool>;
+ { m2 != m1 } -> std::same_as<bool>;
+ };
+
+template<typename SLayout, typename OLayout, bool Expected>
+ constexpr void
+ test_has_op_eq()
+ {
+ static_assert(has_op_eq<
+ typename SLayout::mapping<std::extents<int>>,
+ typename OLayout::mapping<std::extents<int>>> == Expected);
+
+ static_assert(!has_op_eq<
+ typename SLayout::mapping<std::extents<int>>,
+ typename OLayout::mapping<std::extents<int, 1>>>);
+
+ static_assert(has_op_eq<
+ typename SLayout::mapping<std::extents<int, 1>>,
+ typename OLayout::mapping<std::extents<int, 1>>> == Expected);
+
+ static_assert(has_op_eq<
+ typename SLayout::mapping<std::extents<int, 1>>,
+ typename OLayout::mapping<std::extents<int, 2>>> == Expected);
+
+ static_assert(!has_op_eq<
+ typename SLayout::mapping<std::extents<int, 1>>,
+ typename OLayout::mapping<std::extents<int, 1, 2>>>);
+
+ static_assert(has_op_eq<
+ typename SLayout::mapping<std::extents<int, 1, 2>>,
+ typename OLayout::mapping<std::extents<int, 1, 2>>> == Expected);
+
+ static_assert(has_op_eq<
+ typename SLayout::mapping<std::extents<int, 1, 2>>,
+ typename OLayout::mapping<std::extents<int, 2, 2>>> == Expected);
+
+ static_assert(!has_op_eq<
+ typename SLayout::mapping<std::extents<int, 1, 2>>,
+ typename OLayout::mapping<std::extents<int, 1, 2, 3>>>);
+ }
+
+constexpr void
+test_has_op_eq_peculiar()
+{
+ static_assert(has_op_eq<
+ std::layout_right::mapping<std::extents<int>>,
+ std::layout_left::mapping<std::extents<unsigned int>>>);
+
+ static_assert(has_op_eq<
+ std::layout_right::mapping<std::extents<int, 1>>,
+ std::layout_left::mapping<std::extents<int, dyn>>>);
+
+ static_assert(!has_op_eq<
+ std::layout_right::mapping<std::extents<int, 1, 2>>,
+ std::layout_left::mapping<std::extents<int, dyn, 2>>>);
+}
+
+template<typename Layout>
+ constexpr bool
+ test_mapping_all()
+ {
+ test_linear_index_all<Layout>();
+ test_required_span_size_all<Layout>();
+ test_stride_all<Layout>();
+
+ test_eq<Layout>();
+ test_eq_zero<Layout>();
+ return true;
+ }
+
+template<typename Layout>
+ constexpr void
+ test_all()
+ {
+ static_assert(std::is_trivially_default_constructible_v<Layout>);
+ static_assert(std::is_trivially_copyable_v<Layout>);
+ static_assert(test_mapping_properties_all<Layout>());
+
+ test_mapping_all<Layout>();
+ static_assert(test_mapping_all<Layout>());
+
+ test_has_stride_0d<Layout>();
+ test_has_stride_1d<Layout>();
+ test_has_stride_2d<Layout>();
+ test_has_op_eq<Layout, Layout, true>();
+ }
+
+int
+main()
+{
+ test_all<std::layout_left>();
+ test_all<std::layout_right>();
+ test_all<std::layout_stride>();
+
+ test_has_op_eq<std::layout_right, std::layout_left, false>();
+ test_has_op_eq<std::layout_right, std::layout_stride, true>();
+ test_has_op_eq<std::layout_left, std::layout_stride, true>();
+ test_has_op_eq_peculiar();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/stride.cc b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/stride.cc
new file mode 100644
index 0000000..c8af5c6
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/stride.cc
@@ -0,0 +1,526 @@
+// { dg-do run { target c++23 } }
+#include <mdspan>
+
+#include <testsuite_hooks.h>
+
+constexpr size_t dyn = std::dynamic_extent;
+
+template<typename MappingStride>
+ constexpr void
+ test_ctor_default_stride()
+ {
+ using Extents = typename MappingStride::extents_type;
+ MappingStride actual;
+ typename std::layout_right::mapping<Extents> expected;
+
+ constexpr auto rank = MappingStride::extents_type::rank();
+ if constexpr (rank > 0)
+ for(size_t i = 0; i < rank; ++i)
+ VERIFY(actual.stride(i) == expected.stride(i));
+ }
+
+constexpr bool
+test_ctor_default_stride_all()
+{
+ test_ctor_default_stride<
+ std::layout_stride::mapping<std::extents<int, 3>>>();
+
+ test_ctor_default_stride<
+ std::layout_stride::mapping<std::extents<int, 3, 5, 7>>>();
+
+ test_ctor_default_stride<
+ std::layout_stride::mapping<std::dextents<int, 3>>>();
+
+ test_ctor_default_stride<
+ std::layout_stride::mapping<std::extents<int, 0, 5, 7>>>();
+
+ test_ctor_default_stride<
+ std::layout_stride::mapping<std::extents<int, 3, dyn, dyn>>>();
+
+ test_ctor_default_stride<
+ std::layout_stride::mapping<std::extents<int, dyn, dyn, 3>>>();
+ return true;
+}
+
+struct IntLikeA
+{
+ operator int()
+ { return 0; }
+};
+
+struct IntLikeB
+{
+ operator int() noexcept
+ { return 0; }
+};
+
+struct NotIntLike
+{ };
+
+template<typename E, typename E_arg, typename T, size_t N, bool Expected>
+constexpr void
+test_stride_constructible()
+{
+ static_assert(std::is_nothrow_constructible_v<
+ std::layout_stride::mapping<E>, E_arg, std::span<T, N>> == Expected);
+ static_assert(std::is_nothrow_constructible_v<
+ std::layout_stride::mapping<E>, E_arg, std::array<T, N>> == Expected);
+ static_assert(!std::is_constructible_v<std::layout_stride::mapping<E>,
+ E_arg>);
+}
+
+constexpr void
+test_stride_constructible_all()
+{
+ using E0 = std::extents<int>;
+ using E1 = std::extents<int, 2>;
+ using E2 = std::extents<int, dyn>;
+
+ test_stride_constructible<E0, E0, int, 0, true>();
+ test_stride_constructible<E0, E0, IntLikeA, 0, false>();
+ test_stride_constructible<E0, E0, IntLikeB, 0, true>();
+ test_stride_constructible<E0, E0, NotIntLike, 0, false>();
+ test_stride_constructible<E1, E1, int, 1, true>();
+ test_stride_constructible<E2, E1, int, 1, true>();
+ test_stride_constructible<E1, E1, int, 2, false>();
+ test_stride_constructible<E1, E0, int, 1, false>();
+}
+
+template<typename Extents, typename Shape>
+ constexpr void
+ test_ctor_shape_strides(Extents exts, Shape strides)
+ {
+ using M = std::layout_stride::mapping<Extents>;
+ M m(exts, strides);
+
+ if constexpr (Extents::rank() > 0)
+ for(size_t i = 0; i < exts.rank(); ++i)
+ {
+ VERIFY(m.stride(i) == strides[i]);
+ VERIFY(m.extents().extent(i) == exts.extent(i));
+ }
+ }
+
+constexpr bool
+test_ctor_shape_stride_all()
+{
+ test_ctor_shape_strides(std::extents<int>{}, std::array<int, 0>{});
+ test_ctor_shape_strides(std::extents<int, 2>{}, std::array<int, 1>{3});
+ test_ctor_shape_strides(std::extents<int, 2, 4, 6>{},
+ std::array<int, 3>{20, 5, 45});
+ return true;
+}
+
+template<typename Extents, std::array<bool, 2> Strided,
+ std::array<bool, 2> Unique, std::array<bool, 2> Exhautive,
+ typename Extents::index_type Offset = 0>
+ struct MappingLike
+ {
+ using extents_type = Extents;
+ using index_type = typename Extents::index_type;
+
+ constexpr
+ MappingLike(extents_type extents,
+ std::array<index_type, Extents::rank()> strides)
+ : _extents(extents), _strides(strides)
+ { }
+
+ static constexpr bool
+ is_always_strided() requires (Strided[0])
+ { return Strided[1]; }
+
+ static constexpr bool
+ is_always_unique() requires (Unique[0])
+ { return Unique[1]; }
+
+ static constexpr bool
+ is_always_exhaustive() requires (Exhautive[0])
+ { return Exhautive[1]; }
+
+ constexpr Extents
+ extents() const { return _extents; }
+
+ constexpr index_type
+ stride(size_t i) const { return _strides[i]; }
+
+ template<typename... Indices>
+ constexpr index_type
+ operator()(Indices... indices) const
+ {
+ if (empty())
+ VERIFY(false);
+
+ std::array<index_type, Extents::rank()> ind_arr{indices...};
+ index_type ret = Offset;
+ for(size_t i = 0; i < Extents::rank(); ++i)
+ ret += ind_arr[i]*_strides[i];
+ return ret;
+ }
+
+ private:
+ constexpr bool
+ empty() const
+ {
+ for (size_t i = 0; i < extents_type::rank(); ++i)
+ if (_extents.extent(i) == 0)
+ return true;
+ return false;
+ }
+
+ Extents _extents;
+ std::array<index_type, Extents::rank()> _strides;
+ };
+
+
+template<size_t Rank>
+struct ExtentLike
+{
+ using index_type = int;
+
+ static constexpr size_t
+ rank() { return Rank; }
+};
+
+
+template<typename E1>
+constexpr void
+test_mapping_like_constructible()
+{
+ using M = std::layout_stride::mapping<E1>;
+ using E2 = std::dextents<typename E1::index_type, E1::rank()>;
+ using E3 = std::dextents<typename E1::index_type, E1::rank() + 1>;
+ using E4 = ExtentLike<E1::rank()>;
+
+ constexpr auto TT = std::array{true, true};
+ constexpr auto FT = std::array{false, true};
+ constexpr auto TF = std::array{true, false};
+
+ static_assert(std::is_constructible_v<M, MappingLike<E1, TT, TT, TT>>);
+ static_assert(std::is_constructible_v<M, MappingLike<E2, TT, TT, TT>>);
+ static_assert(!std::is_constructible_v<M, MappingLike<E3, TT, TT, TT>>);
+ static_assert(!std::is_constructible_v<M, MappingLike<E1, FT, TT, TT>>);
+ static_assert(!std::is_constructible_v<M, MappingLike<E1, TF, TT, TT>>);
+ static_assert(!std::is_constructible_v<M, MappingLike<E1, TT, FT, TT>>);
+ static_assert(!std::is_constructible_v<M, MappingLike<E1, TT, TF, TT>>);
+ static_assert(!std::is_constructible_v<M, MappingLike<E1, TT, TT, FT>>);
+ static_assert(std::is_constructible_v<M, MappingLike<E1, TT, TT, TF>>);
+ static_assert(!std::is_constructible_v<M, MappingLike<E4, TT, TT, TF>>);
+ static_assert(!std::is_constructible_v<M, MappingLike<E4, TT, TT, TT>>);
+}
+
+constexpr void
+test_mapping_like_constructible_all()
+{
+ test_mapping_like_constructible<std::extents<int>>();
+ test_mapping_like_constructible<std::extents<int, 2>>();
+ test_mapping_like_constructible<std::extents<int, 2, 3>>();
+}
+
+template<typename E1, typename E2>
+constexpr void
+test_mapping_like_convertible()
+{
+ using M1 = std::layout_stride::mapping<E1>;
+ using M2 = std::layout_stride::mapping<E2>;
+ constexpr auto TT = std::array{true, true};
+
+ static_assert(!std::is_convertible_v<MappingLike<E1, TT, TT, TT>, M1>);
+ static_assert(!std::is_convertible_v<MappingLike<E2, TT, TT, TT>, M1>);
+ static_assert(!std::is_convertible_v<MappingLike<E1, TT, TT, TT>, M2>);
+
+ static_assert(std::is_convertible_v<std::layout_stride::mapping<E2>, M1>);
+ static_assert(std::is_convertible_v<std::layout_left::mapping<E2>, M1>);
+ static_assert(std::is_convertible_v<std::layout_right::mapping<E2>, M1>);
+
+ static_assert(!std::is_convertible_v<std::layout_stride::mapping<E1>, M2>);
+ static_assert(!std::is_convertible_v<std::layout_left::mapping<E1>, M2>);
+ static_assert(!std::is_convertible_v<std::layout_right::mapping<E1>, M2>);
+}
+
+constexpr void
+test_mapping_like_convertible_all()
+{
+ test_mapping_like_convertible<std::extents<unsigned int>,
+ std::extents<int>>();
+ test_mapping_like_convertible<std::extents<unsigned int, 2>,
+ std::extents<int, 2>>();
+ test_mapping_like_convertible<std::extents<int, dyn, 3>,
+ std::extents<int, 2, 3>>();
+}
+
+template<typename Extents>
+constexpr void
+test_ctor_stride_like(Extents exts, std::array<int, Extents::rank()> strides)
+{
+ auto other_right = std::layout_right::mapping(exts);
+ auto other_left = std::layout_left::mapping(exts);
+ auto other_stride = std::layout_stride::mapping(exts, strides);
+
+ VERIFY(std::layout_stride::mapping<Extents>(other_right) == other_right);
+ VERIFY(std::layout_stride::mapping<Extents>(other_left) == other_left);
+ VERIFY(std::layout_stride::mapping<Extents>(other_stride) == other_stride);
+}
+
+constexpr void
+test_ctor_stride_like_all()
+{
+ using E1 = std::extents<int>;
+ auto s1 = std::array<int, 0>{};
+ test_ctor_stride_like(E1{}, s1);
+
+ using E2 = std::extents<int, 3>;
+ auto s2 = std::array<int, 1>{2};
+ test_ctor_stride_like(E2{}, s2);
+
+ using E3 = std::extents<int, 3, 5, 7>;
+ auto s3 = std::array<int, 3>{5, 1, 15};
+ test_ctor_stride_like(E3{}, s3);
+}
+
+constexpr bool
+test_ctor_strides_all()
+{
+ test_ctor_default_stride_all();
+ test_ctor_shape_stride_all();
+ test_ctor_stride_like_all();
+ return true;
+}
+
+// Check is_exhaustive.
+template<typename Extents, typename Strides>
+ constexpr void
+ test_is_exhaustive(Extents extents, Strides strides, bool expected)
+ {
+ std::layout_stride::mapping<Extents> m(extents, strides);
+ VERIFY(m.is_exhaustive() == expected);
+
+ bool always_exhaustive = extents.rank() == 0 || m.required_span_size() == 0;
+ VERIFY(m.is_always_exhaustive() == always_exhaustive);
+ }
+
+constexpr void
+test_is_exhaustive_zero_1d()
+{
+ std::extents<int, 0> extents;
+ test_is_exhaustive(extents, std::array{1}, true);
+ test_is_exhaustive(extents, std::array{2}, true);
+}
+
+constexpr void
+test_is_exhaustive_zero_3d()
+{
+ std::extents<int, 3, 0, 7> extents;
+
+ test_is_exhaustive(extents, std::array{1, 1, 1}, true);
+ test_is_exhaustive(extents, std::array{1, 2*21, 2*3}, true);
+ test_is_exhaustive(extents, std::array{7, 2*21, 1}, true);
+ test_is_exhaustive(extents, std::array{1, 21, 3}, true);
+ test_is_exhaustive(extents, std::array{7, 21, 1}, true);
+}
+
+constexpr void
+test_is_exhaustive_0d()
+{
+ std::extents<int> extents;
+ test_is_exhaustive(extents, std::array<int, 0>{}, true);
+}
+
+constexpr void
+test_is_exhaustive_1d()
+{
+ std::extents<int, 3> extents;
+ test_is_exhaustive(extents, std::array{1}, true);
+ test_is_exhaustive(extents, std::array{3}, false);
+}
+
+
+constexpr void
+test_is_exhaustive_3d()
+{
+ std::extents<int, 3, dyn, 7> extents(5);
+
+ test_is_exhaustive(extents, std::array{1, 3, 3*5}, true);
+ test_is_exhaustive(extents, std::array{5*7, 1, 5}, true);
+ test_is_exhaustive(extents, std::array{7, 3*7, 1}, true);
+
+ test_is_exhaustive(extents, std::array{1, 3, 2*3*5}, false);
+ test_is_exhaustive(extents, std::array{2*5*7, 1, 2*5}, false);
+ test_is_exhaustive(extents, std::array{2*7, 2*3*7, 2}, false);
+}
+
+constexpr void
+test_is_exhaustive_ones()
+{
+ std::extents<int, 1, 1, 3, 1> extents;
+ test_is_exhaustive(extents, std::array{1, 1, 1, 1}, true);
+ test_is_exhaustive(extents, std::array{1, 1, 1, 3}, true);
+ test_is_exhaustive(extents, std::array{3, 3, 1, 3}, true);
+ test_is_exhaustive(extents, std::array{3, 1, 1, 3}, true);
+}
+
+constexpr bool
+test_is_exhaustive_all()
+{
+ test_is_exhaustive_zero_1d();
+ test_is_exhaustive_zero_3d();
+ test_is_exhaustive_ones();
+ test_is_exhaustive_0d();
+ test_is_exhaustive_1d();
+ test_is_exhaustive_3d();
+ return true;
+}
+
+template<typename Extents, int Offset>
+ using OffsetMapping = MappingLike<Extents, {true, true}, {true, true},
+ {true, false}, Offset>;
+
+template<typename Extents>
+ constexpr void
+ test_eq(Extents exts,
+ std::array<typename Extents::index_type, Extents::rank()> left_strides,
+ std::array<typename Extents::index_type, Extents::rank()> right_strides,
+ std::array<typename Extents::index_type, Extents::rank()> padded_strides)
+ {
+ using DExtents = std::dextents<int, Extents::rank()>;
+
+ std::layout_left::mapping<Extents> ml;
+ std::layout_right::mapping<DExtents> mr(exts);
+
+ std::layout_stride::mapping<Extents> msd;
+ std::layout_stride::mapping<Extents> msl(exts, left_strides);
+ std::layout_stride::mapping<Extents> msr(exts, right_strides);
+ std::layout_stride::mapping<Extents> msp(exts, padded_strides);
+
+ OffsetMapping<Extents, 0> mor{exts, right_strides};
+ OffsetMapping<Extents, 0> mol{exts, left_strides};
+ OffsetMapping<Extents, 0> mop{exts, padded_strides};
+ OffsetMapping<Extents, 1> moo{exts, right_strides};
+
+ VERIFY(msd == mr);
+ VERIFY(msd == mor);
+ VERIFY(msd != msp);
+ VERIFY(msd != mop);
+
+ VERIFY(msl == ml);
+ VERIFY(msl == mol);
+ VERIFY(msd != msp);
+ VERIFY(msl != mop);
+
+ VERIFY(msp == mop);
+ VERIFY(msp != ml);
+ VERIFY(msp != mr);
+
+ VERIFY(msd != moo);
+ }
+
+constexpr void
+test_eq_0d()
+{
+ using Extents = std::extents<int>;
+ Extents exts;
+ std::layout_left::mapping<Extents> ml;
+ std::layout_right::mapping<Extents> mr;
+ std::layout_stride::mapping<Extents> ms;
+ OffsetMapping<Extents, 0> mor{exts, {}};
+ OffsetMapping<Extents, 1> moo{exts, {}};
+
+ VERIFY(ms == ml);
+ VERIFY(ms == mr);
+ VERIFY(ms == mor);
+ VERIFY(ms != moo);
+}
+
+constexpr void
+test_eq_1d()
+{
+ using Extents = std::extents<int, 2>;
+ auto exhaustive_strides = std::array{1};
+ auto padded_strides = std::array{2};
+
+ test_eq(Extents{}, exhaustive_strides, exhaustive_strides, padded_strides);
+}
+
+constexpr void
+test_eq_2d()
+{
+ using Extents = std::extents<int, 1, 2>;
+ auto left_strides = std::array{1, 1};
+ auto right_strides = std::array{2, 1};
+ auto padded_strides = std::array{2, 8};
+
+ test_eq(Extents{}, left_strides, right_strides, padded_strides);
+}
+
+constexpr void
+test_eq_zero()
+{
+ using Extents = std::extents<int, 0, 2>;
+ using Mapping = std::layout_stride::mapping<Extents>;
+
+ Extents exts;
+ std::array<int, 2> sl{1, 5};
+ std::array<int, 2> sr{5, 1};
+
+ Mapping m1(exts, sl);
+ Mapping m2(exts, sl);
+ Mapping m3(exts, sr);
+ OffsetMapping<Extents, 0> m4(exts, sl);
+
+ VERIFY(m1 == m2);
+ VERIFY(m1 != m3);
+ VERIFY(m1 == m4);
+
+}
+
+constexpr bool
+test_eq_all()
+{
+ test_eq_0d();
+ test_eq_1d();
+ test_eq_2d();
+ test_eq_zero();
+ return true;
+}
+
+template<typename M1, typename M2>
+ concept has_op_eq = requires (M1 m1, M2 m2)
+ {
+ { m1 == m2 } -> std::same_as<bool>;
+ { m2 == m1 } -> std::same_as<bool>;
+ { m1 != m2 } -> std::same_as<bool>;
+ { m2 != m1 } -> std::same_as<bool>;
+ };
+
+constexpr void
+test_has_op_eq()
+{
+ using E1 = std::extents<int>;
+ using E2 = std::extents<int, 2>;
+ using E3 = std::extents<int, 1, 2>;
+ constexpr auto FT = std::array{false, true};
+
+ static_assert(!has_op_eq<
+ std::layout_stride::mapping<E1>, MappingLike<E1, FT, FT, FT>>);
+
+ static_assert(!has_op_eq<
+ std::layout_stride::mapping<E2>, MappingLike<E2, FT, FT, FT>>);
+
+ static_assert(!has_op_eq<
+ std::layout_stride::mapping<E3>, MappingLike<E3, FT, FT, FT>>);
+}
+
+int
+main()
+{
+ test_ctor_strides_all();
+ static_assert(test_ctor_strides_all());
+ test_mapping_like_convertible_all();
+ test_mapping_like_constructible_all();
+ test_stride_constructible_all();
+ test_is_exhaustive_all();
+ static_assert(test_is_exhaustive_all());
+ test_eq_all();
+ static_assert(test_eq_all());
+ test_has_op_eq();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/multimap/48101_neg.cc b/libstdc++-v3/testsuite/23_containers/multimap/48101_neg.cc
index f597ef3..1c1c79d 100644
--- a/libstdc++-v3/testsuite/23_containers/multimap/48101_neg.cc
+++ b/libstdc++-v3/testsuite/23_containers/multimap/48101_neg.cc
@@ -28,8 +28,8 @@ test01()
c2.find(2); // { dg-error "here" }
}
-// { dg-error "_Compare = std::(__8::)?less<int.>" "" { target *-*-* } 0 }
-// { dg-error "_Compare = std::(__8::)?allocator<int>" "" { target *-*-* } 0 }
+// { dg-error "_Compare = std::less<int.>" "" { target *-*-* } 0 }
+// { dg-error "_Compare = std::allocator<int>" "" { target *-*-* } 0 }
// { dg-error "comparison object must be invocable" "" { target *-*-* } 0 }
// { dg-prune-output "no match for call" }
// { dg-prune-output "invalid conversion" }
diff --git a/libstdc++-v3/testsuite/23_containers/multimap/cons/deduction.cc b/libstdc++-v3/testsuite/23_containers/multimap/cons/deduction.cc
index f0699e2..de5e6ac 100644
--- a/libstdc++-v3/testsuite/23_containers/multimap/cons/deduction.cc
+++ b/libstdc++-v3/testsuite/23_containers/multimap/cons/deduction.cc
@@ -210,3 +210,49 @@ test_p1518r2()
std::multimap s2(std::move(m), p);
check_type<MMap>(s2);
}
+
+struct MyPred
+{
+ template<typename T, typename U>
+ bool operator()(T const&, U const&) const;
+};
+
+template<typename K, typename V>
+constexpr bool test_lwg4223()
+{
+ using KD = std::remove_cv_t<std::remove_reference_t<K>>;
+ using VD = std::remove_cv_t<std::remove_reference_t<V>>;
+ using Alloc = __gnu_test::SimpleAllocator<std::pair<const KD, VD>>;
+
+ std::initializer_list<std::pair<K, V>> il = {};
+ Alloc a;
+ MyPred p;
+
+ // The remove_cvref_t is not applied here.
+ // static_assert(std::is_same_v<
+ // decltype(std::multimap(il)),
+ // std::multimap<KD, VD>>);
+
+ static_assert(std::is_same_v<
+ decltype(std::multimap(il.begin(), il.end())),
+ std::multimap<KD, VD>>);
+
+ static_assert(std::is_same_v<
+ decltype(std::multimap(il.begin(), il.end(), p)),
+ std::multimap<KD, VD, MyPred>>);
+
+ static_assert(std::is_same_v<
+ decltype(std::multimap(il.begin(), il.end(), a)),
+ std::multimap<KD, VD, std::less<KD>, Alloc>>);
+
+ static_assert(std::is_same_v<
+ decltype(std::multimap(il.begin(), il.end(), p, a)),
+ std::multimap<KD, VD, MyPred, Alloc>>);
+
+ return true;
+}
+
+static_assert(test_lwg4223<const int, const float>());
+static_assert(test_lwg4223<int&, float&>());
+static_assert(test_lwg4223<int&&, float&&>());
+static_assert(test_lwg4223<const int&, const float&>());
diff --git a/libstdc++-v3/testsuite/23_containers/multimap/cons/from_range.cc b/libstdc++-v3/testsuite/23_containers/multimap/cons/from_range.cc
index 3e456f5..5907bab 100644
--- a/libstdc++-v3/testsuite/23_containers/multimap/cons/from_range.cc
+++ b/libstdc++-v3/testsuite/23_containers/multimap/cons/from_range.cc
@@ -1,7 +1,12 @@
// { dg-do run { target c++23 } }
-#include <algorithm>
#include <map>
+
+#if __cpp_lib_containers_ranges != 202202L
+# error "Feature-test macro __cpp_lib_containers_ranges has wrong value in <map>"
+#endif
+
+#include <algorithm>
#include <ranges>
#include <span>
#include <testsuite_allocator.h>
@@ -38,11 +43,11 @@ test_deduction_guide()
__gnu_test::test_input_range<std::pair<const long, const float>> r2(0, 0);
std::multimap m5(std::from_range, r2);
- static_assert(std::is_same_v<decltype(m5), std::multimap<long, const float>>);
+ static_assert(std::is_same_v<decltype(m5), std::multimap<long, float>>);
- // LWG4223: deduces multimap<const long&, float&>
- //__gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, 0);
- // std::multimap m6(std::from_range, r3);
+ __gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, 0);
+ std::multimap m6(std::from_range, r3);
+ static_assert(std::is_same_v<decltype(m6), std::multimap<long, float>>);
__gnu_test::test_input_range<std::tuple<long, float>> r4(0, 0);
std::multimap m7(std::from_range, r4);
diff --git a/libstdc++-v3/testsuite/23_containers/multiset/48101_neg.cc b/libstdc++-v3/testsuite/23_containers/multiset/48101_neg.cc
index f0786cf..3cc0658 100644
--- a/libstdc++-v3/testsuite/23_containers/multiset/48101_neg.cc
+++ b/libstdc++-v3/testsuite/23_containers/multiset/48101_neg.cc
@@ -29,7 +29,6 @@ test01()
// { dg-error "non-const, non-volatile value_type" "" { target *-*-* } 0 }
// { dg-error "comparison object must be invocable" "" { target *-*-* } 0 }
-// { dg-prune-output "std::allocator<.* has no member named " }
// { dg-prune-output "must have the same value_type as its allocator" }
// { dg-prune-output "no match for call" }
// { dg-prune-output "invalid conversion" }
diff --git a/libstdc++-v3/testsuite/23_containers/multiset/cons/from_range.cc b/libstdc++-v3/testsuite/23_containers/multiset/cons/from_range.cc
index 43821ca..cdba7eb 100644
--- a/libstdc++-v3/testsuite/23_containers/multiset/cons/from_range.cc
+++ b/libstdc++-v3/testsuite/23_containers/multiset/cons/from_range.cc
@@ -1,8 +1,13 @@
// { dg-do run { target c++23 } }
+#include <set>
+
+#if __cpp_lib_containers_ranges != 202202L
+# error "Feature-test macro __cpp_lib_containers_ranges has wrong value in <set>"
+#endif
+
#include <algorithm>
#include <ranges>
-#include <set>
#include <span>
#include <testsuite_allocator.h>
#include <testsuite_hooks.h>
diff --git a/libstdc++-v3/testsuite/23_containers/priority_queue/cons_from_range.cc b/libstdc++-v3/testsuite/23_containers/priority_queue/cons_from_range.cc
index 977ef98..87e404b 100644
--- a/libstdc++-v3/testsuite/23_containers/priority_queue/cons_from_range.cc
+++ b/libstdc++-v3/testsuite/23_containers/priority_queue/cons_from_range.cc
@@ -1,7 +1,12 @@
// { dg-do run { target c++23 } }
-#include <algorithm>
#include <queue>
+
+#if __cpp_lib_containers_ranges != 202202L
+# error "Feature-test macro __cpp_lib_containers_ranges has wrong value in <queue>"
+#endif
+
+#include <algorithm>
#include <ranges>
#include <span>
#include <testsuite_allocator.h>
diff --git a/libstdc++-v3/testsuite/23_containers/queue/cons_from_range.cc b/libstdc++-v3/testsuite/23_containers/queue/cons_from_range.cc
index c21f52c..039d084 100644
--- a/libstdc++-v3/testsuite/23_containers/queue/cons_from_range.cc
+++ b/libstdc++-v3/testsuite/23_containers/queue/cons_from_range.cc
@@ -1,7 +1,12 @@
// { dg-do run { target c++23 } }
-#include <list>
#include <queue>
+
+#if __cpp_lib_containers_ranges != 202202L
+# error "Feature-test macro __cpp_lib_containers_ranges has wrong value in <queue>"
+#endif
+
+#include <list>
#include <span>
#include <testsuite_allocator.h>
#include <testsuite_hooks.h>
diff --git a/libstdc++-v3/testsuite/23_containers/set/48101_neg.cc b/libstdc++-v3/testsuite/23_containers/set/48101_neg.cc
index e8dec72..fe38d1a 100644
--- a/libstdc++-v3/testsuite/23_containers/set/48101_neg.cc
+++ b/libstdc++-v3/testsuite/23_containers/set/48101_neg.cc
@@ -29,7 +29,6 @@ test01()
// { dg-error "non-const, non-volatile value_type" "" { target *-*-* } 0 }
// { dg-error "comparison object must be invocable" "" { target *-*-* } 0 }
-// { dg-prune-output "std::allocator<.* has no member named " }
// { dg-prune-output "must have the same value_type as its allocator" }
// { dg-prune-output "no match for call" }
// { dg-prune-output "invalid conversion" }
diff --git a/libstdc++-v3/testsuite/23_containers/set/cons/from_range.cc b/libstdc++-v3/testsuite/23_containers/set/cons/from_range.cc
index 869326f..efde05d 100644
--- a/libstdc++-v3/testsuite/23_containers/set/cons/from_range.cc
+++ b/libstdc++-v3/testsuite/23_containers/set/cons/from_range.cc
@@ -1,8 +1,13 @@
// { dg-do run { target c++23 } }
+#include <set>
+
+#if __cpp_lib_containers_ranges != 202202L
+# error "Feature-test macro __cpp_lib_containers_ranges has wrong value in <set>"
+#endif
+
#include <algorithm>
#include <ranges>
-#include <set>
#include <span>
#include <testsuite_allocator.h>
#include <testsuite_hooks.h>
diff --git a/libstdc++-v3/testsuite/23_containers/stack/cons_from_range.cc b/libstdc++-v3/testsuite/23_containers/stack/cons_from_range.cc
index e957d0c..2ee52e1 100644
--- a/libstdc++-v3/testsuite/23_containers/stack/cons_from_range.cc
+++ b/libstdc++-v3/testsuite/23_containers/stack/cons_from_range.cc
@@ -1,8 +1,13 @@
// { dg-do run { target c++23 } }
+#include <stack>
+
+#if __cpp_lib_containers_ranges != 202202L
+# error "Feature-test macro __cpp_lib_containers_ranges has wrong value in <span>"
+#endif
+
#include <ranges>
#include <span>
-#include <stack>
#include <testsuite_allocator.h>
#include <testsuite_hooks.h>
#include <testsuite_iterators.h>
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/96088.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/96088.cc
index c7dfd4f..0ec0bba 100644
--- a/libstdc++-v3/testsuite/23_containers/unordered_map/96088.cc
+++ b/libstdc++-v3/testsuite/23_containers/unordered_map/96088.cc
@@ -1,6 +1,6 @@
// { dg-do run { target c++17 } }
// { dg-require-effective-target std_allocator_new }
-// { dg-xfail-run-if "AIX operator new" { powerpc-ibm-aix* } }
+// { dg-require-effective-target c++20 { target powerpc-ibm-aix* } }
// Copyright (C) 2021-2025 Free Software Foundation, Inc.
//
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/cons/66055.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/cons/66055.cc
index c7a12c1..0f95976 100644
--- a/libstdc++-v3/testsuite/23_containers/unordered_map/cons/66055.cc
+++ b/libstdc++-v3/testsuite/23_containers/unordered_map/cons/66055.cc
@@ -27,7 +27,10 @@ using alloc_type = test_type::allocator_type;
test_type h1(10, alloc_type());
test_type h2(10, hasher_type(), alloc_type());
-test_type h3(h1.begin(), h1.end(), 10, alloc_type());
-test_type h4(h1.begin(), h1.end(), 10, hasher_type(), alloc_type());
-test_type h5({ { 1, 1 } }, 10, alloc_type());
-test_type h6({ { 1, 1 } }, 10, hasher_type(), alloc_type());
+test_type h3(h1.begin(), h1.end(), alloc_type());
+test_type h4(h1.begin(), h1.end(), 10, alloc_type());
+test_type h5(h1.begin(), h1.end(), 10, hasher_type(), alloc_type());
+test_type h6({ { 1, 1 } }, alloc_type());
+test_type h7({ { 1, 1 } }, 10, alloc_type());
+test_type h8({ { 1, 1 } }, 10, hasher_type(), alloc_type());
+
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/cons/deduction.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/cons/deduction.cc
index 8b69af8..26013da 100644
--- a/libstdc++-v3/testsuite/23_containers/unordered_map/cons/deduction.cc
+++ b/libstdc++-v3/testsuite/23_containers/unordered_map/cons/deduction.cc
@@ -16,12 +16,28 @@ static_assert(std::is_same_v<
std::unordered_map<int, double>>);
static_assert(std::is_same_v<
+ decltype(std::unordered_map{{std::pair{1, 2.0},
+ {2, 3.0}, {3, 4.0}},
+ SimpleAllocator<std::pair<const int, double>>{}}),
+ std::unordered_map<int, double, std::hash<int>,
+ std::equal_to<int>,
+ SimpleAllocator<std::pair<const int, double>>>>);
+
+static_assert(std::is_same_v<
decltype(std::unordered_map{
{std::pair{1, 2.0}, {2, 3.0}, {3, 4.0}},
1}),
std::unordered_map<int, double>>);
static_assert(std::is_same_v<
+ decltype(std::unordered_map{
+ {std::pair{1, 2.0}, {2, 3.0}, {3, 4.0}},
+ 1, SimpleAllocator<std::pair<const int, double>>{}}),
+ std::unordered_map<int, double, std::hash<int>,
+ std::equal_to<int>,
+ SimpleAllocator<std::pair<const int, double>>>>);
+
+static_assert(std::is_same_v<
decltype(std::unordered_map{{std::pair{1, 2.0},
{2, 3.0}, {3, 4.0}},
{}, std::hash<int>{}, std::equal_to<int>{}}),
@@ -98,6 +114,18 @@ void f()
static_assert(std::is_same_v<
decltype(std::unordered_map{x.begin(), x.end(),
+ std::allocator<std::pair<const int, double>>{}}),
+ std::unordered_map<int, double>>);
+
+ static_assert(std::is_same_v<
+ decltype(std::unordered_map{x.begin(), x.end(),
+ SimpleAllocator<std::pair<const int, double>>{}}),
+ std::unordered_map<int, double, std::hash<int>,
+ std::equal_to<int>,
+ SimpleAllocator<std::pair<const int, double>>>>);
+
+ static_assert(std::is_same_v<
+ decltype(std::unordered_map{x.begin(), x.end(),
1, std::hash<int>{},
std::allocator<std::pair<const int, double>>{}}),
std::unordered_map<int, double>>);
@@ -162,3 +190,72 @@ test_p1518r2()
std::unordered_map s2(std::move(m), p);
check_type<UMap>(s2);
}
+
+struct MyHash
+{
+ template<typename T>
+ std::size_t operator()(T const&) const;
+};
+
+struct MyPred
+{
+ template<typename T, typename U>
+ bool operator()(T const&, U const&) const;
+};
+
+template<typename K, typename V>
+constexpr bool test_lwg4223()
+{
+ using KD = std::remove_cv_t<std::remove_reference_t<K>>;
+ using VD = std::remove_cv_t<std::remove_reference_t<V>>;
+ using Alloc = __gnu_test::SimpleAllocator<std::pair<const KD, VD>>;
+
+ std::initializer_list<std::pair<K, V>> il = {};
+ Alloc a;
+ MyHash h;
+ MyPred p;
+
+ // The remove_cvref_t is not applied here.
+ // static_assert(std::is_same_v<
+ // decltype(std::unordered_map(il)),
+ // std::unordered_map<KD, VD>>);
+
+ static_assert(std::is_same_v<
+ decltype(std::unordered_map(il.begin(), il.end())),
+ std::unordered_map<KD, VD>>);
+
+ static_assert(std::is_same_v<
+ decltype(std::unordered_map(il.begin(), il.end(), 0)),
+ std::unordered_map<KD, VD>>);
+
+ static_assert(std::is_same_v<
+ decltype(std::unordered_map(il.begin(), il.end(), 0, h)),
+ std::unordered_map<KD, VD, MyHash>>);
+
+ static_assert(std::is_same_v<
+ decltype(std::unordered_map(il.begin(), il.end(), 0, h, p)),
+ std::unordered_map<KD, VD, MyHash, MyPred>>);
+
+ static_assert(std::is_same_v<
+ decltype(std::unordered_map(il.begin(), il.end(), a)),
+ std::unordered_map<KD, VD, std::hash<KD>, std::equal_to<KD>, Alloc>>);
+
+ static_assert(std::is_same_v<
+ decltype(std::unordered_map(il.begin(), il.end(), 0, a)),
+ std::unordered_map<KD, VD, std::hash<KD>, std::equal_to<KD>, Alloc>>);
+
+ static_assert(std::is_same_v<
+ decltype(std::unordered_map(il.begin(), il.end(), 0, h, a)),
+ std::unordered_map<KD, VD, MyHash, std::equal_to<KD>, Alloc>>);
+
+ static_assert(std::is_same_v<
+ decltype(std::unordered_map(il.begin(), il.end(), 0, h, p, a)),
+ std::unordered_map<KD, VD, MyHash, MyPred, Alloc>>);
+
+ return true;
+}
+
+static_assert(test_lwg4223<const int, const float>());
+static_assert(test_lwg4223<int&, float&>());
+static_assert(test_lwg4223<int&&, float&&>());
+static_assert(test_lwg4223<const int&, const float&>());
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/cons/from_range.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/cons/from_range.cc
index 6d1da5b..04479a5e 100644
--- a/libstdc++-v3/testsuite/23_containers/unordered_map/cons/from_range.cc
+++ b/libstdc++-v3/testsuite/23_containers/unordered_map/cons/from_range.cc
@@ -1,7 +1,12 @@
// { dg-do run { target c++23 } }
-#include <algorithm>
#include <unordered_map>
+
+#if __cpp_lib_containers_ranges != 202202L
+# error "Feature-test macro __cpp_lib_containers_ranges has wrong value in <unordered_map>"
+#endif
+
+#include <algorithm>
#include <span>
#include <testsuite_allocator.h>
#include <testsuite_hooks.h>
@@ -73,13 +78,11 @@ test_deduction_guide()
__gnu_test::test_input_range<std::pair<const long, const float>> r2(0, 0);
std::unordered_map m9(std::from_range, r2);
- static_assert(std::is_same_v<
- decltype(m9),
- std::unordered_map<long, const float>>);
+ static_assert(std::is_same_v<decltype(m9), std::unordered_map<long, float>>);
- // LWG4223: deduces map<const long&, float&>
- // __gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, 0);
- // std::unordered_map m10(std::from_range, r3);
+ __gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, 0);
+ std::unordered_map m10(std::from_range, r3);
+ static_assert(std::is_same_v<decltype(m10), std::unordered_map<long, float>>);
__gnu_test::test_input_range<std::tuple<long, float>> r4(0, 0);
std::unordered_map m11(std::from_range, r4);
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_arrow_operator_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_arrow_operator_neg.cc
new file mode 100644
index 0000000..09870a7
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_arrow_operator_neg.cc
@@ -0,0 +1,17 @@
+// { dg-do run { target c++11 xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <unordered_map>
+#include <debug/unordered_checks.h>
+
+void test01()
+{
+ __gnu_test::invalid_local_iterator_arrow_operator
+ <std::unordered_map<int, int>>();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_const_conversion_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_const_conversion_neg.cc
new file mode 100644
index 0000000..7bfe3a8
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_const_conversion_neg.cc
@@ -0,0 +1,17 @@
+// { dg-do run { target c++11 xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <unordered_map>
+#include <debug/unordered_checks.h>
+
+void test01()
+{
+ __gnu_test::invalid_local_iterator_const_conversion
+ <std::unordered_map<int, int>>();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_copy_assignment_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_copy_assignment_neg.cc
new file mode 100644
index 0000000..d3b671b
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_copy_assignment_neg.cc
@@ -0,0 +1,17 @@
+// { dg-do run { target c++11 xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <unordered_map>
+#include <debug/unordered_checks.h>
+
+void test01()
+{
+ __gnu_test::invalid_local_iterator_copy_assignment
+ <std::unordered_map<int, int>>();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_copy_construction_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_copy_construction_neg.cc
new file mode 100644
index 0000000..d609671
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_copy_construction_neg.cc
@@ -0,0 +1,17 @@
+// { dg-do run { target c++11 xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <unordered_map>
+#include <debug/unordered_checks.h>
+
+void test01()
+{
+ __gnu_test::invalid_local_iterator_copy_construction
+ <std::unordered_map<int, int>>();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_move_assignment_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_move_assignment_neg.cc
new file mode 100644
index 0000000..8d2ed6b
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_move_assignment_neg.cc
@@ -0,0 +1,17 @@
+// { dg-do run { target c++11 xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <unordered_map>
+#include <debug/unordered_checks.h>
+
+void test01()
+{
+ __gnu_test::invalid_local_iterator_move_assignment
+ <std::unordered_map<int, int>>();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_move_construction_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_move_construction_neg.cc
new file mode 100644
index 0000000..dd9b7dc
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalid_local_iterator_move_construction_neg.cc
@@ -0,0 +1,17 @@
+// { dg-do run { target c++11 xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <unordered_map>
+#include <debug/unordered_checks.h>
+
+void test01()
+{
+ __gnu_test::invalid_local_iterator_move_construction
+ <std::unordered_map<int, int>>();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/debug/max_load_factor_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/max_load_factor_neg.cc
index 7fbc453..2596798 100644
--- a/libstdc++-v3/testsuite/23_containers/unordered_map/debug/max_load_factor_neg.cc
+++ b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/max_load_factor_neg.cc
@@ -22,7 +22,7 @@
void test01()
{
- std::unordered_multimap<int, int> um;
+ std::unordered_map<int, int> um;
um.max_load_factor(-1.0f);
}
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/96088.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/96088.cc
index 6f94296..3c1de37 100644
--- a/libstdc++-v3/testsuite/23_containers/unordered_multimap/96088.cc
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/96088.cc
@@ -1,6 +1,6 @@
// { dg-do run { target c++17 } }
// { dg-require-effective-target std_allocator_new }
-// { dg-xfail-run-if "AIX operator new" { powerpc-ibm-aix* } }
+// { dg-require-effective-target c++20 { target powerpc-ibm-aix* } }
// Copyright (C) 2021-2025 Free Software Foundation, Inc.
//
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/66055.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/66055.cc
index dc0a651..eecc600 100644
--- a/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/66055.cc
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/66055.cc
@@ -27,7 +27,9 @@ using alloc_type = test_type::allocator_type;
test_type h1(10, alloc_type());
test_type h2(10, hasher_type(), alloc_type());
-test_type h3(h1.begin(), h1.end(), 10, alloc_type());
-test_type h4(h1.begin(), h1.end(), 10, hasher_type(), alloc_type());
-test_type h5({ { 1, 1 } }, 10, alloc_type());
-test_type h6({ { 1, 1 } }, 10, hasher_type(), alloc_type());
+test_type h3(h1.begin(), h1.end(), alloc_type());
+test_type h4(h1.begin(), h1.end(), 10, alloc_type());
+test_type h5(h1.begin(), h1.end(), 10, hasher_type(), alloc_type());
+test_type h6({ { 1, 1 } }, alloc_type());
+test_type h7({ { 1, 1 } }, 10, alloc_type());
+test_type h8({ { 1, 1 } }, 10, hasher_type(), alloc_type());
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/deduction.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/deduction.cc
index e7e535b..1db58a0 100644
--- a/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/deduction.cc
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/deduction.cc
@@ -16,6 +16,28 @@ static_assert(std::is_same_v<
std::unordered_multimap<int, double>>);
static_assert(std::is_same_v<
+ decltype(std::unordered_multimap{
+ {std::pair{1, 2.0}, {2, 3.0}, {3, 4.0}},
+ SimpleAllocator<std::pair<const int, double>>{}}),
+ std::unordered_multimap<int, double, std::hash<int>,
+ std::equal_to<int>,
+ SimpleAllocator<std::pair<const int, double>>>>);
+
+static_assert(std::is_same_v<
+ decltype(std::unordered_multimap{
+ {std::pair{1, 2.0}, {2, 3.0}, {3, 4.0}},
+ 1}),
+ std::unordered_multimap<int, double>>);
+
+static_assert(std::is_same_v<
+ decltype(std::unordered_multimap{
+ {std::pair{1, 2.0}, {2, 3.0}, {3, 4.0}},
+ 1, SimpleAllocator<std::pair<const int, double>>{}}),
+ std::unordered_multimap<int, double, std::hash<int>,
+ std::equal_to<int>,
+ SimpleAllocator<std::pair<const int, double>>>>);
+
+static_assert(std::is_same_v<
decltype(std::unordered_multimap{{std::pair{1, 2.0},
{2, 3.0}, {3, 4.0}},
{}, std::hash<int>{}, std::equal_to<int>{}}),
@@ -107,6 +129,18 @@ void f()
static_assert(std::is_same_v<
decltype(std::unordered_multimap{x.begin(), x.end(),
+ std::allocator<std::pair<const int, double>>{}}),
+ std::unordered_multimap<int, double>>);
+
+ static_assert(std::is_same_v<
+ decltype(std::unordered_multimap{x.begin(), x.end(),
+ SimpleAllocator<std::pair<const int, double>>{}}),
+ std::unordered_multimap<int, double, std::hash<int>,
+ std::equal_to<int>,
+ SimpleAllocator<std::pair<const int, double>>>>);
+
+ static_assert(std::is_same_v<
+ decltype(std::unordered_multimap{x.begin(), x.end(),
1, std::hash<int>{},
std::allocator<std::pair<const int, double>>{}}),
std::unordered_multimap<int, double>>);
@@ -171,3 +205,72 @@ test_p1518r2()
std::unordered_multimap s2(std::move(m), p);
check_type<UMMap>(s2);
}
+
+struct MyHash
+{
+ template<typename T>
+ std::size_t operator()(T const&) const;
+};
+
+struct MyPred
+{
+ template<typename T, typename U>
+ bool operator()(T const&, U const&) const;
+};
+
+template<typename K, typename V>
+constexpr bool test_lwg4223()
+{
+ using KD = std::remove_cv_t<std::remove_reference_t<K>>;
+ using VD = std::remove_cv_t<std::remove_reference_t<V>>;
+ using Alloc = __gnu_test::SimpleAllocator<std::pair<const KD, VD>>;
+
+ std::initializer_list<std::pair<K, V>> il = {};
+ Alloc a;
+ MyHash h;
+ MyPred p;
+
+ // The remove_cvref_t is not applied here.
+ // static_assert(std::is_same_v<
+ // decltype(std::unordered_multimap(il)),
+ // std::unordered_multimap<KD, VD>>);
+
+ static_assert(std::is_same_v<
+ decltype(std::unordered_multimap(il.begin(), il.end())),
+ std::unordered_multimap<KD, VD>>);
+
+ static_assert(std::is_same_v<
+ decltype(std::unordered_multimap(il.begin(), il.end(), 0)),
+ std::unordered_multimap<KD, VD>>);
+
+ static_assert(std::is_same_v<
+ decltype(std::unordered_multimap(il.begin(), il.end(), 0, h)),
+ std::unordered_multimap<KD, VD, MyHash>>);
+
+ static_assert(std::is_same_v<
+ decltype(std::unordered_multimap(il.begin(), il.end(), 0, h, p)),
+ std::unordered_multimap<KD, VD, MyHash, MyPred>>);
+
+ static_assert(std::is_same_v<
+ decltype(std::unordered_multimap(il.begin(), il.end(), a)),
+ std::unordered_multimap<KD, VD, std::hash<KD>, std::equal_to<KD>, Alloc>>);
+
+ static_assert(std::is_same_v<
+ decltype(std::unordered_multimap(il.begin(), il.end(), 0, a)),
+ std::unordered_multimap<KD, VD, std::hash<KD>, std::equal_to<KD>, Alloc>>);
+
+ static_assert(std::is_same_v<
+ decltype(std::unordered_multimap(il.begin(), il.end(), 0, h, a)),
+ std::unordered_multimap<KD, VD, MyHash, std::equal_to<KD>, Alloc>>);
+
+ static_assert(std::is_same_v<
+ decltype(std::unordered_multimap(il.begin(), il.end(), 0, h, p, a)),
+ std::unordered_multimap<KD, VD, MyHash, MyPred, Alloc>>);
+
+ return true;
+}
+
+static_assert(test_lwg4223<const int, const float>());
+static_assert(test_lwg4223<int&, float&>());
+static_assert(test_lwg4223<int&&, float&&>());
+static_assert(test_lwg4223<const int&, const float&>());
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/from_range.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/from_range.cc
index 2ca93d3..4567bd8 100644
--- a/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/from_range.cc
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/from_range.cc
@@ -1,7 +1,12 @@
// { dg-do run { target c++23 } }
-#include <algorithm>
#include <unordered_map>
+
+#if __cpp_lib_containers_ranges != 202202L
+# error "Feature-test macro __cpp_lib_containers_ranges has wrong value in <unordered_map>"
+#endif
+
+#include <algorithm>
#include <ranges>
#include <span>
#include <testsuite_allocator.h>
@@ -81,11 +86,13 @@ test_deduction_guide()
std::unordered_multimap m9(std::from_range, r2);
static_assert(std::is_same_v<
decltype(m9),
- std::unordered_multimap<long, const float>>);
+ std::unordered_multimap<long, float>>);
- // LWG4223: deduces map<const long&, float&>
- // __gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, 0);
- // std::unordered_multimap m10(std::from_range, r3);
+ __gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, 0);
+ std::unordered_multimap m10(std::from_range, r3);
+ static_assert(std::is_same_v<
+ decltype(m10),
+ std::unordered_multimap<long, float>>);
__gnu_test::test_input_range<std::tuple<long, float>> r4(0, 0);
std::unordered_multimap m11(std::from_range, r4);
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/begin2_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/begin2_neg.cc
index ff787cf..b2d67fb 100644
--- a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/begin2_neg.cc
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/begin2_neg.cc
@@ -22,8 +22,8 @@
void test01()
{
- std::unordered_map<int, int> um;
- const std::unordered_map<int, int>& cum = um;
+ std::unordered_multimap<int, int> um;
+ const std::unordered_multimap<int, int>& cum = um;
cum.begin(um.bucket_count());
}
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/bucket_size_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/bucket_size_neg.cc
index b5ddb18..4d5cb84 100644
--- a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/bucket_size_neg.cc
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/bucket_size_neg.cc
@@ -22,7 +22,7 @@
void test01()
{
- std::unordered_map<int, int> um;
+ std::unordered_multimap<int, int> um;
um.bucket_size(um.bucket_count());
}
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/cbegin_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/cbegin_neg.cc
index 5ba1da5..654d409 100644
--- a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/cbegin_neg.cc
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/cbegin_neg.cc
@@ -22,7 +22,7 @@
void test01()
{
- std::unordered_map<int, int> um;
+ std::unordered_multimap<int, int> um;
um.cbegin(um.bucket_count());
}
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/cend_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/cend_neg.cc
index 031be37..f7149d4 100644
--- a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/cend_neg.cc
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/cend_neg.cc
@@ -22,7 +22,7 @@
void test01()
{
- std::unordered_map<int, int> um;
+ std::unordered_multimap<int, int> um;
um.cend(um.bucket_count());
}
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/end1_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/end1_neg.cc
index d412fcf..fd0f981 100644
--- a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/end1_neg.cc
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/end1_neg.cc
@@ -22,7 +22,7 @@
void test01()
{
- std::unordered_map<int, int> um;
+ std::unordered_multimap<int, int> um;
um.end(um.bucket_count());
}
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/end2_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/end2_neg.cc
index 0115351..0c3f86c 100644
--- a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/end2_neg.cc
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/end2_neg.cc
@@ -22,8 +22,8 @@
void test01()
{
- std::unordered_map<int, int> um;
- const std::unordered_map<int, int>& cum = um;
+ std::unordered_multimap<int, int> um;
+ const std::unordered_multimap<int, int>& cum = um;
cum.end(um.bucket_count());
}
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_arrow_operator_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_arrow_operator_neg.cc
new file mode 100644
index 0000000..8b23020
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_arrow_operator_neg.cc
@@ -0,0 +1,17 @@
+// { dg-do run { target c++11 xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <unordered_map>
+#include <debug/unordered_checks.h>
+
+void test01()
+{
+ __gnu_test::invalid_local_iterator_arrow_operator
+ <std::unordered_multimap<int, int>>();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_const_conversion_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_const_conversion_neg.cc
new file mode 100644
index 0000000..62c0280
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_const_conversion_neg.cc
@@ -0,0 +1,17 @@
+// { dg-do run { target c++11 xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <unordered_map>
+#include <debug/unordered_checks.h>
+
+void test01()
+{
+ __gnu_test::invalid_local_iterator_const_conversion
+ <std::unordered_multimap<int, int>>();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_copy_assignment_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_copy_assignment_neg.cc
new file mode 100644
index 0000000..9ac5b35
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_copy_assignment_neg.cc
@@ -0,0 +1,17 @@
+// { dg-do run { target c++11 xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <unordered_map>
+#include <debug/unordered_checks.h>
+
+void test01()
+{
+ __gnu_test::invalid_local_iterator_copy_assignment
+ <std::unordered_multimap<int, int>>();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_copy_construction_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_copy_construction_neg.cc
new file mode 100644
index 0000000..4140272
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_copy_construction_neg.cc
@@ -0,0 +1,17 @@
+// { dg-do run { target c++11 xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <unordered_map>
+#include <debug/unordered_checks.h>
+
+void test01()
+{
+ __gnu_test::invalid_local_iterator_copy_construction
+ <std::unordered_multimap<int, int>>();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_move_assignment_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_move_assignment_neg.cc
new file mode 100644
index 0000000..32c847c
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_move_assignment_neg.cc
@@ -0,0 +1,17 @@
+// { dg-do run { target c++11 xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <unordered_map>
+#include <debug/unordered_checks.h>
+
+void test01()
+{
+ __gnu_test::invalid_local_iterator_move_assignment
+ <std::unordered_multimap<int, int>>();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_move_construction_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_move_construction_neg.cc
new file mode 100644
index 0000000..124b9ec
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalid_local_iterator_move_construction_neg.cc
@@ -0,0 +1,17 @@
+// { dg-do run { target c++11 xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <unordered_map>
+#include <debug/unordered_checks.h>
+
+void test01()
+{
+ __gnu_test::invalid_local_iterator_move_construction
+ <std::unordered_multimap<int, int>>();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/max_load_factor_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/max_load_factor_neg.cc
index 2596798..7fbc453 100644
--- a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/max_load_factor_neg.cc
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/max_load_factor_neg.cc
@@ -22,7 +22,7 @@
void test01()
{
- std::unordered_map<int, int> um;
+ std::unordered_multimap<int, int> um;
um.max_load_factor(-1.0f);
}
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multiset/96088.cc b/libstdc++-v3/testsuite/23_containers/unordered_multiset/96088.cc
index 6f79ddf..c016c88 100644
--- a/libstdc++-v3/testsuite/23_containers/unordered_multiset/96088.cc
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multiset/96088.cc
@@ -1,6 +1,6 @@
// { dg-do run { target c++17 } }
// { dg-require-effective-target std_allocator_new }
-// { dg-xfail-run-if "AIX operator new" { powerpc-ibm-aix* } }
+// { dg-require-effective-target c++20 { target powerpc-ibm-aix* } }
// Copyright (C) 2021-2025 Free Software Foundation, Inc.
//
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/66055.cc b/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/66055.cc
index 5c34b94..3ba609f 100644
--- a/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/66055.cc
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/66055.cc
@@ -27,7 +27,9 @@ using alloc_type = test_type::allocator_type;
test_type h1(10, alloc_type());
test_type h2(10, hasher_type(), alloc_type());
-test_type h3(h1.begin(), h1.end(), 10, alloc_type());
-test_type h4(h1.begin(), h1.end(), 10, hasher_type(), alloc_type());
-test_type h5({ 1, 1 }, 10, alloc_type());
-test_type h6({ 1, 1 }, 10, hasher_type(), alloc_type());
+test_type h3(h1.begin(), h1.end(), alloc_type());
+test_type h4(h1.begin(), h1.end(), 10, alloc_type());
+test_type h5(h1.begin(), h1.end(), 10, hasher_type(), alloc_type());
+test_type h6({ 1, 1 }, alloc_type());
+test_type h7({ 1, 1 }, 10, alloc_type());
+test_type h9({ 1, 1 }, 10, hasher_type(), alloc_type());
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/deduction.cc b/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/deduction.cc
index 22b7297..46cd210 100644
--- a/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/deduction.cc
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/deduction.cc
@@ -20,6 +20,22 @@ static_assert(std::is_same_v<
std::unordered_multiset<int>>);
static_assert(std::is_same_v<
+ decltype(std::unordered_multiset{{1, 2, 3}}),
+ std::unordered_multiset<int>>);
+
+static_assert(std::is_same_v<
+ decltype(std::unordered_multiset{{1, 2, 3},
+ std::allocator<int>{}}),
+ std::unordered_multiset<int>>);
+
+static_assert(std::is_same_v<
+ decltype(std::unordered_multiset{{1, 2, 3},
+ SimpleAllocator<int>{}}),
+ std::unordered_multiset<int, std::hash<int>,
+ std::equal_to<int>,
+ SimpleAllocator<int>>>);
+
+static_assert(std::is_same_v<
decltype(std::unordered_multiset{{1, 2, 3},
{}}),
std::unordered_multiset<int>>);
@@ -88,6 +104,18 @@ void f()
static_assert(std::is_same_v<
decltype(std::unordered_multiset{x.begin(), x.end(),
+ std::allocator<int>{}}),
+ std::unordered_multiset<int>>);
+
+ static_assert(std::is_same_v<
+ decltype(std::unordered_multiset{x.begin(), x.end(),
+ SimpleAllocator<int>{}}),
+ std::unordered_multiset<int, std::hash<int>,
+ std::equal_to<int>,
+ SimpleAllocator<int>>>);
+
+ static_assert(std::is_same_v<
+ decltype(std::unordered_multiset{x.begin(), x.end(),
{}, std::hash<int>{}, std::allocator<int>{}}),
std::unordered_multiset<int>>);
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/from_range.cc b/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/from_range.cc
index 45c3848..d44598d 100644
--- a/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/from_range.cc
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/from_range.cc
@@ -1,7 +1,12 @@
// { dg-do run { target c++23 } }
-#include <algorithm>
#include <unordered_set>
+
+#if __cpp_lib_containers_ranges != 202202L
+# error "Feature-test macro __cpp_lib_containers_ranges has wrong value in <unordered_set>"
+#endif
+
+#include <algorithm>
#include <ranges>
#include <span>
#include <testsuite_allocator.h>
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_arrow_operator_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_arrow_operator_neg.cc
new file mode 100644
index 0000000..1677b20
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_arrow_operator_neg.cc
@@ -0,0 +1,17 @@
+// { dg-do run { target c++11 xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <unordered_set>
+#include <debug/unordered_checks.h>
+
+void test01()
+{
+ __gnu_test::invalid_local_iterator_arrow_operator
+ <std::unordered_multiset<int>>();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_const_conversion_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_const_conversion_neg.cc
new file mode 100644
index 0000000..0d64a41
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_const_conversion_neg.cc
@@ -0,0 +1,17 @@
+// { dg-do run { target c++11 xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <unordered_set>
+#include <debug/unordered_checks.h>
+
+void test01()
+{
+ __gnu_test::invalid_local_iterator_const_conversion
+ <std::unordered_multiset<int>>();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_copy_assignment_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_copy_assignment_neg.cc
new file mode 100644
index 0000000..b0d7b9f
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_copy_assignment_neg.cc
@@ -0,0 +1,17 @@
+// { dg-do run { target c++11 xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <unordered_set>
+#include <debug/unordered_checks.h>
+
+void test01()
+{
+ __gnu_test::invalid_local_iterator_copy_assignment
+ <std::unordered_multiset<int>>();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_copy_construction_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_copy_construction_neg.cc
new file mode 100644
index 0000000..fa9c5ee
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_copy_construction_neg.cc
@@ -0,0 +1,17 @@
+// { dg-do run { target c++11 xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <unordered_set>
+#include <debug/unordered_checks.h>
+
+void test01()
+{
+ __gnu_test::invalid_local_iterator_copy_construction
+ <std::unordered_multiset<int>>();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_move_assignment_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_move_assignment_neg.cc
new file mode 100644
index 0000000..b25fedc
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_move_assignment_neg.cc
@@ -0,0 +1,17 @@
+// { dg-do run { target c++11 xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <unordered_set>
+#include <debug/unordered_checks.h>
+
+void test01()
+{
+ __gnu_test::invalid_local_iterator_move_assignment
+ <std::unordered_multiset<int>>();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_move_construction_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_move_construction_neg.cc
new file mode 100644
index 0000000..8b855b2
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalid_local_iterator_move_construction_neg.cc
@@ -0,0 +1,17 @@
+// { dg-do run { target c++11 xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <unordered_set>
+#include <debug/unordered_checks.h>
+
+void test01()
+{
+ __gnu_test::invalid_local_iterator_move_construction
+ <std::unordered_multiset<int>>();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/96088.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/96088.cc
index c09e6f7..10838c4 100644
--- a/libstdc++-v3/testsuite/23_containers/unordered_set/96088.cc
+++ b/libstdc++-v3/testsuite/23_containers/unordered_set/96088.cc
@@ -1,6 +1,6 @@
// { dg-do run { target c++17 } }
// { dg-require-effective-target std_allocator_new }
-// { dg-xfail-run-if "AIX operator new" { powerpc-ibm-aix* } }
+// { dg-require-effective-target c++20 { target powerpc-ibm-aix* } }
// Copyright (C) 2021-2025 Free Software Foundation, Inc.
//
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/cons/66055.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/cons/66055.cc
index 0d318a0..96c0ca3 100644
--- a/libstdc++-v3/testsuite/23_containers/unordered_set/cons/66055.cc
+++ b/libstdc++-v3/testsuite/23_containers/unordered_set/cons/66055.cc
@@ -27,7 +27,9 @@ using alloc_type = test_type::allocator_type;
test_type h1(10, alloc_type());
test_type h2(10, hasher_type(), alloc_type());
-test_type h3(h1.begin(), h1.end(), 10, alloc_type());
-test_type h4(h1.begin(), h1.end(), 10, hasher_type(), alloc_type());
-test_type h5({ 1, 1 }, 10, alloc_type());
-test_type h6({ 1, 1 }, 10, hasher_type(), alloc_type());
+test_type h3(h1.begin(), h1.end(), alloc_type());
+test_type h4(h1.begin(), h1.end(), 10, alloc_type());
+test_type h5(h1.begin(), h1.end(), 10, hasher_type(), alloc_type());
+test_type h6({ 1, 1 }, alloc_type());
+test_type h7({ 1, 1 }, 10, alloc_type());
+test_type h9({ 1, 1 }, 10, hasher_type(), alloc_type());
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/cons/deduction.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/cons/deduction.cc
index db58581..9558d70 100644
--- a/libstdc++-v3/testsuite/23_containers/unordered_set/cons/deduction.cc
+++ b/libstdc++-v3/testsuite/23_containers/unordered_set/cons/deduction.cc
@@ -20,6 +20,22 @@ static_assert(std::is_same_v<
std::unordered_set<int>>);
static_assert(std::is_same_v<
+ decltype(std::unordered_set{{1, 2, 3}}),
+ std::unordered_set<int>>);
+
+static_assert(std::is_same_v<
+ decltype(std::unordered_set{{1, 2, 3},
+ std::allocator<int>{}}),
+ std::unordered_set<int>>);
+
+static_assert(std::is_same_v<
+ decltype(std::unordered_set{{1, 2, 3},
+ SimpleAllocator<int>{}}),
+ std::unordered_set<int, std::hash<int>,
+ std::equal_to<int>,
+ SimpleAllocator<int>>>);
+
+static_assert(std::is_same_v<
decltype(std::unordered_set{{1, 2, 3},
{}}),
std::unordered_set<int>>);
@@ -92,6 +108,18 @@ void f()
std::unordered_set<int>>);
static_assert(std::is_same_v<
+ decltype(std::unordered_set{x.begin(), x.end(),
+ std::allocator<int>{}}),
+ std::unordered_set<int>>);
+
+ static_assert(std::is_same_v<
+ decltype(std::unordered_set{x.begin(), x.end(),
+ SimpleAllocator<int>{}}),
+ std::unordered_set<int, std::hash<int>,
+ std::equal_to<int>,
+ SimpleAllocator<int>>>);
+
+ static_assert(std::is_same_v<
decltype(std::unordered_set{x.begin(), x.end(), 1}),
std::unordered_set<int>>);
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/cons/from_range.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/cons/from_range.cc
index 0806045..8259be8 100644
--- a/libstdc++-v3/testsuite/23_containers/unordered_set/cons/from_range.cc
+++ b/libstdc++-v3/testsuite/23_containers/unordered_set/cons/from_range.cc
@@ -1,7 +1,12 @@
// { dg-do run { target c++23 } }
-#include <algorithm>
#include <unordered_set>
+
+#if __cpp_lib_containers_ranges != 202202L
+# error "Feature-test macro __cpp_lib_containers_ranges has wrong value in <unordered_set>"
+#endif
+
+#include <algorithm>
#include <span>
#include <testsuite_allocator.h>
#include <testsuite_hooks.h>
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_arrow_operator_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_arrow_operator_neg.cc
new file mode 100644
index 0000000..f62ed6b
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_arrow_operator_neg.cc
@@ -0,0 +1,17 @@
+// { dg-do run { target c++11 xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <unordered_set>
+#include <debug/unordered_checks.h>
+
+void test01()
+{
+ __gnu_test::invalid_local_iterator_arrow_operator
+ <std::unordered_set<int>>();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_const_conversion_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_const_conversion_neg.cc
new file mode 100644
index 0000000..839f9ae
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_const_conversion_neg.cc
@@ -0,0 +1,17 @@
+// { dg-do run { target c++11 xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <unordered_set>
+#include <debug/unordered_checks.h>
+
+void test01()
+{
+ __gnu_test::invalid_local_iterator_const_conversion
+ <std::unordered_set<int>>();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_copy_assignment_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_copy_assignment_neg.cc
new file mode 100644
index 0000000..377019f
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_copy_assignment_neg.cc
@@ -0,0 +1,17 @@
+// { dg-do run { target c++11 xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <unordered_set>
+#include <debug/unordered_checks.h>
+
+void test01()
+{
+ __gnu_test::invalid_local_iterator_copy_assignment
+ <std::unordered_set<int>>();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_copy_construction_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_copy_construction_neg.cc
new file mode 100644
index 0000000..1f7e6dd
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_copy_construction_neg.cc
@@ -0,0 +1,17 @@
+// { dg-do run { target c++11 xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <unordered_set>
+#include <debug/unordered_checks.h>
+
+void test01()
+{
+ __gnu_test::invalid_local_iterator_copy_construction
+ <std::unordered_set<int>>();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_move_assignment_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_move_assignment_neg.cc
new file mode 100644
index 0000000..d16a154
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_move_assignment_neg.cc
@@ -0,0 +1,17 @@
+// { dg-do run { target c++11 xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <unordered_set>
+#include <debug/unordered_checks.h>
+
+void test01()
+{
+ __gnu_test::invalid_local_iterator_move_assignment
+ <std::unordered_set<int>>();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_move_construction_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_move_construction_neg.cc
new file mode 100644
index 0000000..d878abf
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalid_local_iterator_move_construction_neg.cc
@@ -0,0 +1,17 @@
+// { dg-do run { target c++11 xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <unordered_set>
+#include <debug/unordered_checks.h>
+
+void test01()
+{
+ __gnu_test::invalid_local_iterator_move_construction
+ <std::unordered_set<int>>();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/vector/allocator/default_init.cc b/libstdc++-v3/testsuite/23_containers/vector/allocator/default_init.cc
index 195cd2d..486c44c 100644
--- a/libstdc++-v3/testsuite/23_containers/vector/allocator/default_init.cc
+++ b/libstdc++-v3/testsuite/23_containers/vector/allocator/default_init.cc
@@ -59,6 +59,17 @@ void test02()
tmp->~test_type();
}
+#ifdef __cpp_lib_constexpr_vector
+constexpr bool
+test03()
+{
+ using alloc_type = default_init_allocator<T>;
+ std::vector<T, alloc_type> v;
+ return v.get_allocator().state == 0;
+}
+static_assert( test03() );
+#endif
+
int main()
{
test01();
diff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/allocator/default_init.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/allocator/default_init.cc
index 3914b7f..c95cb6b 100644
--- a/libstdc++-v3/testsuite/23_containers/vector/bool/allocator/default_init.cc
+++ b/libstdc++-v3/testsuite/23_containers/vector/bool/allocator/default_init.cc
@@ -59,6 +59,17 @@ void test02()
tmp->~test_type();
}
+#ifdef __cpp_lib_constexpr_vector
+constexpr bool
+test03()
+{
+ using alloc_type = default_init_allocator<T>;
+ std::vector<T, alloc_type> v;
+ return v.get_allocator().state == 0;
+}
+static_assert( test03() );
+#endif
+
int main()
{
test01();
diff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/cons/from_range.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/cons/from_range.cc
index 37f0ecf..339c06bd 100644
--- a/libstdc++-v3/testsuite/23_containers/vector/bool/cons/from_range.cc
+++ b/libstdc++-v3/testsuite/23_containers/vector/bool/cons/from_range.cc
@@ -1,5 +1,11 @@
// { dg-do run { target c++23 } }
+#include <unordered_set>
+
+#if __cpp_lib_containers_ranges != 202202L
+# error "Feature-test macro __cpp_lib_containers_ranges has wrong value in <unordered_set>"
+#endif
+
#include <vector>
#include <span>
#include <testsuite_hooks.h>
diff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/format.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/format.cc
new file mode 100644
index 0000000..cecc535
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/vector/bool/format.cc
@@ -0,0 +1,72 @@
+// { dg-do run { target c++23 } }
+// { dg-timeout-factor 2 }
+
+#include <format>
+#include <vector>
+#include <testsuite_hooks.h>
+
+static_assert(!std::formattable<std::vector<bool>::reference, int>);
+static_assert(!std::formattable<std::vector<bool>::reference, char32_t>);
+
+template<typename... Args>
+bool
+is_format_string_for(const char* str, Args&&... args)
+{
+ try {
+ (void) std::vformat(str, std::make_format_args(args...));
+ return true;
+ } catch (const std::format_error&) {
+ return false;
+ }
+}
+
+#define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S)
+#define WIDEN(S) WIDEN_(CharT, S)
+
+void
+test_format_string()
+{
+ std::vector<bool> v(1, true);
+ VERIFY( !is_format_string_for("{:?}", v[0]) );
+ VERIFY( !is_format_string_for("{:P}", v[0]) );
+
+ // width needs to be integer type
+ VERIFY( !is_format_string_for("{:{}}", v[0], 1.0f) );
+}
+
+template<typename CharT>
+void
+test_output()
+{
+ std::basic_string<CharT> res;
+ size_t size = 0;
+ std::vector<bool> v{true, false};
+
+ res = std::format(WIDEN("{}"), v[0]);
+ VERIFY( res == WIDEN("true") );
+
+ res = std::format(WIDEN("{:s}"), v[1]);
+ VERIFY( res == WIDEN("false") );
+
+ res = std::format(WIDEN("{:d} {:#B} {:#o} {:#x}"), v[0], v[1], v[0], v[1]);
+ VERIFY( res == WIDEN("1 0B0 01 0x0") );
+
+ res = std::format(WIDEN("{:{}}"), v[0], 6);
+ VERIFY( res == WIDEN("true ") );
+
+ res = std::format(WIDEN("{:=^#7X}"), v[1]);
+ VERIFY( res == WIDEN("==0X0==") );
+
+ res = std::format(WIDEN("{}"), v);
+ VERIFY( res == WIDEN("[true, false]") );
+
+ res = std::format(WIDEN("{::d}"), v);
+ VERIFY( res == WIDEN("[1, 0]") );
+}
+
+int main()
+{
+ test_format_string();
+ test_output<char>();
+ test_output<wchar_t>();
+}
diff --git a/libstdc++-v3/testsuite/23_containers/vector/capacity/114945.cc b/libstdc++-v3/testsuite/23_containers/vector/capacity/114945.cc
new file mode 100644
index 0000000..daafc59
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/vector/capacity/114945.cc
@@ -0,0 +1,36 @@
+// { dg-options "-O2 -Werror=stringop-overflow -Werror=array-bounds" }
+// { dg-do compile { target c++11 } }
+
+// Bug libstdc++/114945
+// Sporadic std::vector::resize() -Wstringop-overflow or -Warray-bounds warning
+
+#include <stdint.h>
+#include <vector>
+template <typename a> struct b {
+ void resize(std::size_t c) { d.resize(c); }
+ template <typename e> void f(a, e);
+ std::vector<char> d;
+};
+#include <regex>
+std::regex g;
+uint64_t h;
+uint32_t i;
+struct s {
+ enum class j : size_t;
+ void k();
+ using l = b<j>;
+ std::vector<l> m;
+};
+enum class s::j : size_t { n };
+void o() { g = ""; }
+void s::k() {
+ l p;
+ auto q = uint32_t(), r = uint32_t();
+ if (h)
+ r = i;
+ b<size_t> t;
+ if (q || r)
+ p.f(j::n, 5);
+ t.resize(4);
+ m.push_back(p);
+}
diff --git a/libstdc++-v3/testsuite/23_containers/vector/cons/destructible_debug_neg.cc b/libstdc++-v3/testsuite/23_containers/vector/cons/destructible_debug_neg.cc
index 61b99d3..e6689f7 100644
--- a/libstdc++-v3/testsuite/23_containers/vector/cons/destructible_debug_neg.cc
+++ b/libstdc++-v3/testsuite/23_containers/vector/cons/destructible_debug_neg.cc
@@ -43,11 +43,8 @@ test02()
std::vector<PrivateDtor> v;
}
-// { dg-error "value type is destructible" "" { target *-*-* } 0 }
+// { dg-error "deleted function .*DeletedDtor" "" { target *-*-* } 0 }
+// { dg-error "PrivateDtor.* is private" "" { target *-*-* } 0 }
// In Debug Mode the "required from here" errors come from <debug/vector>
// { dg-error "required from here" "" { target *-*-* } 182 }
-
-// Needed because of PR c++/92193
-// { dg-prune-output "deleted function" }
-// { dg-prune-output "private within this context" }
diff --git a/libstdc++-v3/testsuite/23_containers/vector/cons/destructible_neg.cc b/libstdc++-v3/testsuite/23_containers/vector/cons/destructible_neg.cc
index 0807d15..2bd15bc 100644
--- a/libstdc++-v3/testsuite/23_containers/vector/cons/destructible_neg.cc
+++ b/libstdc++-v3/testsuite/23_containers/vector/cons/destructible_neg.cc
@@ -42,8 +42,5 @@ test02()
std::vector<PrivateDtor> v; // { dg-error "here" }
}
-// { dg-error "value type is destructible" "" { target *-*-* } 0 }
-
-// Needed because of PR c++/92193
-// { dg-prune-output "deleted function" }
-// { dg-prune-output "private within this context" }
+// { dg-error "deleted function .*DeletedDtor" "" { target *-*-* } 0 }
+// { dg-error "PrivateDtor.* is private" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/23_containers/vector/cons/from_range.cc b/libstdc++-v3/testsuite/23_containers/vector/cons/from_range.cc
index ed2e3ca..3784b9c 100644
--- a/libstdc++-v3/testsuite/23_containers/vector/cons/from_range.cc
+++ b/libstdc++-v3/testsuite/23_containers/vector/cons/from_range.cc
@@ -1,6 +1,11 @@
// { dg-do run { target c++23 } }
#include <vector>
+
+#if __cpp_lib_containers_ranges != 202202L
+# error "Feature-test macro __cpp_lib_containers_ranges has wrong value in <vector>"
+#endif
+
#include <span>
#include <testsuite_hooks.h>
#include <testsuite_iterators.h>
@@ -101,8 +106,30 @@ test_constexpr()
return true;
}
+void
+test_pr120367()
+{
+#ifdef __cpp_exceptions
+ struct X
+ {
+ X(int) { throw 1; } // Cannot successfully construct an X.
+ ~X() { VERIFY(false); } // So should never need to destroy one.
+ };
+
+ try
+ {
+ int i[1]{};
+ std::vector<X> v(std::from_range, i);
+ }
+ catch (int)
+ {
+ }
+#endif
+}
+
int main()
{
test_ranges();
static_assert( test_constexpr() );
+ test_pr120367();
}
diff --git a/libstdc++-v3/testsuite/24_iterators/indirect_callable/projected.cc b/libstdc++-v3/testsuite/24_iterators/indirect_callable/projected.cc
index 0b18616..e2fbf7d 100644
--- a/libstdc++-v3/testsuite/24_iterators/indirect_callable/projected.cc
+++ b/libstdc++-v3/testsuite/24_iterators/indirect_callable/projected.cc
@@ -22,12 +22,7 @@
template<typename T>
using PI = std::projected<T, std::identity>;
-#if __GLIBCXX__
-// Verify our projected<I, identity> optimization.
-static_assert(std::same_as<PI<int*>, int*>);
-#else
static_assert(std::same_as<PI<int*>::value_type, int>);
-#endif
static_assert(std::same_as<decltype(*std::declval<const PI<int*>&>()), int&>);
struct X
diff --git a/libstdc++-v3/testsuite/24_iterators/operations/prev_neg.cc b/libstdc++-v3/testsuite/24_iterators/operations/prev_neg.cc
index f9de894..5fdfa9e 100644
--- a/libstdc++-v3/testsuite/24_iterators/operations/prev_neg.cc
+++ b/libstdc++-v3/testsuite/24_iterators/operations/prev_neg.cc
@@ -38,5 +38,5 @@ test02()
{
const Y array[1] = { };
(void) std::prev(array + 1);
- // { dg-error "forward_iterator" "" { target *-*-* } 241 }
+ // { dg-error "forward_iterator" "" { target *-*-* } 242 }
}
diff --git a/libstdc++-v3/testsuite/24_iterators/range_generators/lwg3899.cc b/libstdc++-v3/testsuite/24_iterators/range_generators/lwg3899.cc
new file mode 100644
index 0000000..5a812ec
--- /dev/null
+++ b/libstdc++-v3/testsuite/24_iterators/range_generators/lwg3899.cc
@@ -0,0 +1,57 @@
+// { dg-do run { target c++23 } }
+
+// LWG 3899.
+// co_yielding elements of an lvalue generator is unnecessarily inefficient
+
+#include <generator>
+#include <memory_resource>
+#include <testsuite_hooks.h>
+
+struct memory_resource : std::pmr::memory_resource
+{
+ std::size_t count = 0;
+
+ void* do_allocate(std::size_t n, std::size_t a) override
+ {
+ count += n;
+ return std::pmr::new_delete_resource()->allocate(n, a);
+ }
+
+ void do_deallocate(void* p, std::size_t n, std::size_t a) override
+ {
+ return std::pmr::new_delete_resource()->deallocate(p, n, a);
+ }
+
+ bool do_is_equal(const std::pmr::memory_resource& mr) const noexcept override
+ { return this == &mr; }
+};
+
+std::pmr::generator<int>
+f(std::allocator_arg_t, std::pmr::polymorphic_allocator<>, int init)
+{
+ co_yield init + 0;
+ co_yield init + 1;
+}
+
+std::pmr::generator<int>
+g(std::allocator_arg_t, std::pmr::polymorphic_allocator<> alloc)
+{
+ auto gen = f(std::allocator_arg, alloc, 0);
+ auto gen2 = f(std::allocator_arg, alloc, 2);
+ co_yield std::ranges::elements_of(std::move(gen), alloc);
+ co_yield std::ranges::elements_of(gen2, alloc);
+}
+
+int
+main()
+{
+ std::size_t counts[4];
+ memory_resource mr;
+ for (auto d : g(std::allocator_arg , &mr))
+ counts[d] = mr.count;
+ VERIFY(counts[0] != 0);
+ // No allocations after the first one:
+ VERIFY(counts[1] == counts[0]);
+ VERIFY(counts[2] == counts[0]);
+ VERIFY(counts[3] == counts[0]);
+}
diff --git a/libstdc++-v3/testsuite/25_algorithms/ends_with/1.cc b/libstdc++-v3/testsuite/25_algorithms/ends_with/1.cc
new file mode 100644
index 0000000..612c27a
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/ends_with/1.cc
@@ -0,0 +1,165 @@
+// { dg-do run { target c++23 } }
+
+#include <algorithm>
+#include <ranges>
+
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+namespace ranges = std::ranges;
+
+template<typename Range1, typename Range2>
+void
+test01()
+{
+ int n[] = {1,2,3,4,5,6,7,8,9,10};
+
+ Range1 haystack(n, n+10);
+ Range2 needle(n+7, n+10);
+ VERIFY( ranges::ends_with(haystack, needle) );
+
+ haystack = Range1(n);
+ needle = Range2(n, n+10);
+ VERIFY( ranges::ends_with(haystack, needle) );
+
+ haystack = Range1(n);
+ needle = Range2(n+6, n+9);
+ VERIFY( !ranges::ends_with(haystack, needle) );
+
+ haystack = Range1(n);
+ needle = Range2(n+6, n+9);
+ VERIFY( ranges::ends_with(haystack, needle,
+ [](int n, int m) { return std::abs(n - m) <= 1; }) );
+
+ haystack = Range1(n);
+ needle = Range2(n+6, n+9);
+ VERIFY( ranges::ends_with(haystack, needle,
+ ranges::equal_to{},
+ [](int n) { return n - 1; }) );
+
+ haystack = Range1(n);
+ needle = Range2(n+6, n+9);
+ VERIFY( ranges::ends_with(haystack, needle,
+ ranges::equal_to{},
+ std::identity{},
+ [](int n) { return n + 1; }) );
+
+ haystack = Range1(n, n+5);
+ needle = Range2(n, n+10);
+ VERIFY( !ranges::ends_with(haystack, needle) );
+}
+
+template<typename Range1, typename Range2>
+void
+test02()
+{
+ int n[] = {1,2,3,4,5,6,7,8,9,10};
+
+ Range1 haystack(n, n+10);
+ Range2 needle(n+7, n+10);
+ VERIFY( ranges::ends_with(haystack.begin(), haystack.end(),
+ needle.begin(), needle.end()) );
+
+ haystack = Range1(n);
+ needle = Range2(n, n+10);
+ VERIFY( ranges::ends_with(haystack.begin(), haystack.end(),
+ needle.begin(), needle.end()) );
+
+ haystack = Range1(n);
+ needle = Range2(n+6, n+9);
+ VERIFY( !ranges::ends_with(haystack.begin(), haystack.end(),
+ needle.begin(), needle.end()) );
+
+ haystack = Range1(n);
+ needle = Range2(n+6, n+9);
+ VERIFY( ranges::ends_with(haystack.begin(), haystack.end(),
+ needle.begin(), needle.end(),
+ [](int n, int m) { return std::abs(n - m) <= 1; }) );
+
+ haystack = Range1(n);
+ needle = Range2(n+6, n+9);
+ VERIFY( ranges::ends_with(haystack.begin(), haystack.end(),
+ needle.begin(), needle.end(),
+ ranges::equal_to{},
+ [](int n) { return n - 1; }) );
+
+ haystack = Range1(n);
+ needle = Range2(n+6, n+9);
+ VERIFY( ranges::ends_with(haystack.begin(), haystack.end(),
+ needle.begin(), needle.end(),
+ ranges::equal_to{},
+ std::identity{},
+ [](int n) { return n + 1; }) );
+
+ haystack = Range1(n, n+5);
+ needle = Range2(n, n+10);
+ VERIFY( !ranges::ends_with(haystack.begin(), haystack.end(),
+ needle.begin(), needle.end()) );
+
+ haystack = Range1(n, n+5);
+ needle = Range2(n+10, n+10);
+ VERIFY( ranges::ends_with(haystack.begin(), haystack.end(),
+ needle.begin(), needle.end()) );
+}
+
+void
+test03()
+{
+ auto haystack = std::views::iota(0, 10);
+ auto needle = std::views::iota(5, 10);
+
+#if __SIZEOF_INT128__
+ auto haystack_ict = std::views::iota(__int128(0), __int128(10));
+ auto needle_ict = std::views::iota(__int128(5), __int128(10));
+#else
+ auto haystack_ict = std::views::iota(0ll, 10ll);
+ auto needle_ict = std::views::iota(5ll, 10ll);
+#endif
+
+ VERIFY( ranges::ends_with(haystack, needle_ict) );
+ VERIFY( ranges::ends_with(haystack.begin(), haystack.end(),
+ needle_ict.begin(), needle_ict.end()) );
+
+ VERIFY( ranges::ends_with(haystack_ict, needle) );
+ VERIFY( ranges::ends_with(haystack_ict.begin(), haystack_ict.end(),
+ needle.begin(), needle.end()) );
+
+ VERIFY( ranges::ends_with(haystack_ict, needle_ict) );
+ VERIFY( ranges::ends_with(haystack_ict.begin(), haystack_ict.end(),
+ needle_ict.begin(), needle_ict.end()) );
+}
+
+int
+main()
+{
+ using namespace __gnu_test;
+ using forward = test_forward_range<int>;
+ using bidirectional_common = bidirectional_container<int>;
+ using input_sized = test_input_sized_range<int>;
+ using input_sized_sent = test_sized_range_sized_sent<int, input_iterator_wrapper>;
+ using random_access = test_random_access_range<int>;
+ using random_access_sized = test_random_access_sized_range<int>;
+ using random_access_sized_sent = test_sized_range_sized_sent<int, random_access_iterator_wrapper>;
+
+ test01<forward, forward>();
+ test01<random_access, random_access>();
+ test02<forward, forward>();
+ test02<random_access, random_access>();
+
+ test01<bidirectional_common, bidirectional_common>();
+ test02<bidirectional_common, bidirectional_common>();
+ test01<bidirectional_common, forward>();
+ test02<bidirectional_common, forward>();
+
+ test01<input_sized, input_sized>();
+ test01<random_access_sized, random_access_sized>();
+ // test02<input_sized, input_sized>(); constraint violation
+ test02<random_access_sized, random_access_sized>();
+
+ test01<input_sized_sent, input_sized_sent>();
+ test01<random_access_sized_sent, random_access_sized_sent>();
+ test02<input_sized_sent, input_sized_sent>();
+ test02<random_access_sized_sent, random_access_sized_sent>();
+
+ test03();
+}
diff --git a/libstdc++-v3/testsuite/25_algorithms/heap/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/heap/constrained.cc
index 8037a2d..5486c85 100644
--- a/libstdc++-v3/testsuite/25_algorithms/heap/constrained.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/heap/constrained.cc
@@ -20,6 +20,7 @@
#include <algorithm>
#include <random>
+#include <ranges>
#include <testsuite_hooks.h>
#include <testsuite_iterators.h>
@@ -97,10 +98,55 @@ test02()
return ok;
}
+constexpr bool
+test03()
+{
+ // PR libstdc++/100795 - ranges::heap algos should not use std::heap directly
+#if __SIZEOF_INT128__
+ auto v = std::views::iota(__int128(0), __int128(20));
+#else
+ auto v = std::views::iota(0ll, 20ll);
+#endif
+
+ int storage[20] = {2,5,4,3,1,6,7,9,10,8,11,14,12,13,15,16,18,0,19,17};
+ auto w = v | std::views::transform([&](auto i) -> int& { return storage[i]; });
+ using type = decltype(w);
+ using cat = std::iterator_traits<std::ranges::iterator_t<type>>::iterator_category;
+ static_assert( std::same_as<cat, std::output_iterator_tag> );
+ static_assert( std::ranges::random_access_range<type> );
+
+ for (int i = 1; i < 20; i++)
+ ranges::push_heap(w.begin(), w.begin() + i);
+ ranges::sort_heap(w);
+ VERIFY( ranges::equal(w, v) );
+ ranges::make_heap(w);
+ auto it = ranges::pop_heap(w);
+ VERIFY( it[-1] == 19 );
+
+ for (int i = 1; i < 20; i++)
+ ranges::push_heap(w.begin(), w.begin() + i, std::ranges::greater{});
+ ranges::sort_heap(w, std::ranges::greater{});
+ VERIFY( ranges::equal(w, v | std::views::reverse) );
+ ranges::make_heap(w, std::ranges::greater{});
+ it = ranges::pop_heap(w, std::ranges::greater{});
+ VERIFY( it[-1] == 0 );
+
+ for (int i = 1; i < 20; i++)
+ ranges::push_heap(w.begin(), w.begin() + i, std::ranges::greater{}, std::negate{});
+ ranges::sort_heap(w, std::ranges::greater{}, std::negate{});
+ VERIFY( ranges::equal(w, v) );
+ ranges::make_heap(w, std::ranges::greater{}, std::negate{});
+ it = ranges::pop_heap(w, std::ranges::greater{}, std::negate{});
+ VERIFY( it[-1] == 19 );
+
+ return true;
+}
+
int
main()
{
test01<test_range>();
test01<test_container>();
static_assert(test02());
+ static_assert(test03());
}
diff --git a/libstdc++-v3/testsuite/25_algorithms/inplace_merge/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/inplace_merge/constrained.cc
index b569c91..5634588 100644
--- a/libstdc++-v3/testsuite/25_algorithms/inplace_merge/constrained.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/inplace_merge/constrained.cc
@@ -18,6 +18,7 @@
// { dg-do run { target c++20 } }
#include <algorithm>
+#include <ranges>
#include <vector>
#include <testsuite_hooks.h>
#include <testsuite_iterators.h>
@@ -60,9 +61,44 @@ test02()
}
+void
+test03()
+{
+ // PR libstdc++/100795 - ranges::inplace_merge should not use
+ // std::inplace_merge directly
+#if __SIZEOF_INT128__
+ auto v = std::views::iota(__int128(0), __int128(20));
+#else
+ auto v = std::views::iota(0ll, 20ll);
+#endif
+
+ int storage[20] = {2,5,4,3,1,6,7,9,10,8,11,14,12,13,15,16,18,0,19,17};
+ auto w = v | std::views::transform([&](auto i) -> int& { return storage[i]; });
+ using type = decltype(w);
+ using cat = std::iterator_traits<std::ranges::iterator_t<type>>::iterator_category;
+ static_assert( std::same_as<cat, std::output_iterator_tag> );
+ static_assert( std::ranges::random_access_range<type> );
+
+ ranges::sort(w | std::views::take(10));
+ ranges::sort(w | std::views::drop(10));
+ ranges::inplace_merge(w, w.begin() + 10);
+ VERIFY( ranges::equal(w, v) );
+
+ ranges::sort(w | std::views::take(10), std::ranges::greater{});
+ ranges::sort(w | std::views::drop(10), std::ranges::greater{});
+ ranges::inplace_merge(w, w.begin() + 10, std::ranges::greater{});
+ VERIFY( ranges::equal(w, v | std::views::reverse) );
+
+ ranges::sort(w | std::views::take(10), std::ranges::greater{}, std::negate{});
+ ranges::sort(w | std::views::drop(10), std::ranges::greater{}, std::negate{});
+ ranges::inplace_merge(w, w.begin() + 10, std::ranges::greater{}, std::negate{});
+ VERIFY( ranges::equal(w, v) );
+}
+
int
main()
{
test01();
test02();
+ test03();
}
diff --git a/libstdc++-v3/testsuite/25_algorithms/nth_element/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/nth_element/constrained.cc
index 3189b22..8cb1625 100644
--- a/libstdc++-v3/testsuite/25_algorithms/nth_element/constrained.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/nth_element/constrained.cc
@@ -20,6 +20,7 @@
#include <algorithm>
#include <random>
+#include <ranges>
#include <testsuite_hooks.h>
#include <testsuite_iterators.h>
@@ -67,9 +68,39 @@ test02()
return x[3] == 4;
}
+constexpr bool
+test03()
+{
+ // PR libstdc++/100795 - ranges::sort should not use std::sort directly
+#if __SIZEOF_INT128__
+ auto v = std::views::iota(__int128(0), __int128(20));
+#else
+ auto v = std::views::iota(0ll, 20ll);
+#endif
+
+ int storage[20] = {2,5,4,3,1,6,7,9,10,8,11,14,12,13,15,16,18,0,19,17};
+ auto w = v | std::views::transform([&](auto i) -> int& { return storage[i]; });
+ using type = decltype(w);
+ using cat = std::iterator_traits<std::ranges::iterator_t<type>>::iterator_category;
+ static_assert( std::same_as<cat, std::output_iterator_tag> );
+ static_assert( std::ranges::random_access_range<type> );
+
+ ranges::nth_element(w, w.begin() + 10);
+ VERIFY( w[10] == 10 );
+
+ ranges::nth_element(w, w.begin() + 5, std::ranges::greater{});
+ VERIFY( w[5] == 19 - 5 );
+
+ ranges::nth_element(w, w.begin() + 15, std::ranges::greater{}, std::negate{});
+ VERIFY( w[15] == 15 );
+
+ return true;
+}
+
int
main()
{
test01();
static_assert(test02());
+ static_assert(test03());
}
diff --git a/libstdc++-v3/testsuite/25_algorithms/remove_if/120789.cc b/libstdc++-v3/testsuite/25_algorithms/remove_if/120789.cc
new file mode 100644
index 0000000..c1f4eeb
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/remove_if/120789.cc
@@ -0,0 +1,36 @@
+// PR libstdc++/120789 - ranges::remove_if should use ranges::iter_move
+// { dg-do compile { target c++20 } }
+
+#include <algorithm>
+
+struct A
+{
+ bool operator==(const A&) const;
+};
+
+struct B
+{
+ B(B&&) = delete;
+ B& operator=(const A&) const;
+
+ operator A() const;
+ bool operator==(const B&) const;
+};
+
+struct I
+{
+ using value_type = A;
+ using difference_type = int;
+ B operator*() const;
+ I& operator++();
+ I operator++(int);
+ bool operator==(const I&) const;
+ friend A iter_move(const I&);
+};
+
+void
+test01()
+{
+ std::ranges::subrange<I, I> r;
+ auto [begin, end] = std::ranges::remove_if(r, [](auto&&) { return true; });
+}
diff --git a/libstdc++-v3/testsuite/25_algorithms/sample/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/sample/constrained.cc
index b9945b1..0ec3e0b 100644
--- a/libstdc++-v3/testsuite/25_algorithms/sample/constrained.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/sample/constrained.cc
@@ -20,6 +20,7 @@
#include <algorithm>
#include <random>
+#include <ranges>
#include <testsuite_hooks.h>
#include <testsuite_iterators.h>
@@ -59,9 +60,34 @@ test01()
}
}
+void
+test02()
+{
+ // PR libstdc++/100795 - ranges::sample should not use std::sample
+#if 0 // FIXME: ranges::sample rejects integer-class difference types.
+#if __SIZEOF_INT128__
+ auto v = std::views::iota(__int128(0), __int128(20));
+#else
+ auto v = std::views::iota(0ll, 20ll);
+#endif
+#else
+ auto v = std::views::iota(0, 20);
+#endif
+
+ int storage[20] = {2,5,4,3,1,6,7,9,10,8,11,14,12,13,15,16,18,0,19,17};
+ auto w = v | std::views::transform([&](auto i) -> int& { return storage[i]; });
+ using type = decltype(w);
+ static_assert( std::ranges::random_access_range<type> );
+
+ ranges::sample(v, w.begin(), 20, rng);
+ ranges::sort(w);
+ VERIFY( ranges::equal(w, v) );
+}
+
int
main()
{
test01<forward_iterator_wrapper, output_iterator_wrapper>();
test01<input_iterator_wrapper, random_access_iterator_wrapper>();
+ test02();
}
diff --git a/libstdc++-v3/testsuite/25_algorithms/shuffle/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/shuffle/constrained.cc
index d0977a2..70c6bdf 100644
--- a/libstdc++-v3/testsuite/25_algorithms/shuffle/constrained.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/shuffle/constrained.cc
@@ -20,6 +20,7 @@
#include <algorithm>
#include <random>
+#include <ranges>
#include <vector>
#include <testsuite_hooks.h>
#include <testsuite_iterators.h>
@@ -62,8 +63,32 @@ test01()
}
}
+void
+test02()
+{
+ // PR libstdc++/100795 - ranges::shuffle should not use std::shuffle directly
+#if 0 // FIXME: ranges::shuffle rejects integer-class difference types.
+#if __SIZEOF_INT128__
+ auto v = std::views::iota(__int128(0), __int128(20));
+#else
+ auto v = std::views::iota(0ll, 20ll);
+#endif
+#else
+ auto v = std::views::iota(0, 20);
+#endif
+
+ int storage[20] = {2,5,4,3,1,6,7,9,10,8,11,14,12,13,15,16,18,0,19,17};
+ auto w = v | std::views::transform([&](auto i) -> int& { return storage[i]; });
+ using type = decltype(w);
+ static_assert( std::ranges::random_access_range<type> );
+
+ std::ranlux48_base g;
+ ranges::shuffle(w, g);
+}
+
int
main()
{
test01();
+ test02();
}
diff --git a/libstdc++-v3/testsuite/25_algorithms/sort/118209.cc b/libstdc++-v3/testsuite/25_algorithms/sort/118209.cc
new file mode 100644
index 0000000..6dedbde
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/sort/118209.cc
@@ -0,0 +1,23 @@
+// PR libstdc++ - ranges::sort doesn't use iter_move, cannot sort zip of move-only type
+// { dg-do compile { target c++23 } }
+
+#include <algorithm>
+#include <ranges>
+#include <vector>
+
+struct F {
+ int a = -1;
+ explicit F(int d) : a(d) { }
+ F(const F&) = delete;
+ F(F&& o) : a(o.a) { }
+ void operator=(const F&) = delete;
+ F& operator=(F&& o) { return *this; }
+ auto operator<=>(const F&) const = default;
+};
+
+int main () {
+ int a[] = {3,2,1};
+ std::vector<F> v(a, a+3);
+ std::ranges::sort(v); // OK
+ std::ranges::sort(std::views::zip(v)); // didn't compile
+}
diff --git a/libstdc++-v3/testsuite/25_algorithms/sort/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/sort/constrained.cc
index 82754af..930dbd7 100644
--- a/libstdc++-v3/testsuite/25_algorithms/sort/constrained.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/sort/constrained.cc
@@ -20,6 +20,7 @@
#include <algorithm>
#include <random>
+#include <ranges>
#include <vector>
#include <testsuite_hooks.h>
#include <testsuite_iterators.h>
@@ -72,9 +73,39 @@ test02()
&& ranges::equal(x, y, {}, &X::i, &X::i));
}
+constexpr bool
+test03()
+{
+ // PR libstdc++/100795 - ranges::sort should not use std::sort directly
+#if __SIZEOF_INT128__
+ auto v = std::views::iota(__int128(0), __int128(20));
+#else
+ auto v = std::views::iota(0ll, 20ll);
+#endif
+
+ int storage[20] = {2,5,4,3,1,6,7,9,10,8,11,14,12,13,15,16,18,0,19,17};
+ auto w = v | std::views::transform([&](auto i) -> int& { return storage[i]; });
+ using type = decltype(w);
+ using cat = std::iterator_traits<std::ranges::iterator_t<type>>::iterator_category;
+ static_assert( std::same_as<cat, std::output_iterator_tag> );
+ static_assert( std::ranges::random_access_range<type> );
+
+ ranges::sort(w);
+ VERIFY( ranges::equal(w, v) );
+
+ ranges::sort(w, std::ranges::greater{});
+ VERIFY( ranges::equal(w, v | std::views::reverse) );
+
+ ranges::sort(w, std::ranges::greater{}, std::negate{});
+ VERIFY( ranges::equal(w, v) );
+
+ return true;
+}
+
int
main()
{
test01();
static_assert(test02());
+ static_assert(test03());
}
diff --git a/libstdc++-v3/testsuite/25_algorithms/stable_partition/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/stable_partition/constrained.cc
index fc11c64..4dc2678 100644
--- a/libstdc++-v3/testsuite/25_algorithms/stable_partition/constrained.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/stable_partition/constrained.cc
@@ -21,6 +21,7 @@
// { dg-require-effective-target hosted }
#include <algorithm>
+#include <ranges>
#include <testsuite_hooks.h>
#include <testsuite_iterators.h>
@@ -70,9 +71,34 @@ test02()
}
}
+void
+test03()
+{
+ // PR libstdc++/100795 - ranges::stable_partition should not use
+ // std::stable_partition directly
+#if __SIZEOF_INT128__
+ auto v = std::views::iota(__int128(0), __int128(20));
+#else
+ auto v = std::views::iota(0ll, 20ll);
+#endif
+
+ int storage[20] = {2,5,4,3,1,6,7,9,10,8,11,14,12,13,15,16,18,0,19,17};
+ auto w = v | std::views::transform([&](auto i) -> int& { return storage[i]; });
+ using type = decltype(w);
+ using cat = std::iterator_traits<std::ranges::iterator_t<type>>::iterator_category;
+ static_assert( std::same_as<cat, std::output_iterator_tag> );
+ static_assert( std::ranges::random_access_range<type> );
+
+ auto pred = [] (int a) { return a%2==0; };
+ ranges::stable_partition(w, pred);
+ VERIFY( ranges::all_of(w.begin(), w.begin() + 10, pred) );
+ VERIFY( ranges::none_of(w.begin() + 10, w.end(), pred) );
+}
+
int
main()
{
test01();
test02();
+ test03();
}
diff --git a/libstdc++-v3/testsuite/25_algorithms/stable_sort/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/stable_sort/constrained.cc
index 0bd438f..5504344 100644
--- a/libstdc++-v3/testsuite/25_algorithms/stable_sort/constrained.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/stable_sort/constrained.cc
@@ -20,6 +20,7 @@
#include <algorithm>
#include <random>
+#include <ranges>
#include <vector>
#include <testsuite_hooks.h>
#include <testsuite_iterators.h>
@@ -62,8 +63,37 @@ test01()
}
}
+void
+test02()
+{
+ // PR libstdc++/100795 - ranges::stable_sort should not use std::stable_sort
+ // directly
+#if __SIZEOF_INT128__
+ auto v = std::views::iota(__int128(0), __int128(20));
+#else
+ auto v = std::views::iota(0ll, 20ll);
+#endif
+
+ int storage[20] = {2,5,4,3,1,6,7,9,10,8,11,14,12,13,15,16,18,0,19,17};
+ auto w = v | std::views::transform([&](auto i) -> int& { return storage[i]; });
+ using type = decltype(w);
+ using cat = std::iterator_traits<std::ranges::iterator_t<type>>::iterator_category;
+ static_assert( std::same_as<cat, std::output_iterator_tag> );
+ static_assert( std::ranges::random_access_range<type> );
+
+ ranges::stable_sort(w);
+ VERIFY( ranges::equal(w, v) );
+
+ ranges::stable_sort(w, std::ranges::greater{});
+ VERIFY( ranges::equal(w, v | std::views::reverse) );
+
+ ranges::stable_sort(w, std::ranges::greater{}, std::negate{});
+ VERIFY( ranges::equal(w, v) );
+}
+
int
main()
{
test01();
+ test02();
}
diff --git a/libstdc++-v3/testsuite/25_algorithms/starts_with/1.cc b/libstdc++-v3/testsuite/25_algorithms/starts_with/1.cc
new file mode 100644
index 0000000..0c288d8
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/starts_with/1.cc
@@ -0,0 +1,158 @@
+// { dg-do run { target c++23 } }
+
+#include <algorithm>
+#include <ranges>
+
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+namespace ranges = std::ranges;
+
+template<typename Range1, typename Range2>
+void
+test01()
+{
+ int n[] = {1,2,3,4,5,6,7,8,9,10};
+
+ Range1 haystack(n, n+10);
+ Range2 needle(n, n+3);
+ VERIFY( ranges::starts_with(haystack, needle) );
+
+ haystack = Range1(n);
+ needle = Range2(n, n+10);
+ VERIFY( ranges::starts_with(haystack, needle) );
+
+ haystack = Range1(n);
+ needle = Range2(n+1, n+4);
+ VERIFY( !ranges::starts_with(haystack, needle) );
+
+ haystack = Range1(n);
+ needle = Range2(n+1, n+4);
+ VERIFY( ranges::starts_with(haystack, needle,
+ [](int n, int m) { return std::abs(n - m) <= 1; }) );
+
+ haystack = Range1(n);
+ needle = Range2(n+1, n+4);
+ VERIFY( ranges::starts_with(haystack, needle,
+ ranges::equal_to{},
+ [](int n) { return n + 1; }) );
+
+ haystack = Range1(n);
+ needle = Range2(n+1, n+4);
+ VERIFY( ranges::starts_with(haystack, needle,
+ ranges::equal_to{},
+ std::identity{},
+ [](int n) { return n - 1; }) );
+
+ haystack = Range1(n, n+5);
+ needle = Range2(n, n+10);
+ VERIFY( !ranges::starts_with(haystack, needle) );
+
+ haystack = Range1(n, n+5);
+ needle = Range2(n+10, n+10);
+ VERIFY( ranges::starts_with(haystack, needle) );
+}
+
+template<typename Range1, typename Range2>
+void
+test02()
+{
+ int n[] = {1,2,3,4,5,6,7,8,9,10};
+
+ Range1 haystack(n, n+10);
+ Range2 needle(n, n+3);
+ VERIFY( ranges::starts_with(haystack.begin(), haystack.end(),
+ needle.begin(), needle.end()) );
+
+ haystack = Range1(n);
+ needle = Range2(n, n+10);
+ VERIFY( ranges::starts_with(haystack.begin(), haystack.end(),
+ needle.begin(), needle.end()) );
+
+ haystack = Range1(n);
+ needle = Range2(n+1, n+4);
+ VERIFY( !ranges::starts_with(haystack.begin(), haystack.end(),
+ needle.begin(), needle.end()) );
+
+ haystack = Range1(n);
+ needle = Range2(n+1, n+4);
+ VERIFY( ranges::starts_with(haystack.begin(), haystack.end(),
+ needle.begin(), needle.end(),
+ [](int n, int m) { return std::abs(n - m) <= 1; }) );
+
+ haystack = Range1(n);
+ needle = Range2(n+1, n+4);
+ VERIFY( ranges::starts_with(haystack.begin(), haystack.end(),
+ needle.begin(), needle.end(),
+ ranges::equal_to{},
+ [](int n) { return n + 1; }) );
+
+ haystack = Range1(n);
+ needle = Range2(n+1, n+4);
+ VERIFY( ranges::starts_with(haystack.begin(), haystack.end(),
+ needle.begin(), needle.end(),
+ ranges::equal_to{},
+ std::identity{},
+ [](int n) { return n - 1; }) );
+
+ haystack = Range1(n, n+5);
+ needle = Range2(n, n+10);
+ VERIFY( !ranges::starts_with(haystack.begin(), haystack.end(),
+ needle.begin(), needle.end()) );
+}
+
+void
+test03()
+{
+ auto haystack = std::views::iota(0, 10);
+ auto needle = std::views::iota(0, 5);
+
+#if __SIZEOF_INT128__
+ auto haystack_ict = std::views::iota(__int128(0), __int128(10));
+ auto needle_ict = std::views::iota(__int128(0), __int128(5));
+#else
+ auto haystack_ict = std::views::iota(0ll, 10ll);
+ auto needle_ict = std::views::iota(0ll, 5ll);
+#endif
+
+ VERIFY( ranges::starts_with(haystack, needle_ict) );
+ VERIFY( ranges::starts_with(haystack.begin(), haystack.end(),
+ needle_ict.begin(), needle_ict.end()) );
+
+ VERIFY( ranges::starts_with(haystack_ict, needle) );
+ VERIFY( ranges::starts_with(haystack_ict.begin(), haystack_ict.end(),
+ needle.begin(), needle.end()) );
+
+ VERIFY( ranges::starts_with(haystack_ict, needle_ict) );
+ VERIFY( ranges::starts_with(haystack_ict.begin(), haystack_ict.end(),
+ needle_ict.begin(), needle_ict.end()) );
+}
+
+int
+main()
+{
+ using namespace __gnu_test;
+ using input = test_input_range<int>;
+ using input_sized = test_input_sized_range<int>;
+ using input_sized_sent = test_sized_range_sized_sent<int, input_iterator_wrapper>;
+ using random_access = test_random_access_range<int>;
+ using random_access_sized = test_random_access_sized_range<int>;
+ using random_access_sized_sent = test_sized_range_sized_sent<int, random_access_iterator_wrapper>;
+
+ test01<input, input>();
+ test01<random_access, random_access>();
+ test02<input, input>();
+ test02<random_access, random_access>();
+
+ test01<input_sized, input_sized>();
+ test01<random_access_sized, random_access_sized>();
+ test02<input_sized, input_sized>();
+ test02<random_access_sized, random_access_sized>();
+
+ test01<input_sized_sent, input_sized_sent>();
+ test01<random_access_sized_sent, random_access_sized_sent>();
+ test02<input_sized_sent, input_sized_sent>();
+ test02<random_access_sized_sent, random_access_sized_sent>();
+
+ test03();
+}
diff --git a/libstdc++-v3/testsuite/25_algorithms/unique/120789.cc b/libstdc++-v3/testsuite/25_algorithms/unique/120789.cc
new file mode 100644
index 0000000..24b1071
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/unique/120789.cc
@@ -0,0 +1,36 @@
+// PR libstdc++/120789 - ranges::unique should use ranges::iter_move
+// { dg-do compile { target c++20 } }
+
+#include <algorithm>
+
+struct A
+{
+ bool operator==(const A&) const;
+};
+
+struct B
+{
+ B(B&&) = delete;
+ B& operator=(const A&) const;
+
+ operator A() const;
+ bool operator==(const B&) const;
+};
+
+struct I
+{
+ using value_type = A;
+ using difference_type = int;
+ B operator*() const;
+ I& operator++();
+ I operator++(int);
+ bool operator==(const I&) const;
+ friend A iter_move(const I&);
+};
+
+void
+test01()
+{
+ std::ranges::subrange<I, I> r;
+ auto [begin, end] = std::ranges::unique(r);
+}
diff --git a/libstdc++-v3/testsuite/25_algorithms/unique_copy/120384.cc b/libstdc++-v3/testsuite/25_algorithms/unique_copy/120384.cc
new file mode 100644
index 0000000..27cd337
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/unique_copy/120384.cc
@@ -0,0 +1,12 @@
+// { dg-options "-D_GLIBCXX_CONCEPT_CHECKS" }
+// { dg-do compile }
+
+// PR 120384 _BinaryPredicateConcept checks in std::unique_copy are wrong
+
+#include <algorithm>
+
+void
+test_pr120384(const int* first, const int* last, int* out)
+{
+ std::unique_copy(first, last, out);
+}
diff --git a/libstdc++-v3/testsuite/25_algorithms/unique_copy/lwg2439.cc b/libstdc++-v3/testsuite/25_algorithms/unique_copy/lwg2439.cc
new file mode 100644
index 0000000..f2ec3e3
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/unique_copy/lwg2439.cc
@@ -0,0 +1,127 @@
+// { dg-do run }
+
+#include <algorithm>
+#include <testsuite_iterators.h>
+
+using namespace __gnu_test;
+
+int out[4];
+short out_shrt[4];
+short in[7] = { 1, 2, 2, 2, 3, 4, 4 };
+
+template<typename T>
+void
+check_and_reset(T* p)
+{
+ VERIFY( p[0] == 1 );
+ VERIFY( p[1] == 2 );
+ VERIFY( p[2] == 3 );
+ VERIFY( p[3] == 4 );
+ std::fill_n(p, 4, 0);
+}
+
+struct Eq
+{
+ bool operator()(short i, short j) const { return i == j; }
+ bool operator()(short, int) const { VERIFY(false); }
+ bool operator()(int, short) const { VERIFY(false); }
+};
+
+struct Eq2
+{
+ bool operator()(const short& i, const short& j) const
+ {
+ // Both arguments should be elements of the 'in' array.
+ VERIFY( in+0 <= &i && &i < in+7 );
+ VERIFY( in+0 <= &j && &j < in+7 );
+ VERIFY( &i < &j );
+ return i == j;
+ }
+ bool operator()(short, int) const { VERIFY(false); }
+ bool operator()(int, short) const { VERIFY(false); }
+};
+
+struct Eq3
+{
+ bool operator()(const short& i, const short& j) const
+ {
+ // First argument should be element of the 'out' array.
+ // Second argument should be element of the 'in' array.
+ VERIFY( out_shrt+0 <= &i && &i < out_shrt+4 );
+ VERIFY( in+0 <= &j && &j < in+7 );
+ return i == j;
+ }
+ bool operator()(short, int) const { VERIFY(false); }
+ bool operator()(int, short) const { VERIFY(false); }
+};
+
+void
+test_forward_source()
+{
+ // The input range uses forward iterators
+ test_container<short, forward_iterator_wrapper> inc(in);
+ test_container<int, output_iterator_wrapper> outc(out);
+ std::unique_copy(inc.begin(), inc.end(), outc.begin());
+ check_and_reset(out);
+
+ test_container<short, forward_iterator_wrapper> inc2(in);
+ test_container<int, output_iterator_wrapper> outc2(out);
+ std::unique_copy(inc2.begin(), inc2.end(), outc2.begin(), Eq2());
+ check_and_reset(out);
+}
+
+void
+test_output_dest()
+{
+ // The input range uses input iterators.
+ // The output range uses output iterators.
+ test_container<short, input_iterator_wrapper> inc(in);
+ test_container<int, output_iterator_wrapper> outc(out);
+ std::unique_copy(inc.begin(), inc.end(), outc.begin());
+ check_and_reset(out);
+
+ test_container<short, input_iterator_wrapper> inc2(in);
+ test_container<int, output_iterator_wrapper> outc2(out);
+ std::unique_copy(inc2.begin(), inc2.end(), outc2.begin(), Eq());
+ check_and_reset(out);
+}
+
+void
+test_forward_dest_diff_type()
+{
+ // The input range uses input iterators.
+ // The output range uses forward iterators, but with different value type.
+ test_container<short, input_iterator_wrapper> inc(in);
+ test_container<int, forward_iterator_wrapper> outc(out);
+ std::unique_copy(inc.begin(), inc.end(), outc.begin());
+ check_and_reset(out);
+
+ test_container<short, input_iterator_wrapper> inc2(in);
+ test_container<int, forward_iterator_wrapper> outc2(out);
+ std::unique_copy(inc2.begin(), inc2.end(), outc2.begin(), Eq());
+ check_and_reset(out);
+}
+
+void
+test_forward_dest_same_type()
+{
+ // The input range uses input iterators.
+ // The output range uses forward iterators, with same value type.
+ test_container<short, input_iterator_wrapper> inc(in);
+ test_container<short, forward_iterator_wrapper> outc(out_shrt);
+ std::unique_copy(inc.begin(), inc.end(), outc.begin());
+ check_and_reset(out_shrt);
+
+ test_container<short, input_iterator_wrapper> inc2(in);
+ test_container<short, forward_iterator_wrapper> outc2(out_shrt);
+ std::unique_copy(inc2.begin(), inc2.end(), outc2.begin(), Eq3());
+ check_and_reset(out_shrt);
+}
+
+int main()
+{
+ test_forward_source();
+ test_output_dest();
+ test_forward_dest_diff_type();
+ test_forward_dest_same_type();
+}
diff --git a/libstdc++-v3/testsuite/26_numerics/complex/fabs_neg.cc b/libstdc++-v3/testsuite/26_numerics/complex/fabs_neg.cc
new file mode 100644
index 0000000..36c483e
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/complex/fabs_neg.cc
@@ -0,0 +1,13 @@
+// { dg-do compile }
+// Bug 120235 std::fabs(const std::complex<T>&) should not be defined
+
+#include <complex>
+
+void test_pr120235(std::complex<double> c)
+{
+ (void) std::fabs(c);
+ // { dg-error "no matching function" "" { target c++98_only } 8 }
+ // { dg-warning "deprecated: use 'std::abs'" "" { target c++11 } 8 }
+}
+
+// { dg-prune-output "no type named '__type'" }
diff --git a/libstdc++-v3/testsuite/26_numerics/headers/cmath/82644.cc b/libstdc++-v3/testsuite/26_numerics/headers/cmath/82644.cc
index 3274f05..40abb2c 100644
--- a/libstdc++-v3/testsuite/26_numerics/headers/cmath/82644.cc
+++ b/libstdc++-v3/testsuite/26_numerics/headers/cmath/82644.cc
@@ -15,8 +15,9 @@
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
-// { dg-options "-D__STDCPP_WANT_MATH_SPEC_FUNCS__ -D__STRICT_ANSI__" }
+// { dg-options "-D__STDCPP_WANT_MATH_SPEC_FUNCS__" }
// { dg-do compile { target c++11 } }
+// // { dg-add-options strict_std }
#define conf_hyperg 1
#define conf_hypergf 2
diff --git a/libstdc++-v3/testsuite/26_numerics/headers/cstdlib/abs128.cc b/libstdc++-v3/testsuite/26_numerics/headers/cstdlib/abs128.cc
new file mode 100644
index 0000000..cfb0562
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/headers/cstdlib/abs128.cc
@@ -0,0 +1,16 @@
+// { dg-do compile }
+// { dg-add-options strict_std }
+
+#include <cstdlib>
+
+template<typename T> T same_type(T, T) { return T(); }
+
+#ifdef __SIZEOF_INT128__
+__int128 i = 0;
+__int128 j = same_type(std::abs(i), i);
+#endif
+
+#ifdef __SIZEOF_FLOAT128__
+__float128 f = 0.0;
+__float128 g = same_type(std::abs(f), f);
+#endif
diff --git a/libstdc++-v3/testsuite/26_numerics/pstl/numeric_ops/108236.cc b/libstdc++-v3/testsuite/26_numerics/pstl/numeric_ops/108236.cc
index e0e3027..cbef8ab 100644
--- a/libstdc++-v3/testsuite/26_numerics/pstl/numeric_ops/108236.cc
+++ b/libstdc++-v3/testsuite/26_numerics/pstl/numeric_ops/108236.cc
@@ -8,30 +8,6 @@
#include <execution>
#include <testsuite_hooks.h>
-struct Mint
-{
- Mint(int i = 0) : val(i) { }
- Mint(Mint&&) = default;
- Mint& operator=(Mint&&) = default;
-
- operator int() const { return val; }
-
-private:
- int val;
-};
-
-void
-test_move_only()
-{
- const int input[]{10, 20, 30};
- int output[3];
- std::exclusive_scan(std::execution::seq, input, input+3, output, Mint(5),
- std::plus<int>{});
- VERIFY( output[0] == 5 );
- VERIFY( output[1] == 15 );
- VERIFY( output[2] == 35 );
-}
-
void
test_pr108236()
{
@@ -45,6 +21,5 @@ test_pr108236()
int main()
{
- test_move_only();
test_pr108236();
}
diff --git a/libstdc++-v3/testsuite/26_numerics/pstl/numeric_ops/move_only.cc b/libstdc++-v3/testsuite/26_numerics/pstl/numeric_ops/move_only.cc
new file mode 100644
index 0000000..38ad3c2
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/pstl/numeric_ops/move_only.cc
@@ -0,0 +1,90 @@
+// { dg-options "-ltbb" }
+// { dg-do run { target c++17 } }
+// { dg-require-effective-target tbb_backend }
+
+#include <numeric>
+#include <execution>
+#include <testsuite_hooks.h>
+
+struct Mint
+{
+ Mint(int i = 0) : val(i) { }
+
+ Mint(Mint&& m) : val(m.val) { m.val = -1; }
+
+ Mint& operator=(Mint&& m)
+ {
+ val = m.val;
+ m.val = -1;
+ return *this;
+ }
+
+ operator int() const
+ {
+ VERIFY(val >= 0); // Check we don't read value of a moved-from instance.
+ return val;
+ }
+
+ friend Mint operator+(const Mint& lhs, const Mint& rhs)
+ { return Mint(lhs.val + rhs.val); }
+
+private:
+ int val;
+};
+
+void
+test_reduce()
+{
+ Mint input[]{1, 2, 3};
+ Mint m = std::reduce(std::execution::seq, input, input+3);
+ VERIFY( static_cast<int>(m) == 6 );
+
+ m = std::reduce(std::execution::seq, input, input+3, Mint(100));
+ VERIFY( static_cast<int>(m) == 106 );
+
+ m = std::reduce(std::execution::seq, input, input+3, Mint(200),
+ std::plus<>{});
+ VERIFY( static_cast<int>(m) == 206 );
+}
+
+void
+test_transform_reduce()
+{
+}
+
+void
+test_exclusive_scan()
+{
+ const int input[]{10, 20, 30};
+ int output[3];
+ std::exclusive_scan(std::execution::seq, input, input+3, output, Mint(5),
+ std::plus<int>{});
+ VERIFY( output[0] == 5 );
+ VERIFY( output[1] == 15 );
+ VERIFY( output[2] == 35 );
+}
+
+void
+test_inclusive_scan()
+{
+}
+
+void
+test_transform_exclusive_scan()
+{
+}
+
+void
+test_transform_inclusive_scan()
+{
+}
+
+int main()
+{
+ test_reduce();
+ test_transform_reduce();
+ test_exclusive_scan();
+ test_inclusive_scan();
+ test_transform_exclusive_scan();
+ test_transform_inclusive_scan();
+}
diff --git a/libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc b/libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc
index 3c5aa7f..0afba65 100644
--- a/libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc
+++ b/libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc
@@ -12,4 +12,4 @@ auto x = std::generate_canonical<std::size_t,
// { dg-error "static assertion failed: template argument must be a floating point type" "" { target *-*-* } 270 }
-// { dg-error "static assertion failed: template argument must be a floating point type" "" { target *-*-* } 3351 }
+// { dg-error "static assertion failed: template argument must be a floating point type" "" { target *-*-* } 3357 }
diff --git a/libstdc++-v3/testsuite/27_io/basic_istringstream/cons/char/string_view.cc b/libstdc++-v3/testsuite/27_io/basic_istringstream/cons/char/string_view.cc
new file mode 100644
index 0000000..f25b538
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/basic_istringstream/cons/char/string_view.cc
@@ -0,0 +1,201 @@
+// C++26 [istringstream.general]
+
+// { dg-do run { target c++26 } }
+
+#include <sstream>
+#include <string>
+#include <string_view>
+#include <testsuite_allocator.h>
+#include <testsuite_hooks.h>
+
+// Check C++26 P2495 istringstream ctors and members str(s) that accept a
+// string_view, or anything convertible to a string_view, in place of a
+// string object. Mostly just verify plumbing.
+
+#ifndef C
+# define C char
+# define L(a) a
+#endif
+
+using string = std::basic_string<C>;
+using string_view = std::basic_string_view<C>;
+using istringstream = std::basic_istringstream<C>;
+
+struct convertible_to_string_view {
+ string s;
+ operator string_view() const { return s; }
+};
+
+const string str(L("This is a test string"));
+convertible_to_string_view cstr{str}; // a copy
+const convertible_to_string_view ccstr{str}; // another copy
+
+template <typename istringstream = std::basic_istringstream<C>>
+void
+test01()
+{
+ // Test C++26 constructor and str(s) taking a generalized string_view
+
+ static_assert(! requires { istringstream(1); },
+ "istringstream ctor should reject what cannot be converted to a string_view");
+ static_assert(! requires { istringstream().str(1); },
+ "istringstream::str(s) should reject what cannot be converted to a string_view");
+
+ static_assert(!std::is_convertible_v<string_view, istringstream>,
+ "istringstream(string_view, ios::openmode) is explicit");
+ static_assert(!std::is_convertible_v<const string_view, istringstream>,
+ "istringstream(string_view, ios::openmode) is explicit");
+ static_assert(!std::is_convertible_v<convertible_to_string_view, istringstream>,
+ "istringstream(convertible_to_string_view, ios::openmode) is explicit");
+ static_assert(!std::is_convertible_v<const convertible_to_string_view, istringstream>,
+ "istringstream(convertible_to_string_view, ios::openmode) is explicit");
+
+ {
+ istringstream istr(cstr);
+ VERIFY( istr.str() == cstr.s );
+ VERIFY( istr.get() == cstr.s[0] );
+ }
+ {
+ istringstream istr(ccstr);
+ VERIFY( istr.str() == ccstr.s );
+ VERIFY( istr.get() == ccstr.s[0] );
+ }
+ {
+ istringstream istr(cstr, std::ios_base::in);
+ VERIFY( istr.str() == cstr.s );
+ VERIFY( istr.get() == cstr.s[0] );
+ VERIFY( istr.rdbuf()->sputc('X') != 'X' );
+ }
+ {
+ istringstream istr(cstr, std::ios_base::out);
+ VERIFY( istr.str() == cstr.s );
+ VERIFY( istr.get() == cstr.s[0] );
+ VERIFY( istr.rdbuf()->sputc('X') == 'X' );
+ }
+}
+
+void
+test02()
+{
+ // Test various C++26 constructors taking string views
+ // and mix of other arguments
+
+ auto const mode = std::ios_base::in | std::ios_base::out;
+
+ {
+ // template <typename T>
+ // basic_istringstream(const T&, ios_base::openmode, const allocator_type&)
+
+ istringstream::allocator_type a;
+ {
+ istringstream istr(cstr, mode, a); // ={} checks for non-explicit ctor
+ VERIFY( istr.str() == cstr.s );
+ }
+ {
+ istringstream istr(cstr, std::ios::in, a);
+ VERIFY( istr.str() == cstr.s );
+ VERIFY( istr.get() == cstr.s[0] );
+ VERIFY( istr.rdbuf()->sputc('X') != 'X' );
+ }
+ {
+ istringstream istr(cstr, std::ios::out, a);
+ VERIFY( istr.str() == cstr.s );
+ VERIFY( istr.get() == cstr.s[0] );
+ VERIFY( istr.rdbuf()->sputc('X') == 'X' );
+ }
+ }
+
+ {
+ // template <typename T>
+ // basic_istringstream(const T&, ios_base::openmode)
+ {
+ istringstream istr(cstr, mode);
+ VERIFY( istr.str() == cstr.s );
+ VERIFY( istr.get() == cstr.s[0] );
+ VERIFY( istr.rdbuf()->sputc('X') == 'X' );
+ }
+ {
+ istringstream istr(cstr, std::ios::in);
+ VERIFY( istr.str() == cstr.s );
+ VERIFY( istr.get() == cstr.s[0] );
+ VERIFY( istr.rdbuf()->sputc('X') != 'X' );
+ }
+ {
+ istringstream istr(cstr, std::ios::out);
+ VERIFY( istr.str() == cstr.s );
+ VERIFY( istr.get() == cstr.s[0] );
+ VERIFY( istr.rdbuf()->sputc('X') == 'X' );
+ }
+ }
+
+ {
+ // template <typename T>
+ // explicit
+ // basic_istringstream(const T&, ios_base::openmode = ios_base::in)
+
+ istringstream istr(cstr);
+ VERIFY( istr.str() == cstr.s );
+ VERIFY( istr.get() == cstr.s[0] );
+ VERIFY( istr.rdbuf()->sputc('X') != 'X' );
+ }
+}
+
+using alloc_type = __gnu_test::uneq_allocator<C>;
+
+template<typename Alloc, typename CC = typename Alloc::value_type>
+ using istringstream_with_alloc
+ = std::basic_istringstream<CC, std::char_traits<CC>, Alloc>;
+
+void test03()
+{
+ alloc_type a{1};
+ {
+ istringstream_with_alloc<alloc_type> istr(cstr, a);
+#if _GLIBCXX_USE_CXX11_ABI
+ VERIFY( istr.rdbuf()->get_allocator() == a );
+#endif
+ VERIFY( string_view{istr.str()} == cstr );
+ VERIFY( istr.get() == cstr.s[0] );
+ }
+ {
+ istringstream_with_alloc<alloc_type> istr(cstr, std::ios::in, a);
+#if _GLIBCXX_USE_CXX11_ABI
+ VERIFY( istr.rdbuf()->get_allocator() == a );
+#endif
+ VERIFY( string_view{istr.str()} == cstr );
+ VERIFY( istr.get() == cstr.s[0] );
+ VERIFY( istr.rdbuf()->sputc('X') != 'X' );
+ }
+ {
+ istringstream_with_alloc<alloc_type> istr(cstr, std::ios::out, a);
+#if _GLIBCXX_USE_CXX11_ABI
+ VERIFY( istr.rdbuf()->get_allocator() == a );
+#endif
+ VERIFY( string_view{istr.str()} == cstr );
+ VERIFY( istr.get() == cstr.s[0] );
+ VERIFY( istr.rdbuf()->sputc('X') == 'X' );
+ }
+}
+
+void test04()
+{
+ {
+ istringstream istr;
+ istr.str( cstr );
+ VERIFY( istr.str() == cstr.s );
+ }
+ {
+ istringstream istr;
+ istr.str( ccstr );
+ VERIFY( istr.str() == ccstr.s );
+ }
+}
+
+int
+main()
+{
+ test01();
+ test02();
+ test03();
+ test04();
+}
diff --git a/libstdc++-v3/testsuite/27_io/basic_istringstream/cons/wchar_t/string_view.cc b/libstdc++-v3/testsuite/27_io/basic_istringstream/cons/wchar_t/string_view.cc
new file mode 100644
index 0000000..62fb03c
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/basic_istringstream/cons/wchar_t/string_view.cc
@@ -0,0 +1,6 @@
+// C++26 [istringstream.general]
+// { dg-do run { target c++26 } }
+
+#define C wchar_t
+#define L(a) L##a
+#include "../char/string_view.cc"
diff --git a/libstdc++-v3/testsuite/27_io/basic_ostream/inserters_arithmetic/char/hexfloat.cc b/libstdc++-v3/testsuite/27_io/basic_ostream/inserters_arithmetic/char/hexfloat.cc
index b1bc7fb..f694730 100644
--- a/libstdc++-v3/testsuite/27_io/basic_ostream/inserters_arithmetic/char/hexfloat.cc
+++ b/libstdc++-v3/testsuite/27_io/basic_ostream/inserters_arithmetic/char/hexfloat.cc
@@ -95,6 +95,11 @@ test01()
void
test02()
{
+ /* If these conditions are not met, basic_string.h doesn't define
+ std::stold(const string&, size_t* = 0), and then the test would
+ fail to compile. */
+#if (_GLIBCXX_HAVE_STRTOLD && ! _GLIBCXX_HAVE_BROKEN_STRTOLD) \
+ || __DBL_MANT_DIG__ == __LDBL_MANT_DIG__
ostringstream os;
long double d = 272.L; // 0x1.1p+8L;
os << hexfloat << setprecision(1);
@@ -140,6 +145,7 @@ test02()
cout << "got: " << os.str() << endl;
#endif
VERIFY( os && os.str() == "15" );
+#endif
}
int
diff --git a/libstdc++-v3/testsuite/27_io/basic_ostringstream/cons/char/string_view.cc b/libstdc++-v3/testsuite/27_io/basic_ostringstream/cons/char/string_view.cc
new file mode 100644
index 0000000..6279c19
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/basic_ostringstream/cons/char/string_view.cc
@@ -0,0 +1,200 @@
+// C++26 [ostringstream.general]
+
+// { dg-do run { target c++26 } }
+
+#include <sstream>
+#include <string>
+#include <string_view>
+#include <testsuite_allocator.h>
+#include <testsuite_hooks.h>
+
+// Check C++26 P2495 ostringstream ctors and members str(s) that accept a
+// string_view, or anything convertible to a string_view, in place of a
+// string object. Mostly just verify plumbing.
+
+#ifndef C
+# define C char
+# define L(a) a
+#endif
+
+using string = std::basic_string<C>;
+using string_view = std::basic_string_view<C>;
+using ostringstream = std::basic_ostringstream<C>;
+
+struct convertible_to_string_view {
+ string s;
+ operator string_view() const { return s; }
+};
+
+const string str(L("This is a test string"));
+convertible_to_string_view cstr{str}; // a copy
+const convertible_to_string_view ccstr{str}; // another copy
+
+template <typename ostringstream = std::basic_ostringstream<C>>
+void
+test01()
+{
+ // Test C++26 constructor and str(s) taking a generalized string_view
+
+ static_assert(! requires { ostringstream(1); },
+ "ostringstream ctor should reject what cannot be converted to a string_view");
+ static_assert(! requires { ostringstream().str(1); },
+ "ostringstream::str(s) should reject what cannot be converted to a string_view");
+
+ static_assert(!std::is_convertible_v<string_view, ostringstream>,
+ "ostringstream(string_view, ios::openmode) is explicit");
+ static_assert(!std::is_convertible_v<const string_view, ostringstream>,
+ "ostringstream(string_view, ios::openmode) is explicit");
+ static_assert(!std::is_convertible_v<convertible_to_string_view, ostringstream>,
+ "ostringstream(convertible_to_string_view, ios::openmode) is explicit");
+ static_assert(!std::is_convertible_v<const convertible_to_string_view, ostringstream>,
+ "ostringstream(convertible_to_string_view, ios::openmode) is explicit");
+
+ {
+ ostringstream ostrstr(cstr);
+ VERIFY( ostrstr.str() == cstr.s );
+ VERIFY( ostrstr.rdbuf()->sgetc() == ostringstream::traits_type::eof() );
+ }
+ {
+ ostringstream ostrstr(ccstr);
+ VERIFY( ostrstr.str() == ccstr.s );
+ VERIFY( ostrstr.rdbuf()->sgetc() == ostringstream::traits_type::eof() );
+ }
+ {
+ ostringstream ostrstr(cstr, std::ios_base::in);
+ VERIFY( ostrstr.str() == cstr.s );
+ VERIFY( ostrstr.rdbuf()->sgetc() == cstr.s[0]);
+ VERIFY( ostrstr.put('Y').rdstate() == ostrstr.goodbit );
+ }
+ {
+ ostringstream ostrstr(cstr, std::ios_base::out);
+ VERIFY( ostrstr.str() == cstr.s );
+ VERIFY( ostrstr.rdbuf()->sgetc() == ostringstream::traits_type::eof() );
+ VERIFY( ostrstr.put('Y').rdstate() == ostrstr.goodbit );
+ }
+}
+
+void
+test02()
+{
+ // Test plumbing of C++26 various constructors taking string views
+
+ auto const mode = std::ios_base::in | std::ios_base::out;
+
+ {
+ ostringstream::allocator_type a;
+ // template <typename T>
+ // basic_ostringstream(const T&, ios_base::openmode, const allocator_type&)
+ {
+ ostringstream ostrstr(cstr, mode, a); // ={} checks for non-explicit ctor
+ VERIFY( ostrstr.str() == cstr.s );
+ }
+ {
+ ostringstream ostrstr(cstr, std::ios::in, a);
+ VERIFY( ostrstr.str() == cstr.s );
+ VERIFY( ostrstr.rdbuf()->sgetc() == cstr.s[0]);
+ VERIFY( ostrstr.put('Y').rdstate() == ostrstr.goodbit );
+ }
+ {
+ ostringstream ostrstr(cstr, std::ios::out, a);
+ VERIFY( ostrstr.str() == cstr.s );
+ VERIFY( ostrstr.rdbuf()->sgetc() == ostringstream::traits_type::eof() );
+ VERIFY( ostrstr.put('Y').rdstate() == ostrstr.goodbit );
+ }
+ }
+
+ {
+ // template <typename T>
+ // basic_ostringstream(const T&, ios_base::openmode)
+ {
+ ostringstream ostrstr(cstr, mode);
+ VERIFY( ostrstr.str() == cstr.s );
+ VERIFY( ostrstr.rdbuf()->sgetc() == cstr.s[0]);
+ VERIFY( ostrstr.put('Y').good() );
+ }
+ {
+ ostringstream ostrstr(cstr, std::ios::in);
+ VERIFY( ostrstr.str() == cstr.s );
+ VERIFY( ostrstr.rdbuf()->sgetc() == cstr.s[0]);
+ VERIFY( ostrstr.put('X').good() );
+ }
+ {
+ ostringstream ostrstr(cstr, std::ios::out);
+ VERIFY( ostrstr.str() == cstr.s );
+ VERIFY( ostrstr.rdbuf()->sgetc() == ostringstream::traits_type::eof() );
+ VERIFY( ostrstr.put('Y').rdstate() == ostrstr.goodbit );
+ }
+ }
+
+ {
+ // template <typename T>
+ // explicit
+ // basic_ostringstream(const T&, ios_base::openmode = ios_base::out)
+
+ ostringstream ostrstr(cstr);
+ VERIFY( ostrstr.str() == cstr.s );
+ VERIFY( ostrstr.rdbuf()->sgetc() == ostringstream::traits_type::eof() );
+ VERIFY( ostrstr.put('Y').good() );
+ }
+}
+
+using alloc_type = __gnu_test::uneq_allocator<C>;
+
+template<typename Alloc, typename CC = typename Alloc::value_type>
+ using ostringstream_with_alloc
+ = std::basic_ostringstream<CC, std::char_traits<CC>, Alloc>;
+
+void test03()
+{
+ alloc_type a{1};
+ {
+ ostringstream_with_alloc<alloc_type> ostrstr(cstr, a);
+#if _GLIBCXX_USE_CXX11_ABI
+ VERIFY( ostrstr.rdbuf()->get_allocator() == a );
+#endif
+ VERIFY( string_view{ostrstr.str()} == cstr );
+ VERIFY( ostrstr.rdbuf()->sgetc() == ostringstream::traits_type::eof() );
+ VERIFY( ostrstr.put('X').good() );
+ }
+ {
+ ostringstream_with_alloc<alloc_type> ostrstr(cstr, std::ios::in, a);
+#if _GLIBCXX_USE_CXX11_ABI
+ VERIFY( ostrstr.rdbuf()->get_allocator() == a );
+#endif
+ VERIFY( string_view{ostrstr.str()} == cstr );
+ VERIFY( ostrstr.rdbuf()->sgetc() == cstr.s[0]);
+ VERIFY( ostrstr.put('X').good() );
+ }
+ {
+ ostringstream_with_alloc<alloc_type> ostrstr(cstr, std::ios::out, a);
+#if _GLIBCXX_USE_CXX11_ABI
+ VERIFY( ostrstr.rdbuf()->get_allocator() == a );
+#endif
+ VERIFY( string_view{ostrstr.str()} == cstr );
+ VERIFY( ostrstr.rdbuf()->sgetc() == ostringstream::traits_type::eof() );
+ VERIFY( ostrstr.put('Y').rdstate() == ostrstr.goodbit );
+ }
+}
+
+void test04()
+{
+ {
+ ostringstream ostrstr;
+ ostrstr.str(cstr);
+ VERIFY( ostrstr.str() == cstr.s );
+ }
+ {
+ ostringstream ostrstr;
+ ostrstr.str(ccstr);
+ VERIFY( ostrstr.str() == ccstr.s );
+ }
+}
+
+int
+main()
+{
+ test01();
+ test02();
+ test03();
+ test04();
+}
diff --git a/libstdc++-v3/testsuite/27_io/basic_ostringstream/cons/wchar_t/string_view.cc b/libstdc++-v3/testsuite/27_io/basic_ostringstream/cons/wchar_t/string_view.cc
new file mode 100644
index 0000000..ee6ac8d
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/basic_ostringstream/cons/wchar_t/string_view.cc
@@ -0,0 +1,6 @@
+// C++26 [ostringstream.general]
+// { dg-do run { target c++26 } }
+
+#define C wchar_t
+#define L(a) L##a
+#include "../char/string_view.cc"
diff --git a/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/char/string_view.cc b/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/char/string_view.cc
new file mode 100644
index 0000000..14278b3
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/char/string_view.cc
@@ -0,0 +1,211 @@
+// C++26 31.8.2.1 [stringbuf.general]
+
+// { dg-do run { target c++26 } }
+
+#include <sstream>
+#include <string>
+#include <string_view>
+#include <testsuite_allocator.h>
+#include <testsuite_hooks.h>
+
+// Check C++26 P2495 stringbuf ctors and members str(s) that accept a
+// string_view, or anything convertible to a string_view, in place of a
+// string object.
+
+#ifndef C
+# define C char
+# define L(a) a
+#endif
+
+using string = std::basic_string<C>;
+using string_view = std::basic_string_view<C>;
+using stringbuf = std::basic_stringbuf<C>;
+
+struct convertible_to_string_view {
+ string s;
+ operator string_view() const { return s; }
+};
+
+const string str(L("This is a test string"));
+convertible_to_string_view cstr{str}; // a copy
+const convertible_to_string_view ccstr{str}; // another copy
+
+template <typename stringbuf = std::basic_stringbuf<C>>
+void
+test01()
+{
+ // Test C++26 constructor and str(s) taking a generalized string_view
+
+ static_assert(! requires { stringbuf(1); },
+ "stringbuf ctor should reject what cannot be converted to a string_view");
+ static_assert(! requires { stringbuf().str(1); },
+ "stringbuf::str(s) should reject what cannot be converted to a string_view");
+
+ static_assert(!std::is_convertible_v<string_view, stringbuf>,
+ "stringbuf(string_view, ios::openmode) is explicit");
+ static_assert(!std::is_convertible_v<const string_view, stringbuf>,
+ "stringbuf(string_view, ios::openmode) is explicit");
+ static_assert(!std::is_convertible_v<convertible_to_string_view, stringbuf>,
+ "stringbuf(convertible_to_string_view, ios::openmode) is explicit");
+ static_assert(
+ !std::is_convertible_v<const convertible_to_string_view, stringbuf>,
+ "stringbuf(convertible_to_string_view, ios::openmode) is explicit");
+
+ {
+ stringbuf sbuf(cstr);
+ VERIFY( sbuf.str() == cstr.s );
+ VERIFY( sbuf.sgetc() == cstr.s[0] );
+ }
+ {
+ stringbuf sbuf(ccstr);
+ VERIFY( sbuf.str() == ccstr.s );
+ VERIFY( sbuf.sgetc() == ccstr.s[0] );
+ }
+ {
+ stringbuf sbuf(cstr, std::ios_base::in);
+ VERIFY( sbuf.str() == cstr.s );
+ VERIFY( sbuf.sgetc() == cstr.s[0] );
+ VERIFY( sbuf.sputc('X') == stringbuf::traits_type::eof() );
+ }
+ {
+ stringbuf sbuf(ccstr, std::ios_base::in);
+ VERIFY( sbuf.str() == ccstr.s );
+ VERIFY( sbuf.sgetc() == ccstr.s[0] );
+ VERIFY( sbuf.sputc('X') == stringbuf::traits_type::eof() );
+ }
+ {
+ stringbuf sbuf(cstr, std::ios_base::out);
+ VERIFY( sbuf.str() == cstr.s );
+ VERIFY( sbuf.sputc('Y') == 'Y' );
+ VERIFY( sbuf.sgetc() == stringbuf::traits_type::eof() );
+ }
+ {
+ stringbuf sbuf(ccstr, std::ios_base::out);
+ VERIFY( sbuf.str() == ccstr.s );
+ VERIFY( sbuf.sputc('Y') == 'Y' );
+ VERIFY( sbuf.sgetc() == stringbuf::traits_type::eof() );
+ }
+}
+
+void
+test02()
+{
+ // Test C++26 constructors taking string views using different allocators
+
+ auto const mode = std::ios_base::in | std::ios_base::out;
+
+ {
+ // template <typename T>
+ // basic_stringbuf(const T&, ios_base::openmode, const allocator_type&)
+
+ stringbuf::allocator_type a;
+ {
+ stringbuf sbuf(cstr, mode, a); // ={} checks for non-explicit ctor
+ VERIFY( sbuf.str() == cstr.s );
+ }
+ {
+ stringbuf sbuf(cstr, std::ios::in, a);
+ VERIFY( sbuf.str() == cstr.s );
+ VERIFY( sbuf.sgetc() == cstr.s[0] );
+ VERIFY( sbuf.sputc('X') == stringbuf::traits_type::eof() );
+ }
+
+ {
+ stringbuf sbuf(cstr, std::ios::out, a);
+ VERIFY( sbuf.str() == cstr.s );
+ VERIFY( sbuf.sputc('X') == 'X' );
+ VERIFY( sbuf.sgetc() == stringbuf::traits_type::eof() );
+ }
+ }
+
+ {
+ // template <typename T>
+ // basic_stringbuf(const T&, ios_base::openmode)
+ {
+ stringbuf sbuf(cstr, mode);
+ VERIFY( sbuf.str() == cstr.s );
+ }
+ {
+ stringbuf sbuf(cstr, std::ios::in);
+ VERIFY( sbuf.str() == cstr.s );
+ VERIFY( sbuf.sgetc() == cstr.s[0] );
+ VERIFY( sbuf.sputc('X') == stringbuf::traits_type::eof() );
+ }
+ {
+ stringbuf sbuf(cstr, std::ios::out);
+ VERIFY( sbuf.str() == cstr.s );
+ VERIFY( sbuf.sputc('X') == 'X' );
+ VERIFY( sbuf.sgetc() == stringbuf::traits_type::eof() );
+ }
+ }
+
+ {
+ // template <typename T>
+ // explicit
+ // basic_stringbuf(const T&, ios_base::openmode = ios_base::in|ios_base::out)
+
+ stringbuf sbuf(cstr);
+ VERIFY( sbuf.str() == cstr.s );
+ VERIFY( sbuf.sgetc() == cstr.s[0] );
+ }
+}
+
+using alloc_type = __gnu_test::uneq_allocator<C>;
+
+template<typename Alloc, typename CC = typename Alloc::value_type>
+ using stringbuf_with_alloc
+ = std::basic_stringbuf<CC, std::char_traits<CC>, Alloc>;
+
+void test03()
+{
+ alloc_type a{1};
+ {
+ stringbuf_with_alloc<alloc_type> sbuf(cstr, a);
+#if _GLIBCXX_USE_CXX11_ABI
+ VERIFY( sbuf.get_allocator() == a );
+#endif
+ VERIFY( string_view{sbuf.str()} == cstr );
+ VERIFY( sbuf.sgetc() == cstr.s[0] );
+ }
+ {
+ stringbuf_with_alloc<alloc_type> sbuf(cstr, std::ios::in, a);
+#if _GLIBCXX_USE_CXX11_ABI
+ VERIFY( sbuf.get_allocator() == a );
+#endif
+ VERIFY( string_view{sbuf.str()} == cstr );
+ VERIFY( sbuf.sgetc() == cstr.s[0] );
+ VERIFY( sbuf.sputc('X') == stringbuf::traits_type::eof() );
+ }
+ {
+ stringbuf_with_alloc<alloc_type> sbuf(cstr, std::ios::out, a);
+#if _GLIBCXX_USE_CXX11_ABI
+ VERIFY( sbuf.get_allocator() == a );
+#endif
+ VERIFY( string_view{sbuf.str()} == cstr );
+ VERIFY( sbuf.sputc('X') == 'X' );
+ VERIFY( sbuf.sgetc() == stringbuf::traits_type::eof() );
+ }
+}
+
+void test04()
+{
+ {
+ stringbuf sbuf;
+ sbuf.str(cstr);
+ VERIFY( sbuf.str() == cstr.s );
+ }
+ {
+ stringbuf sbuf;
+ sbuf.str(ccstr);
+ VERIFY( sbuf.str() == ccstr.s );
+ }
+}
+
+int
+main()
+{
+ test01();
+ test02();
+ test03();
+ test04();
+}
diff --git a/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/wchar_t/string_view.cc b/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/wchar_t/string_view.cc
new file mode 100644
index 0000000..c428491
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/wchar_t/string_view.cc
@@ -0,0 +1,6 @@
+// C++26 [stringbuf.general]
+// { dg-do run { target c++26 } }
+
+#define C wchar_t
+#define L(a) L##a
+#include "../char/string_view.cc"
diff --git a/libstdc++-v3/testsuite/27_io/basic_stringstream/cons/char/string_view.cc b/libstdc++-v3/testsuite/27_io/basic_stringstream/cons/char/string_view.cc
new file mode 100644
index 0000000..1c9ecea
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/basic_stringstream/cons/char/string_view.cc
@@ -0,0 +1,210 @@
+// C++26 31.8.2.1 [stringstream.general]
+
+// { dg-do run { target c++26 } }
+
+#include <sstream>
+#include <string>
+#include <string_view>
+#include <testsuite_allocator.h>
+#include <testsuite_hooks.h>
+
+// Check C++26 P2495 stringstream ctors and members str(s) that accept a
+// string_view, or anything convertible to a string_view, in place of a
+// string object. Mostly just verify plumbing.
+
+#ifndef C
+# define C char
+# define L(a) a
+#endif
+
+using string = std::basic_string<C>;
+using string_view = std::basic_string_view<C>;
+using stringstream = std::basic_stringstream<C>;
+
+struct convertible_to_string_view {
+ string s;
+ operator string_view() const { return s; }
+};
+
+const string str(L("This is a test string"));
+convertible_to_string_view cstr{str}; // a copy
+const convertible_to_string_view ccstr{str}; // another copy
+
+template <typename stringstream = std::basic_stringstream<C>>
+void
+test01()
+{
+ // Test C++26 constructor and str(s) taking a generalized string_view
+
+ static_assert(! requires { stringstream(1); },
+ "stringstream ctor should reject what cannot be converted to a string_view");
+ static_assert(! requires { stringstream().str(1); },
+ "stringstream::str(s) should reject what cannot be converted to a string_view");
+
+ static_assert(!std::is_convertible_v<string_view, stringstream>,
+ "stringstream(string_view, ios::openmode) is explicit");
+ static_assert(!std::is_convertible_v<const string_view, stringstream>,
+ "stringstream(string_view, ios::openmode) is explicit");
+ static_assert(!std::is_convertible_v<convertible_to_string_view, stringstream>,
+ "stringstream(convertible_to_string_view, ios::openmode) is explicit");
+ static_assert(!std::is_convertible_v<const convertible_to_string_view, stringstream>,
+ "stringstream(convertible_to_string_view, ios::openmode) is explicit");
+
+ {
+ stringstream strstr(cstr);
+ VERIFY( strstr.str() == cstr.s );
+ VERIFY( strstr.get() == cstr.s[0] );
+ }
+ {
+ stringstream strstr(ccstr);
+ VERIFY( strstr.str() == ccstr.s );
+ VERIFY( strstr.get() == ccstr.s[0] );
+ }
+ {
+ stringstream strstr(cstr, std::ios_base::in);
+ VERIFY( strstr.str() == cstr.s );
+ VERIFY( strstr.get() == cstr.s[0] );
+ VERIFY( strstr.put('X').rdstate() == strstr.badbit );
+ }
+ {
+ stringstream strstr(cstr, std::ios_base::out);
+ VERIFY( strstr.str() == cstr.s );
+ VERIFY( strstr.put('Y').good() );
+ VERIFY( strstr.get() == stringstream::traits_type::eof());
+ }
+}
+
+void
+test02()
+{
+ // Test C++26 various constructors taking string views
+
+ auto const mode = std::ios_base::in | std::ios_base::out;
+
+ {
+ // template <typename T>
+ // basic_stringstream(const T&, ios_base::openmode, const allocator_type&)
+
+ stringstream::allocator_type a;
+ {
+ stringstream strstr(cstr, mode, a); // ={} checks for non-explicit ctor
+ VERIFY( strstr.str() == cstr.s );
+ }
+ {
+ stringstream strstr(cstr, std::ios::in, a);
+ VERIFY( strstr.str() == cstr.s );
+ VERIFY( strstr.get() == cstr.s[0] );
+ VERIFY( strstr.put('X').rdstate() == strstr.badbit );
+ }
+ {
+ stringstream strstr(cstr, std::ios::out, a);
+ VERIFY( strstr.str() == cstr.s );
+ VERIFY( strstr.put('X').good() );
+ VERIFY( strstr.get() == stringstream::traits_type::eof());
+ }
+ }
+
+ {
+ // template <typename T>
+ // basic_stringstream(const T&, ios_base::openmode)
+
+ {
+ stringstream strstr(cstr, mode);
+ VERIFY( strstr.str() == cstr.s );
+ VERIFY( strstr.get() == cstr.s[0] );
+ VERIFY( strstr.put('X').good() );
+ }
+ {
+ stringstream strstr(cstr, std::ios::in);
+ VERIFY( strstr.str() == cstr.s );
+ VERIFY( strstr.get() == cstr.s[0] );
+ VERIFY( strstr.put('X').rdstate() == strstr.badbit );
+ }
+ {
+ stringstream strstr(cstr, std::ios::out);
+ VERIFY( strstr.str() == cstr.s );
+ VERIFY( strstr.put('X').good() );
+ VERIFY( strstr.get() == stringstream::traits_type::eof());
+ }
+ }
+
+ {
+ // template <typename T>
+ // explicit
+ // basic_stringstream(const T&, ios_base::openmode = ios_base::in|ios_base::out)
+
+ stringstream strstr(cstr);
+ VERIFY( strstr.str() == cstr.s );
+ VERIFY( strstr.get() == cstr.s[0] );
+ VERIFY( strstr.put('X').good() );
+ }
+}
+
+// A minimal allocator with no default constructor
+template<typename T>
+ struct NoDefaultCons : __gnu_test::SimpleAllocator<T>
+ {
+ using __gnu_test::SimpleAllocator<T>::SimpleAllocator;
+ NoDefaultCons() = delete;
+ NoDefaultCons(int) { }
+ };
+
+using alloc_type = __gnu_test::uneq_allocator<C>;
+
+template<typename Alloc, typename CC = typename Alloc::value_type>
+ using stringstream_with_alloc
+ = std::basic_stringstream<CC, std::char_traits<CC>, Alloc>;
+
+void test03()
+{
+ alloc_type a{1};
+ {
+ stringstream_with_alloc<alloc_type> strstr(cstr, a);
+#if _GLIBCXX_USE_CXX11_ABI
+ VERIFY( strstr.rdbuf()->get_allocator() == a );
+#endif
+ VERIFY( string_view{strstr.str()} == cstr );
+ VERIFY( strstr.get() == cstr.s[0] );
+ }
+ {
+ stringstream_with_alloc<alloc_type> strstr(cstr, std::ios::in, a);
+#if _GLIBCXX_USE_CXX11_ABI
+ VERIFY( strstr.rdbuf()->get_allocator() == a );
+#endif
+ VERIFY( string_view{strstr.str()} == cstr );
+ VERIFY( strstr.get() == cstr.s[0] );
+ VERIFY( strstr.put('X').rdstate() == strstr.badbit );
+ }
+ {
+ stringstream_with_alloc<alloc_type> strstr(cstr, std::ios::out, a);
+#if _GLIBCXX_USE_CXX11_ABI
+ VERIFY( strstr.rdbuf()->get_allocator() == a );
+#endif
+ VERIFY( string_view{strstr.str()} == cstr );
+ VERIFY( strstr.put('X').good() );
+ VERIFY( strstr.get() == stringstream::traits_type::eof());
+ }
+}
+
+void test04()
+{
+ {
+ stringstream strstr;
+ strstr.str( cstr );
+ VERIFY( strstr.str() == cstr.s );
+ }
+ {
+ stringstream strstr;
+ strstr.str( ccstr );
+ VERIFY( strstr.str() == ccstr.s );
+ }
+}
+
+int
+main()
+{
+ test01();
+ test02();
+ test03();
+ test04();
+}
diff --git a/libstdc++-v3/testsuite/27_io/basic_stringstream/cons/wchar_t/string_view.cc b/libstdc++-v3/testsuite/27_io/basic_stringstream/cons/wchar_t/string_view.cc
new file mode 100644
index 0000000..921c0fe
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/basic_stringstream/cons/wchar_t/string_view.cc
@@ -0,0 +1,6 @@
+// C++26 [stringstream.general]
+// { dg-do run { target c++26 } }
+
+#define C wchar_t
+#define L(a) L##a
+#include "../char/string_view.cc"
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/concat/120029.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/concat/120029.cc
new file mode 100644
index 0000000..5153d59
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/concat/120029.cc
@@ -0,0 +1,72 @@
+// { dg-do run { target c++17 } }
+
+// Bug libstdc++/120029
+// Dangling iterator usage in path::operator+=(const path& p) when this == p
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+
+namespace fs = std::filesystem;
+
+void
+test_root_dir()
+{
+ fs::path p = "/";
+ p += p;
+ p += p;
+ VERIFY( p == "////" );
+ p += p.filename();
+ VERIFY( p == "////" );
+ p += *std::prev(p.end());
+ VERIFY( p == "////" );
+}
+
+void
+test_root_name()
+{
+ fs::path p = "C:/";
+ p += p;
+ p += p;
+ VERIFY( p == "C:/C:/C:/C:/" );
+ p += p.filename();
+ VERIFY( p == "C:/C:/C:/C:/" );
+ p += *std::prev(p.end());
+ VERIFY( p == "C:/C:/C:/C:/" );
+}
+
+void
+test_filename()
+{
+ fs::path p = "file";
+ p += p;
+ p += p;
+ VERIFY( p == "filefilefilefile" );
+ p += p.filename();
+ VERIFY( p == "filefilefilefilefilefilefilefile" );
+ p += *std::prev(p.end());
+ VERIFY( p == "filefilefilefilefilefilefilefilefilefilefilefilefilefilefilefile" );
+}
+
+void
+test_multi()
+{
+ fs::path p = "/home/username/Documents/mu";
+ p += p;
+ p += p;
+ VERIFY( p == "/home/username/Documents/mu/home/username/Documents/mu/home/username/Documents/mu/home/username/Documents/mu" );
+ p += p.filename();
+ VERIFY( p == "/home/username/Documents/mu/home/username/Documents/mu/home/username/Documents/mu/home/username/Documents/mumu" );
+ p += *std::prev(p.end());
+ VERIFY( p == "/home/username/Documents/mu/home/username/Documents/mu/home/username/Documents/mu/home/username/Documents/mumumumu" );
+ auto n = std::distance(p.begin(), p.end());
+ for (int i = 0; i < n; ++i)
+ p += *std::next(p.begin(), i);
+}
+
+int main()
+{
+ test_root_dir();
+ test_root_name();
+ test_filename();
+ test_multi();
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/100334.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/100334.cc
index 018c0c9..21ff570c 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/100334.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/100334.cc
@@ -47,16 +47,17 @@ int
main()
{
// all atomic share the same waiter
-// atomics_sharing_same_waiter<char> atomics;
atomics_sharing_same_waiter<char> atomics;
for (auto& atom : atomics.a)
{
atom->store(0);
}
- auto a = &std::__detail::__waiter_pool_base::_S_for(reinterpret_cast<char *>(atomics.a[0]));
- auto b = &std::__detail::__waiter_pool_base::_S_for(reinterpret_cast<char *>(atomics.a[1]));
+#if 0
+ auto a = &std::__detail::__waitable_state::_S_state_for((void*)(atomics.a[0]));
+ auto b = &std::__detail::__waitable_state::_S_state_for((void*)(atomics.a[1]));
VERIFY( a == b );
+#endif
auto fut0 = std::async(std::launch::async, [&] { atomics.a[0]->wait(0); });
auto fut1 = std::async(std::launch::async, [&] { atomics.a[1]->wait(0); });
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_integral/wait_notify.cc b/libstdc++-v3/testsuite/29_atomics/atomic_integral/wait_notify.cc
index c7f8779..6e74f2c 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic_integral/wait_notify.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_integral/wait_notify.cc
@@ -33,12 +33,16 @@ template<typename Tp>
std::atomic<Tp> a{ Tp(1) };
VERIFY( a.load() == Tp(1) );
a.wait( Tp(0) );
+ std::atomic<bool> b{false};
std::thread t([&]
{
- a.store(Tp(0));
- a.notify_one();
+ b.store(true, std::memory_order_relaxed);
+ a.store(Tp(0));
+ a.notify_one();
});
a.wait(Tp(1));
+ // Ensure we actually waited until a.store(0) happened:
+ VERIFY( b.load(std::memory_order_relaxed) );
t.join();
}
diff --git a/libstdc++-v3/testsuite/30_threads/barrier/1.cc b/libstdc++-v3/testsuite/30_threads/barrier/1.cc
index eff8ef3..01c55d9 100644
--- a/libstdc++-v3/testsuite/30_threads/barrier/1.cc
+++ b/libstdc++-v3/testsuite/30_threads/barrier/1.cc
@@ -16,7 +16,8 @@
// <http://www.gnu.org/licenses/>.
// { dg-do compile { target c++20 } }
-// { dg-require-effective-target gthreads }
+// { dg-require-effective-target gthreads { target { ! *-*-linux* } } }
+// { dg-require-effective-target hosted }
// { dg-add-options no_pch }
#include <barrier>
diff --git a/libstdc++-v3/testsuite/30_threads/barrier/2.cc b/libstdc++-v3/testsuite/30_threads/barrier/2.cc
index e0188b3..728030b 100644
--- a/libstdc++-v3/testsuite/30_threads/barrier/2.cc
+++ b/libstdc++-v3/testsuite/30_threads/barrier/2.cc
@@ -16,7 +16,7 @@
// <http://www.gnu.org/licenses/>.
// { dg-do compile { target c++20 } }
-// { dg-require-effective-target gthreads }
+// { dg-require-effective-target gthreads { target { ! *-*-linux* } } }
// { dg-require-effective-target hosted }
// { dg-add-options no_pch }
diff --git a/libstdc++-v3/testsuite/30_threads/barrier/cons.cc b/libstdc++-v3/testsuite/30_threads/barrier/cons.cc
new file mode 100644
index 0000000..0b80514
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/barrier/cons.cc
@@ -0,0 +1,6 @@
+// { dg-do compile { target c++20 } }
+
+#include <barrier>
+
+// PR 118395 Constructor of std::barrier is not constexpr
+constinit std::barrier<> b(std::barrier<>::max());
diff --git a/libstdc++-v3/testsuite/30_threads/barrier/lwg3898.cc b/libstdc++-v3/testsuite/30_threads/barrier/lwg3898.cc
new file mode 100644
index 0000000..e3160dc
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/barrier/lwg3898.cc
@@ -0,0 +1,45 @@
+// { dg-do run { target c++20 } }
+// { dg-require-effective-target gthreads }
+
+#include <barrier>
+#include <exception>
+#include <cstdlib>
+#if !_GLIBCXX_USE_C99_STDLIB && defined _GLIBCXX_HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+void handle_terminate()
+{
+#if _GLIBCXX_USE_C99_STDLIB
+ std::_Exit(0);
+#elif defined _GLIBCXX_HAVE_UNISTD_H
+ _exit(0);
+#else
+ std::exit(0);
+#endif
+}
+
+struct F
+{
+ void operator()()
+ {
+ std::set_terminate(handle_terminate);
+ throw 1;
+ }
+};
+
+void
+test_lwg3898()
+{
+ std::barrier<F> b(1, F{});
+ // This should call the terminate handler and exit with zero status:
+ b.arrive_and_wait();
+ // Should not reach here:
+ std::abort();
+}
+
+int
+main()
+{
+ test_lwg3898();
+}
diff --git a/libstdc++-v3/testsuite/30_threads/packaged_task/cons/dangling_ref.cc b/libstdc++-v3/testsuite/30_threads/packaged_task/cons/dangling_ref.cc
index 51c6ade..8cc3f78 100644
--- a/libstdc++-v3/testsuite/30_threads/packaged_task/cons/dangling_ref.cc
+++ b/libstdc++-v3/testsuite/30_threads/packaged_task/cons/dangling_ref.cc
@@ -8,6 +8,5 @@ int f();
std::packaged_task<const int&()> task(f);
// { dg-error "dangling reference" "" { target { c++14_down } } 0 }
// { dg-error "reference to temporary" "" { target { c++14_down } } 0 }
-// { dg-error "no matching function" "" { target c++17 } 0 }
-// { dg-error "enable_if" "" { target c++17 } 0 }
// { dg-error "static assertion failed" "" { target c++17 } 0 }
+// { dg-error "note: .*std::is_invocable_r" "" { target c++17 } 0 }
diff --git a/libstdc++-v3/testsuite/30_threads/packaged_task/cons/lwg4154_neg.cc b/libstdc++-v3/testsuite/30_threads/packaged_task/cons/lwg4154_neg.cc
index 6ba1bb1..b3413c2 100644
--- a/libstdc++-v3/testsuite/30_threads/packaged_task/cons/lwg4154_neg.cc
+++ b/libstdc++-v3/testsuite/30_threads/packaged_task/cons/lwg4154_neg.cc
@@ -12,16 +12,16 @@ struct F {
// Mandates: is_invocable_r_v<R, decay_t<F>&, ArgTypes...> is true.
const F f;
-std::packaged_task<void()> p(f); // { dg-error "here" "" { target c++17 } }
-// { dg-error "static assertion failed" "" { target c++17 } 0 }
-// { dg-error "invoke_r" "" { target *-*-* } 0 }
-// { dg-prune-output "enable_if<false" }
+std::packaged_task<void()> p(f); // { dg-error "here" }
+// { dg-error "static assertion failed" "" { target *-*-* } 0 }
+// { dg-error "note: .*std::is_invocable_r_v<void, " "" { target c++17 } 0 }
// Only callable as rvalue
struct Frv {
int* operator()() && { return 0; }
};
-std::packaged_task<int*()> p2(Frv{}); // { dg-error "here" "" { target c++17 } }
+std::packaged_task<int*()> p2(Frv{}); // { dg-error "here" }
+// { dg-error "note: .*std::is_invocable_r_v<int., " "" { target c++17 } 0 }
// Only callable as non-const lvalue
struct Fnc {
diff --git a/libstdc++-v3/testsuite/30_threads/scoped_lock/requirements/typedefs.cc b/libstdc++-v3/testsuite/30_threads/scoped_lock/requirements/typedefs.cc
index 4cd07da..ba52b36 100644
--- a/libstdc++-v3/testsuite/30_threads/scoped_lock/requirements/typedefs.cc
+++ b/libstdc++-v3/testsuite/30_threads/scoped_lock/requirements/typedefs.cc
@@ -1,5 +1,4 @@
// { dg-do compile { target c++17 } }
-// { dg-require-gthreads "" }
// { dg-add-options no_pch }
// Copyright (C) 2017-2025 Free Software Foundation, Inc.
@@ -29,9 +28,30 @@
# error "Feature-test macro for scoped_lock has wrong value"
#endif
+struct BasicLockable
+{
+ BasicLockable() = default;
+ ~BasicLockable() = default;
+ void lock() { }
+ void unlock() { }
+};
+
void test01()
{
- // Check for required typedefs
- typedef std::scoped_lock<std::mutex> test_type;
- typedef test_type::mutex_type mutex_type;
+ // Check for required typedef.
+ using test_type = std::scoped_lock<BasicLockable>;
+ static_assert(std::is_same_v<test_type::mutex_type, BasicLockable>);
+}
+
+template<typename T, typename = void>
+constexpr bool has_mutex_type = false;
+
+template<typename T>
+constexpr bool has_mutex_type<T, std::void_t<typename T::mutex_type>> = true;
+
+void test02()
+{
+ // Check that typedef is absent as required.
+ using test_type = std::scoped_lock<BasicLockable, BasicLockable>;
+ static_assert(!has_mutex_type<test_type>);
}
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/1.cc b/libstdc++-v3/testsuite/30_threads/semaphore/1.cc
index ac9f97b..9472def 100644
--- a/libstdc++-v3/testsuite/30_threads/semaphore/1.cc
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/1.cc
@@ -16,6 +16,8 @@
// <http://www.gnu.org/licenses/>.
// { dg-do compile { target c++20 } }
+// { dg-require-effective-target gthreads { target { ! *-*-linux* } } }
+// { dg-require-effective-target hosted }
// { dg-add-options no_pch }
#include <semaphore>
@@ -25,3 +27,25 @@
#elif __cpp_lib_semaphore != 201907L
# error "Feature-test macro for semaphore has wrong value in <semaphore>"
#endif
+
+static_assert(std::is_same_v<std::counting_semaphore<1>,
+ std::binary_semaphore>);
+
+static_assert(! std::is_same_v<std::counting_semaphore<2>,
+ std::binary_semaphore>);
+
+static_assert(! std::is_same_v<std::counting_semaphore<>,
+ std::binary_semaphore>);
+
+// The standard permits max() to be greater than the template argument,
+// but for the current libstdc++ implementation it's always equal to it.
+static_assert(std::binary_semaphore::max() == 1);
+static_assert(std::counting_semaphore<0>::max() == 0);
+static_assert(std::counting_semaphore<2>::max() == 2);
+
+#include <limits.h>
+
+static_assert(std::counting_semaphore<INT_MAX>::max() == INT_MAX);
+static_assert(std::counting_semaphore<INT_MAX-1>::max() == INT_MAX-1);
+static_assert(std::counting_semaphore<PTRDIFF_MAX>::max() == PTRDIFF_MAX);
+static_assert(std::counting_semaphore<PTRDIFF_MAX-3>::max() == PTRDIFF_MAX-3);
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/100806.cc b/libstdc++-v3/testsuite/30_threads/semaphore/100806.cc
index c770f05..4b761ce 100644
--- a/libstdc++-v3/testsuite/30_threads/semaphore/100806.cc
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/100806.cc
@@ -12,7 +12,7 @@
#include <chrono>
#include <vector>
-std::counting_semaphore<4> semaphore{6};
+std::counting_semaphore<6> semaphore{6};
std::mutex mtx;
std::vector<std::string> results;
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/104928-2.cc b/libstdc++-v3/testsuite/30_threads/semaphore/104928-2.cc
new file mode 100644
index 0000000..7b90da8
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/104928-2.cc
@@ -0,0 +1,101 @@
+// { dg-do run { target c++20 } }
+// { dg-additional-options "-pthread" { target pthread } }
+// { dg-require-gthreads "" }
+// { dg-add-options libatomic }
+
+// Bug libstdc++/104928 - std::counting_semaphore on Linux can sleep forever
+
+#include <semaphore>
+#include <thread>
+#include <chrono>
+#include <atomic>
+
+std::binary_semaphore t1(1);
+std::binary_semaphore sem2(0);
+std::atomic<int> room1 = 0;
+int room2 = 0;
+
+std::atomic<bool> run{true};
+
+enum class AcquireKind { Acquire, Try, TryFor };
+
+template<std::ptrdiff_t N, AcquireKind Kind>
+struct Morris
+{
+ using Semaphore = std::counting_semaphore<N>;
+
+ Semaphore sem1{1};
+ Semaphore sem2{0};
+ unsigned counter = 0;
+
+ void operator()()
+ {
+ while (run)
+ {
+ room1 += 1;
+
+ acquire(sem1);
+ room2 += 1;
+ room1 -= 1;
+ if (room1 == 0)
+ sem2.release();
+ else
+ sem1.release();
+
+ acquire(sem2);
+ room2 -= 1;
+
+ // critical region
+ ++counter;
+ // end critical region
+
+ if (room2 == 0)
+ sem1.release();
+ else
+ sem2.release();
+ }
+ }
+
+ void acquire(Semaphore& sem)
+ {
+ using enum AcquireKind;
+ using namespace std::chrono;
+ if constexpr (Kind == Acquire)
+ sem.acquire();
+ else if constexpr (Kind == Try)
+ while (!sem.try_acquire()) { }
+ else if constexpr (Kind == TryFor)
+ while (!sem.try_acquire_for(1h)) { }
+ }
+};
+
+template<std::ptrdiff_t N, AcquireKind Kind>
+void
+test_morris_kind()
+{
+ Morris<N, Kind> algo;
+ std::thread t1(std::ref(algo));
+ std::thread t2(std::ref(algo));
+ std::this_thread::sleep_for(std::chrono::seconds(2));
+ run = false;
+ t1.join();
+ t2.join();
+}
+
+template<std::ptrdiff_t N>
+void
+test_morris()
+{
+ test_morris_kind<N, AcquireKind::Acquire>();
+ test_morris_kind<N, AcquireKind::Try>();
+ test_morris_kind<N, AcquireKind::TryFor>();
+}
+
+int main()
+{
+ test_morris<1>(); // std::binary_semaphore
+ test_morris<1000>(); // std::counting_semaphore that can use futex
+#if PTRDIFF_MAX > INT_MAX
+ // test_morris<PTRDIFF_MAX>(); // std::counting_semaphore that cannot use futex
+#endif
+}
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/104928.cc b/libstdc++-v3/testsuite/30_threads/semaphore/104928.cc
new file mode 100644
index 0000000..f360da9
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/104928.cc
@@ -0,0 +1,70 @@
+// { dg-do run { target c++20 } }
+// { dg-additional-options "-pthread" { target pthread } }
+// { dg-require-gthreads "" }
+// { dg-add-options libatomic }
+// { dg-options "-DSIMULATOR_TEST" { target simulator } }
+
+// Bug libstdc++/104928 - std::counting_semaphore on Linux can sleep forever
+
+#include <semaphore>
+#include <thread>
+#include <chrono>
+#include <climits>
+
+#ifdef SIMULATOR_TEST
+const int loop_count = 100;
+const int thread_count = 6;
+#else
+const int loop_count = 1000000;
+const int thread_count = 20;
+#endif
+
+template<std::ptrdiff_t N, typename Acquire>
+void
+test_acquire(Acquire acq_func)
+{
+ std::counting_semaphore<N * loop_count> s{0};
+ std::thread threads[thread_count];
+ for (int i = 0; i < thread_count; i += 2) {
+ threads[i] = std::thread([&s, &acq_func]() {
+ for (int i = 0; i < loop_count; ++i)
+ acq_func(s);
+ });
+ threads[i+1] = std::thread([&s]() {
+ for (int i = 0; i < loop_count; ++i)
+ s.release();
+ });
+ }
+ for (auto& t : threads)
+ t.join();
+}
+
+template<typename Acquire>
+void
+test_all(Acquire f)
+{
+ const int max = INT_MAX / loop_count;
+ test_acquire<max>(f); // can use futex
+#if PTRDIFF_MAX > INT_MAX
+ test_acquire<max * 10>(f); // cannot use futex
+#endif
+}
+
+int main()
+{
+ test_all([](auto& sem) { sem.acquire(); });
+
+ test_all([](auto& sem) { while (!sem.try_acquire()) { } });
+
+ using namespace std::chrono;
+
+ test_all([](auto& sem) { while (!sem.try_acquire_for(1h)) { } });
+
+ auto try_acquire_until = [](auto& sem, auto time) {
+ while (!sem.try_acquire_until(time + 1h))
+ { }
+ };
+ test_all([&](auto& sem) { try_acquire_until(sem, system_clock::now()); });
+ test_all([&](auto& sem) { try_acquire_until(sem, steady_clock::now()); });
+ test_all([&](auto& sem) { try_acquire_until(sem, utc_clock::now()); });
+}
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/2.cc b/libstdc++-v3/testsuite/30_threads/semaphore/2.cc
index 251e96a..bff747c 100644
--- a/libstdc++-v3/testsuite/30_threads/semaphore/2.cc
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/2.cc
@@ -16,6 +16,7 @@
// <http://www.gnu.org/licenses/>.
// { dg-do compile { target c++20 } }
+// { dg-require-effective-target gthreads { target { ! *-*-linux* } } }
// { dg-require-effective-target hosted }
// { dg-add-options no_pch }
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/3.cc b/libstdc++-v3/testsuite/30_threads/semaphore/3.cc
new file mode 100644
index 0000000..51b9fbb
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/3.cc
@@ -0,0 +1,19 @@
+// { dg-do compile { target *-*-*linux* } }
+// { dg-require-effective-target c++20 }
+// { dg-require-effective-target hosted }
+
+#include <semaphore>
+#include <limits.h>
+
+// on Linux these specializations all use a futex:
+static_assert(sizeof(std::counting_semaphore<0>) == sizeof(int));
+static_assert(sizeof(std::counting_semaphore<1>) == sizeof(int));
+static_assert(sizeof(std::counting_semaphore<INT_MAX>) == sizeof(int));
+static_assert(sizeof(std::counting_semaphore<>) == sizeof(int));
+
+// This will use a futex iff ptrdiff_t has 32 bits:
+static_assert(sizeof(std::counting_semaphore<PTRDIFF_MAX>) == sizeof(std::ptrdiff_t));
+
+#if PTRDIFF_MAX > INT_MAX
+static_assert(sizeof(std::counting_semaphore<INT_MAX+1LL>) == sizeof(std::ptrdiff_t));
+#endif
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/cons.cc b/libstdc++-v3/testsuite/30_threads/semaphore/cons.cc
new file mode 100644
index 0000000..790ff2e
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/cons.cc
@@ -0,0 +1,9 @@
+// { dg-do compile { target c++20 } }
+// { dg-require-effective-target gthreads { target { ! *-*-linux* } } }
+// { dg-require-effective-target hosted }
+
+#include <semaphore>
+
+// PR 110854 Constructor of std::counting_semaphore is not constexpr
+constinit std::binary_semaphore b(0);
+constinit std::counting_semaphore<5> c(2);
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/cons_neg.cc b/libstdc++-v3/testsuite/30_threads/semaphore/cons_neg.cc
new file mode 100644
index 0000000..56e27d7
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/cons_neg.cc
@@ -0,0 +1,12 @@
+// { dg-options "-D_GLIBCXX_ASSERTIONS" }
+// { dg-do run { target c++20 xfail *-*-* } }
+// { dg-require-effective-target hosted }
+// { dg-add-options libatomic }
+
+#include <semaphore>
+
+int main()
+{
+ // Preconditions: desired >= 0 is true, and desired <= max() is true.
+ std::binary_semaphore b(2);
+}
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc b/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
index 1498d38..e2680b1 100644
--- a/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value_neg.cc
@@ -16,8 +16,8 @@
// <http://www.gnu.org/licenses/>.
// { dg-do compile { target c++20 } }
-// { dg-require-effective-target pthread }
-// { dg-require-gthreads "" }
+// { dg-require-effective-target gthreads { target { ! *-*-linux* } } }
+// { dg-require-effective-target hosted }
#include <semaphore>
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/platform_try_acquire_for.cc b/libstdc++-v3/testsuite/30_threads/semaphore/platform_try_acquire_for.cc
deleted file mode 100644
index 6d90564..0000000
--- a/libstdc++-v3/testsuite/30_threads/semaphore/platform_try_acquire_for.cc
+++ /dev/null
@@ -1,9 +0,0 @@
-// { dg-options "-D_GLIBCXX_USE_POSIX_SEMAPHORE" }
-// { dg-do run { target c++20 } }
-// { dg-additional-options "-pthread" { target pthread } }
-// { dg-require-gthreads "" }
-// { dg-add-options libatomic }
-
-#include "try_acquire_for.cc"
-
-// { dg-prune-output "ignoring _GLIBCXX_USE_POSIX_SEMAPHORE" }
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
index d709126..ea7859b 100644
--- a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire.cc
@@ -17,7 +17,8 @@
// { dg-do run { target c++20 } }
// { dg-additional-options "-pthread" { target pthread } }
-// { dg-require-gthreads "" }
+// { dg-require-effective-target gthreads { target { ! *-*-linux* } } }
+// { dg-require-effective-target hosted }
// { dg-add-options libatomic }
#include <semaphore>
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
deleted file mode 100644
index cf57455..0000000
--- a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc
+++ /dev/null
@@ -1,153 +0,0 @@
-// Copyright (C) 2020-2025 Free Software Foundation, Inc.
-//
-// This file is part of the GNU ISO C++ Library. This library is free
-// software; you can redistribute it and/or modify it under the
-// terms of the GNU General Public License as published by the
-// Free Software Foundation; either version 3, or (at your option)
-// any later version.
-
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License along
-// with this library; see the file COPYING3. If not see
-// <http://www.gnu.org/licenses/>.
-
-// { dg-do run { target c++20 } }
-// { dg-additional-options "-pthread" { target pthread } }
-// { dg-require-gthreads "" }
-// { dg-add-options libatomic }
-
-#include <semaphore>
-#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
-#include <chrono>
-#include <thread>
-#include <atomic>
-#include <testsuite_hooks.h>
-
-void test01()
-{
- using namespace std::chrono_literals;
- std::__platform_semaphore s(2);
- s._M_acquire();
-
- auto const dur = 250ms;
- {
- auto const t0 = std::chrono::steady_clock::now();
- VERIFY( s._M_try_acquire_for(dur) );
- auto const diff = std::chrono::steady_clock::now() - t0;
- VERIFY( diff < dur );
- }
-
- {
- auto const t0 = std::chrono::steady_clock::now();
- VERIFY( !s._M_try_acquire_for(dur) );
- auto const diff = std::chrono::steady_clock::now() - t0;
- VERIFY( diff >= dur );
- }
-}
-
-void test02()
-{
- using namespace std::chrono_literals;
- std::__platform_semaphore s(1);
- std::atomic<int> a(0), b(0);
- std::thread t([&] {
- a.wait(0);
- auto const dur = 250ms;
- VERIFY( !s._M_try_acquire_for(dur) );
- b++;
- b.notify_one();
-
- a.wait(1);
- VERIFY( s._M_try_acquire_for(dur) );
- b++;
- b.notify_one();
- });
- t.detach();
-
- s._M_acquire();
- a++;
- a.notify_one();
- b.wait(0);
- s._M_release(1);
- a++;
- a.notify_one();
-
- b.wait(1);
-}
-
-void test03()
-{
- using namespace std::chrono_literals;
- std::__platform_semaphore s(2);
- s._M_acquire();
-
- auto const dur = 250ms;
- {
- auto const at = std::chrono::system_clock::now() + dur;
- auto const t0 = std::chrono::steady_clock::now();
- VERIFY( s._M_try_acquire_until(at) );
- auto const diff = std::chrono::steady_clock::now() - t0;
- VERIFY( diff < dur );
- }
-
- {
- auto const at = std::chrono::system_clock::now() + dur;
- auto const t0 = std::chrono::steady_clock::now();
- VERIFY( !s._M_try_acquire_until(at) );
- auto const diff = std::chrono::steady_clock::now() - t0;
- VERIFY( diff >= dur );
- }
-}
-
-void test04()
-{
- using namespace std::chrono_literals;
- std::__platform_semaphore s(1);
- std::atomic<int> a(0), b(0);
- std::thread t([&] {
- a.wait(0);
- auto const dur = 250ms;
- {
- auto const at = std::chrono::system_clock::now() + dur;
- VERIFY( !s._M_try_acquire_until(at) );
-
- b++;
- b.notify_one();
- }
-
- a.wait(1);
- {
- auto const at = std::chrono::system_clock::now() + dur;
- VERIFY( s._M_try_acquire_until(at) );
- }
- b++;
- b.notify_one();
- });
- t.detach();
-
- s._M_acquire();
- a++;
- a.notify_one();
- b.wait(0);
- s._M_release(1);
- a++;
- a.notify_one();
-
- b.wait(1);
-}
-#endif
-
-int main()
-{
-#ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
- test01();
- test02();
- test03();
- test04();
-#endif
- return 0;
-}
diff --git a/libstdc++-v3/testsuite/30_threads/thread/id/output.cc b/libstdc++-v3/testsuite/30_threads/thread/id/output.cc
index 94a6ff0..3d1dd38 100644
--- a/libstdc++-v3/testsuite/30_threads/thread/id/output.cc
+++ b/libstdc++-v3/testsuite/30_threads/thread/id/output.cc
@@ -118,8 +118,38 @@ test02()
VERIFY( ws1.length() == len );
#endif
+ out.str("");
+ out << i;
+ s1 = out.str();
+ len = s1.size();
+ out.str("");
+
+ // with width
+ s2 = std::format("{0:{1}}", i, len + 2);
+ VERIFY( s2 == (" " + s1) );
+ // with align + width
+ s2 = std::format("{0:>{1}}", i, len + 2);
+ VERIFY( s2 == (" " + s1) );
+ s2 = std::format("{0:<{1}}", i, len + 2);
+ VERIFY( s2 == (s1 + " ") );
+ // with fill-and-align + width
+ s2 = std::format("{0:x^{1}}", i, len + 5);
+ VERIFY( s2 == ("xx" + s1 + "xxx") );
+
+#ifdef _GLIBCXX_USE_WCHAR_T
+ static_assert( std::is_default_constructible_v<std::formatter<std::thread::id, wchar_t>> );
+ ws1 = std::format(L"{}", i);
+ VERIFY( ws1.length() == len );
+#endif
+
t1.join();
t2.join();
+
+ static_assert( std::formattable<std::thread::id, char> );
+ static_assert( std::formattable<std::thread::id, wchar_t> );
+ static_assert( !std::formattable<std::thread::id, char16_t> );
+ static_assert( !std::formattable<std::thread::id, int> );
+
#elif __cplusplus >= 202302L
# error "Feature-test macro for formatters has wrong value in <thread>"
#endif
diff --git a/libstdc++-v3/testsuite/experimental/filesystem/path/concat/120029.cc b/libstdc++-v3/testsuite/experimental/filesystem/path/concat/120029.cc
new file mode 100644
index 0000000..209d968
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/filesystem/path/concat/120029.cc
@@ -0,0 +1,74 @@
+// { dg-options "-DUSE_FILESYSTEM_TS -lstdc++fs" }
+// { dg-do run { target c++11 } }
+// { dg-require-filesystem-ts "" }
+
+// Bug libstdc++/120029
+// Dangling iterator usage in path::operator+=(const path& p) when this == p
+
+#include <experimental/filesystem>
+#include <testsuite_hooks.h>
+
+namespace fs = std::experimental::filesystem;
+
+void
+test_root_dir()
+{
+ fs::path p = "/";
+ p += p;
+ p += p;
+ VERIFY( p == "////" );
+ p += p.filename();
+ VERIFY( p == "////////" );
+ p += *std::prev(p.end());
+ VERIFY( p == "////////////////" );
+}
+
+void
+test_root_name()
+{
+ fs::path p = "C:/";
+ p += p;
+ p += p;
+ VERIFY( p == "C:/C:/C:/C:/" );
+ p += p.filename(); // For Filesystem TS the filename is "."
+ VERIFY( p == "C:/C:/C:/C:/." );
+ p += *std::prev(p.end());
+ VERIFY( p == "C:/C:/C:/C:/.." );
+}
+
+void
+test_filename()
+{
+ fs::path p = "file";
+ p += p;
+ p += p;
+ VERIFY( p == "filefilefilefile" );
+ p += p.filename();
+ VERIFY( p == "filefilefilefilefilefilefilefile" );
+ p += *std::prev(p.end());
+ VERIFY( p == "filefilefilefilefilefilefilefilefilefilefilefilefilefilefilefile" );
+}
+
+void
+test_multi()
+{
+ fs::path p = "/home/username/Documents/mu";
+ p += p;
+ p += p;
+ VERIFY( p == "/home/username/Documents/mu/home/username/Documents/mu/home/username/Documents/mu/home/username/Documents/mu" );
+ p += p.filename();
+ VERIFY( p == "/home/username/Documents/mu/home/username/Documents/mu/home/username/Documents/mu/home/username/Documents/mumu" );
+ p += *std::prev(p.end());
+ VERIFY( p == "/home/username/Documents/mu/home/username/Documents/mu/home/username/Documents/mu/home/username/Documents/mumumumu" );
+ auto n = std::distance(p.begin(), p.end());
+ for (int i = 0; i < n; ++i)
+ p += *std::next(p.begin(), i);
+}
+
+int main()
+{
+ test_root_dir();
+ test_root_name();
+ test_filename();
+ test_multi();
+}
diff --git a/libstdc++-v3/testsuite/experimental/names.cc b/libstdc++-v3/testsuite/experimental/names.cc
index e0a7d4f..94ae76f 100644
--- a/libstdc++-v3/testsuite/experimental/names.cc
+++ b/libstdc++-v3/testsuite/experimental/names.cc
@@ -22,6 +22,12 @@
// naming variables, parameters etc. in the library.
#include "../17_intro/names.cc"
+
+#ifdef _AIX
+// <netdb.h> declares endnetgrent_r with ptr parameter.
+# undef ptr
+#endif
+
// Filesystem
#if __has_include(<experimental/filesystem>)
# include <experimental/filesystem>
diff --git a/libstdc++-v3/testsuite/experimental/net/buffer/arithmetic.cc b/libstdc++-v3/testsuite/experimental/net/buffer/arithmetic.cc
index 04b3c93..483d01f 100644
--- a/libstdc++-v3/testsuite/experimental/net/buffer/arithmetic.cc
+++ b/libstdc++-v3/testsuite/experimental/net/buffer/arithmetic.cc
@@ -26,7 +26,6 @@ using std::experimental::net::const_buffer;
void
test01()
{
- bool test __attribute__((unused)) = false;
char c[4];
mutable_buffer mb;
@@ -64,7 +63,6 @@ test01()
void
test02()
{
- bool test __attribute__((unused)) = false;
char c[4];
const_buffer cb;
diff --git a/libstdc++-v3/testsuite/experimental/net/buffer/const.cc b/libstdc++-v3/testsuite/experimental/net/buffer/const.cc
index c6adae6..4310c28 100644
--- a/libstdc++-v3/testsuite/experimental/net/buffer/const.cc
+++ b/libstdc++-v3/testsuite/experimental/net/buffer/const.cc
@@ -50,7 +50,6 @@ test01()
void
test02()
{
- bool test __attribute__((unused)) = false;
char c[4];
const_buffer b;
diff --git a/libstdc++-v3/testsuite/experimental/net/buffer/mutable.cc b/libstdc++-v3/testsuite/experimental/net/buffer/mutable.cc
index 9f0d7d4..06a848c 100644
--- a/libstdc++-v3/testsuite/experimental/net/buffer/mutable.cc
+++ b/libstdc++-v3/testsuite/experimental/net/buffer/mutable.cc
@@ -47,7 +47,6 @@ test01()
void
test02()
{
- bool test __attribute__((unused)) = false;
char c[4];
mutable_buffer b;
diff --git a/libstdc++-v3/testsuite/experimental/net/buffer/size.cc b/libstdc++-v3/testsuite/experimental/net/buffer/size.cc
index 4592a19..7d5f339 100644
--- a/libstdc++-v3/testsuite/experimental/net/buffer/size.cc
+++ b/libstdc++-v3/testsuite/experimental/net/buffer/size.cc
@@ -26,7 +26,6 @@ using std::experimental::net::mutable_buffer;
void
test01()
{
- bool test __attribute__((unused)) = false;
char c[4];
mutable_buffer mb;
@@ -44,7 +43,6 @@ test01()
void
test02()
{
- bool test __attribute__((unused)) = false;
char c[32];
std::vector<mutable_buffer> mv{ {c, 0}, {c, 32}, {c, 16}, {c, 3}, {c, 0} };
diff --git a/libstdc++-v3/testsuite/experimental/net/timer/waitable/cons.cc b/libstdc++-v3/testsuite/experimental/net/timer/waitable/cons.cc
index 6da7528..e394ec8 100644
--- a/libstdc++-v3/testsuite/experimental/net/timer/waitable/cons.cc
+++ b/libstdc++-v3/testsuite/experimental/net/timer/waitable/cons.cc
@@ -27,8 +27,6 @@ using std::experimental::net::io_context;
void
test01()
{
- bool test __attribute__((unused)) = false;
-
io_context ctx1, ctx2;
system_timer timer1(ctx1);
@@ -54,8 +52,6 @@ test01()
void
test02()
{
- bool test __attribute__((unused)) = false;
-
io_context ctx1, ctx2;
auto t1 = system_timer::clock_type::now();
auto t2 = t1 + system_timer::duration(10);
@@ -83,8 +79,6 @@ test02()
void
test03()
{
- bool test __attribute__((unused)) = false;
-
io_context ctx1, ctx2;
auto now = system_timer::clock_type::now();
auto d1 = system_timer::duration(10);
diff --git a/libstdc++-v3/testsuite/experimental/net/timer/waitable/dest.cc b/libstdc++-v3/testsuite/experimental/net/timer/waitable/dest.cc
index d384a67..ef458bd 100644
--- a/libstdc++-v3/testsuite/experimental/net/timer/waitable/dest.cc
+++ b/libstdc++-v3/testsuite/experimental/net/timer/waitable/dest.cc
@@ -28,8 +28,6 @@ using std::experimental::net::io_context;
void
test01()
{
- bool test __attribute__((unused)) = false;
-
std::error_code ec;
io_context ctx;
diff --git a/libstdc++-v3/testsuite/experimental/net/timer/waitable/ops.cc b/libstdc++-v3/testsuite/experimental/net/timer/waitable/ops.cc
index 82c05c0..ff0b800 100644
--- a/libstdc++-v3/testsuite/experimental/net/timer/waitable/ops.cc
+++ b/libstdc++-v3/testsuite/experimental/net/timer/waitable/ops.cc
@@ -29,8 +29,6 @@ using std::error_code;
void
test01()
{
- bool test __attribute__((unused)) = false;
-
io_context ctx;
error_code ec;
bool complete = false;
@@ -57,8 +55,6 @@ test01()
void
test02()
{
- bool test __attribute__((unused)) = false;
-
io_context ctx;
error_code ec1, ec2;
diff --git a/libstdc++-v3/testsuite/ext/special_functions/airy_ai/check_value.cc b/libstdc++-v3/testsuite/ext/special_functions/airy_ai/check_value.cc
index 7ff005b..6e8e36b 100644
--- a/libstdc++-v3/testsuite/ext/special_functions/airy_ai/check_value.cc
+++ b/libstdc++-v3/testsuite/ext/special_functions/airy_ai/check_value.cc
@@ -96,7 +96,6 @@ template<typename Ret, unsigned int Num>
void
test(const testcase_airy_ai<Ret> (&data)[Num], Ret toler)
{
- bool test __attribute__((unused)) = true;
const Ret eps = std::numeric_limits<Ret>::epsilon();
Ret max_abs_diff = -Ret(1);
Ret max_abs_frac = -Ret(1);
diff --git a/libstdc++-v3/testsuite/ext/special_functions/airy_bi/check_value.cc b/libstdc++-v3/testsuite/ext/special_functions/airy_bi/check_value.cc
index 0afefdd..6fcad83 100644
--- a/libstdc++-v3/testsuite/ext/special_functions/airy_bi/check_value.cc
+++ b/libstdc++-v3/testsuite/ext/special_functions/airy_bi/check_value.cc
@@ -96,7 +96,6 @@ template<typename Ret, unsigned int Num>
void
test(const testcase_airy_bi<Ret> (&data)[Num], Ret toler)
{
- bool test __attribute__((unused)) = true;
const Ret eps = std::numeric_limits<Ret>::epsilon();
Ret max_abs_diff = -Ret(1);
Ret max_abs_frac = -Ret(1);
diff --git a/libstdc++-v3/testsuite/ext/special_functions/conf_hyperg/check_value.cc b/libstdc++-v3/testsuite/ext/special_functions/conf_hyperg/check_value.cc
index 1227361..a050f62 100644
--- a/libstdc++-v3/testsuite/ext/special_functions/conf_hyperg/check_value.cc
+++ b/libstdc++-v3/testsuite/ext/special_functions/conf_hyperg/check_value.cc
@@ -3820,7 +3820,6 @@ template<typename Ret, unsigned int Num>
void
test(const testcase_conf_hyperg<Ret> (&data)[Num], Ret toler)
{
- bool test __attribute__((unused)) = true;
const Ret eps = std::numeric_limits<Ret>::epsilon();
Ret max_abs_diff = -Ret(1);
Ret max_abs_frac = -Ret(1);
diff --git a/libstdc++-v3/testsuite/ext/special_functions/hyperg/check_value.cc b/libstdc++-v3/testsuite/ext/special_functions/hyperg/check_value.cc
index 8e0c57f..b658684 100644
--- a/libstdc++-v3/testsuite/ext/special_functions/hyperg/check_value.cc
+++ b/libstdc++-v3/testsuite/ext/special_functions/hyperg/check_value.cc
@@ -12293,7 +12293,6 @@ template<typename Ret, unsigned int Num>
void
test(const testcase_hyperg<Ret> (&data)[Num], Ret toler)
{
- bool test __attribute__((unused)) = true;
const Ret eps = std::numeric_limits<Ret>::epsilon();
Ret max_abs_diff = -Ret(1);
Ret max_abs_frac = -Ret(1);
diff --git a/libstdc++-v3/testsuite/lib/libstdc++.exp b/libstdc++-v3/testsuite/lib/libstdc++.exp
index 3c34d18..9f2dd8a 100644
--- a/libstdc++-v3/testsuite/lib/libstdc++.exp
+++ b/libstdc++-v3/testsuite/lib/libstdc++.exp
@@ -586,6 +586,7 @@ proc v3_target_compile { source dest type options } {
global tool
lappend options "additional_flags=-fdiagnostics-plain-output"
+ lappend options "additional_flags=-Wabi=20";
if { [target_info needs_status_wrapper] != "" && [info exists gluefile] } {
lappend options "libs=${gluefile}"
@@ -648,6 +649,11 @@ proc v3_target_compile { source dest type options } {
set v3_additional_files {}
set comp_output [target_compile $source $dest $type $options]
+
+ # Strip versioned namespace from the compiler output,
+ # so that dg-error and dg-warning patterns can ignore it:
+ regsub -all "std::__8::" $comp_output "std::" comp_output
+
if { $type == "executable" && $file_to_delete != "" } {
file delete $file_to_delete
if { [istarget *-*-darwin*] && [file exists $file_to_delete.dSYM] } {
@@ -1013,8 +1019,8 @@ proc check_v3_target_time { } {
}]
}
-proc check_v3_target_namedlocale { args } {
- set key "et_namedlocale $args"
+proc check_v3_target_namedlocale { locale } {
+ set key "et_namedlocale $locale"
return [check_v3_target_prop_cached $key {
global tool
# Set up, compile, and execute a C++ test program that tries to use
@@ -1029,7 +1035,7 @@ proc check_v3_target_namedlocale { args } {
puts $f "using namespace std;"
puts $f "char *transform_locale(const char *name)"
puts $f "{"
- puts $f " char *result = new char\[50\];"
+ puts $f " char *result = new char\[strlen(name)+6\];"
puts $f " strcpy(result, name);"
puts $f "#if defined __FreeBSD__ || defined __DragonFly__ || defined __NetBSD__"
puts $f " /* fall-through */"
@@ -1040,14 +1046,9 @@ proc check_v3_target_namedlocale { args } {
puts $f "#endif"
puts $f " return result;"
puts $f "}"
- puts $f "int main (int argc, char** argv)"
+ puts $f "int main ()"
puts $f "{"
- puts $f " if (argc < 2)"
- puts $f " {"
- puts $f " printf(\"locale support test not supported\\n\");"
- puts $f " return 1;"
- puts $f " }"
- puts $f " const char *namedloc = transform_locale(*(argv + 1));"
+ puts $f " const char *namedloc = transform_locale(\"$locale\");"
puts $f " try"
puts $f " {"
puts $f " locale((const char*)namedloc);"
@@ -1071,10 +1072,10 @@ proc check_v3_target_namedlocale { args } {
return 0
}
- set result [${tool}_load "./$exe" "$args" ""]
+ set result [${tool}_load "./$exe" "" ""]
set status [lindex $result 0]
- verbose "check_v3_target_namedlocale <$args>: status is <$status>" 2
+ verbose "check_v3_target_namedlocale <$locale>: status is <$status>" 2
if { $status == "pass" } {
return 1
diff --git a/libstdc++-v3/testsuite/lib/prune.exp b/libstdc++-v3/testsuite/lib/prune.exp
index 416e851..a9a2993 100644
--- a/libstdc++-v3/testsuite/lib/prune.exp
+++ b/libstdc++-v3/testsuite/lib/prune.exp
@@ -77,6 +77,9 @@ proc libstdc++-dg-prune { system text } {
# Ignore harmless warnings from Xcode 4+.
regsub -all "(^|\n)\[^\n\]*ld: warning: could not create compact unwind for\[^\n\]*" $text "" text
+ # Ignore duplicate path warnings from Xcode 16+.
+ regsub -all "(^|\n)\[^\n\]*ld: warning: duplicate -rpath\[^\n\]*" $text "" text
+
# Ignore dsymutil warning (tool bug is actually in the linker)
regsub -all "(^|\n)\[^\n\]*could not find object file symbol for symbol\[^\n\]*" $text "" text
diff --git a/libstdc++-v3/testsuite/special_functions/01_assoc_laguerre/check_value.cc b/libstdc++-v3/testsuite/special_functions/01_assoc_laguerre/check_value.cc
index 4e40f0f..90d7d36 100644
--- a/libstdc++-v3/testsuite/special_functions/01_assoc_laguerre/check_value.cc
+++ b/libstdc++-v3/testsuite/special_functions/01_assoc_laguerre/check_value.cc
@@ -2217,7 +2217,6 @@ template<typename Ret, unsigned int Num>
void
test(const testcase_assoc_laguerre<Ret> (&data)[Num], Ret toler)
{
- bool test __attribute__((unused)) = true;
const Ret eps = std::numeric_limits<Ret>::epsilon();
Ret max_abs_diff = -Ret(1);
Ret max_abs_frac = -Ret(1);
diff --git a/libstdc++-v3/testsuite/special_functions/02_assoc_legendre/check_value.cc b/libstdc++-v3/testsuite/special_functions/02_assoc_legendre/check_value.cc
index b54e59e..54ae51d 100644
--- a/libstdc++-v3/testsuite/special_functions/02_assoc_legendre/check_value.cc
+++ b/libstdc++-v3/testsuite/special_functions/02_assoc_legendre/check_value.cc
@@ -1985,7 +1985,6 @@ template<typename Ret, unsigned int Num>
void
test(const testcase_assoc_legendre<Ret> (&data)[Num], Ret toler)
{
- bool test __attribute__((unused)) = true;
const Ret eps = std::numeric_limits<Ret>::epsilon();
Ret max_abs_diff = -Ret(1);
Ret max_abs_frac = -Ret(1);
diff --git a/libstdc++-v3/testsuite/special_functions/02_assoc_legendre/pr86655.cc b/libstdc++-v3/testsuite/special_functions/02_assoc_legendre/pr86655.cc
index 9d6507a..cbd7c51 100644
--- a/libstdc++-v3/testsuite/special_functions/02_assoc_legendre/pr86655.cc
+++ b/libstdc++-v3/testsuite/special_functions/02_assoc_legendre/pr86655.cc
@@ -37,7 +37,6 @@ template<typename _Tp>
void
test_m_gt_l()
{
- bool test __attribute__((unused)) = true;
for (auto l : {0u, 1u, 2u, 5u})
for (auto m : {l + 1u, l + 2u})
for (auto i : {-2, -1, 0, 1, 2})
diff --git a/libstdc++-v3/testsuite/special_functions/03_beta/check_value.cc b/libstdc++-v3/testsuite/special_functions/03_beta/check_value.cc
index 24f5033..e5e85a5 100644
--- a/libstdc++-v3/testsuite/special_functions/03_beta/check_value.cc
+++ b/libstdc++-v3/testsuite/special_functions/03_beta/check_value.cc
@@ -261,7 +261,6 @@ template<typename Ret, unsigned int Num>
void
test(const testcase_beta<Ret> (&data)[Num], Ret toler)
{
- bool test __attribute__((unused)) = true;
const Ret eps = std::numeric_limits<Ret>::epsilon();
Ret max_abs_diff = -Ret(1);
Ret max_abs_frac = -Ret(1);
diff --git a/libstdc++-v3/testsuite/special_functions/04_comp_ellint_1/check_value.cc b/libstdc++-v3/testsuite/special_functions/04_comp_ellint_1/check_value.cc
index efa7d5a..c109410 100644
--- a/libstdc++-v3/testsuite/special_functions/04_comp_ellint_1/check_value.cc
+++ b/libstdc++-v3/testsuite/special_functions/04_comp_ellint_1/check_value.cc
@@ -73,7 +73,6 @@ template<typename Ret, unsigned int Num>
void
test(const testcase_comp_ellint_1<Ret> (&data)[Num], Ret toler)
{
- bool test __attribute__((unused)) = true;
const Ret eps = std::numeric_limits<Ret>::epsilon();
Ret max_abs_diff = -Ret(1);
Ret max_abs_frac = -Ret(1);
diff --git a/libstdc++-v3/testsuite/special_functions/05_comp_ellint_2/check_value.cc b/libstdc++-v3/testsuite/special_functions/05_comp_ellint_2/check_value.cc
index 8c77daf..6a5d14d 100644
--- a/libstdc++-v3/testsuite/special_functions/05_comp_ellint_2/check_value.cc
+++ b/libstdc++-v3/testsuite/special_functions/05_comp_ellint_2/check_value.cc
@@ -73,7 +73,6 @@ template<typename Ret, unsigned int Num>
void
test(const testcase_comp_ellint_2<Ret> (&data)[Num], Ret toler)
{
- bool test __attribute__((unused)) = true;
const Ret eps = std::numeric_limits<Ret>::epsilon();
Ret max_abs_diff = -Ret(1);
Ret max_abs_frac = -Ret(1);
diff --git a/libstdc++-v3/testsuite/special_functions/06_comp_ellint_3/check_value.cc b/libstdc++-v3/testsuite/special_functions/06_comp_ellint_3/check_value.cc
index 8a74415..df544b5 100644
--- a/libstdc++-v3/testsuite/special_functions/06_comp_ellint_3/check_value.cc
+++ b/libstdc++-v3/testsuite/special_functions/06_comp_ellint_3/check_value.cc
@@ -459,7 +459,6 @@ template<typename Ret, unsigned int Num>
void
test(const testcase_comp_ellint_3<Ret> (&data)[Num], Ret toler)
{
- bool test __attribute__((unused)) = true;
const Ret eps = std::numeric_limits<Ret>::epsilon();
Ret max_abs_diff = -Ret(1);
Ret max_abs_frac = -Ret(1);
diff --git a/libstdc++-v3/testsuite/special_functions/07_cyl_bessel_i/check_value.cc b/libstdc++-v3/testsuite/special_functions/07_cyl_bessel_i/check_value.cc
index ab182c1..a379bed 100644
--- a/libstdc++-v3/testsuite/special_functions/07_cyl_bessel_i/check_value.cc
+++ b/libstdc++-v3/testsuite/special_functions/07_cyl_bessel_i/check_value.cc
@@ -702,7 +702,6 @@ template<typename Ret, unsigned int Num>
void
test(const testcase_cyl_bessel_i<Ret> (&data)[Num], Ret toler)
{
- bool test __attribute__((unused)) = true;
const Ret eps = std::numeric_limits<Ret>::epsilon();
Ret max_abs_diff = -Ret(1);
Ret max_abs_frac = -Ret(1);
diff --git a/libstdc++-v3/testsuite/special_functions/08_cyl_bessel_j/check_value.cc b/libstdc++-v3/testsuite/special_functions/08_cyl_bessel_j/check_value.cc
index a99e1e7..e09ae3d 100644
--- a/libstdc++-v3/testsuite/special_functions/08_cyl_bessel_j/check_value.cc
+++ b/libstdc++-v3/testsuite/special_functions/08_cyl_bessel_j/check_value.cc
@@ -735,7 +735,6 @@ template<typename Ret, unsigned int Num>
void
test(const testcase_cyl_bessel_j<Ret> (&data)[Num], Ret toler)
{
- bool test __attribute__((unused)) = true;
const Ret eps = std::numeric_limits<Ret>::epsilon();
Ret max_abs_diff = -Ret(1);
Ret max_abs_frac = -Ret(1);
diff --git a/libstdc++-v3/testsuite/special_functions/09_cyl_bessel_k/check_value.cc b/libstdc++-v3/testsuite/special_functions/09_cyl_bessel_k/check_value.cc
index 5e6804e..ce5abcc 100644
--- a/libstdc++-v3/testsuite/special_functions/09_cyl_bessel_k/check_value.cc
+++ b/libstdc++-v3/testsuite/special_functions/09_cyl_bessel_k/check_value.cc
@@ -746,7 +746,6 @@ template<typename Ret, unsigned int Num>
void
test(const testcase_cyl_bessel_k<Ret> (&data)[Num], Ret toler)
{
- bool test __attribute__((unused)) = true;
const Ret eps = std::numeric_limits<Ret>::epsilon();
Ret max_abs_diff = -Ret(1);
Ret max_abs_frac = -Ret(1);
diff --git a/libstdc++-v3/testsuite/special_functions/10_cyl_neumann/check_value.cc b/libstdc++-v3/testsuite/special_functions/10_cyl_neumann/check_value.cc
index 30c8a34..d934377 100644
--- a/libstdc++-v3/testsuite/special_functions/10_cyl_neumann/check_value.cc
+++ b/libstdc++-v3/testsuite/special_functions/10_cyl_neumann/check_value.cc
@@ -779,7 +779,6 @@ template<typename Ret, unsigned int Num>
void
test(const testcase_cyl_neumann<Ret> (&data)[Num], Ret toler)
{
- bool test __attribute__((unused)) = true;
const Ret eps = std::numeric_limits<Ret>::epsilon();
Ret max_abs_diff = -Ret(1);
Ret max_abs_frac = -Ret(1);
diff --git a/libstdc++-v3/testsuite/special_functions/11_ellint_1/check_value.cc b/libstdc++-v3/testsuite/special_functions/11_ellint_1/check_value.cc
index c8bad36..2d6a3c5 100644
--- a/libstdc++-v3/testsuite/special_functions/11_ellint_1/check_value.cc
+++ b/libstdc++-v3/testsuite/special_functions/11_ellint_1/check_value.cc
@@ -459,7 +459,6 @@ template<typename Ret, unsigned int Num>
void
test(const testcase_ellint_1<Ret> (&data)[Num], Ret toler)
{
- bool test __attribute__((unused)) = true;
const Ret eps = std::numeric_limits<Ret>::epsilon();
Ret max_abs_diff = -Ret(1);
Ret max_abs_frac = -Ret(1);
diff --git a/libstdc++-v3/testsuite/special_functions/12_ellint_2/check_value.cc b/libstdc++-v3/testsuite/special_functions/12_ellint_2/check_value.cc
index fc971e6..0bbd7bb 100644
--- a/libstdc++-v3/testsuite/special_functions/12_ellint_2/check_value.cc
+++ b/libstdc++-v3/testsuite/special_functions/12_ellint_2/check_value.cc
@@ -459,7 +459,6 @@ template<typename Ret, unsigned int Num>
void
test(const testcase_ellint_2<Ret> (&data)[Num], Ret toler)
{
- bool test __attribute__((unused)) = true;
const Ret eps = std::numeric_limits<Ret>::epsilon();
Ret max_abs_diff = -Ret(1);
Ret max_abs_frac = -Ret(1);
diff --git a/libstdc++-v3/testsuite/special_functions/13_ellint_3/check_value.cc b/libstdc++-v3/testsuite/special_functions/13_ellint_3/check_value.cc
index f46d8a5..bb1b4c1 100644
--- a/libstdc++-v3/testsuite/special_functions/13_ellint_3/check_value.cc
+++ b/libstdc++-v3/testsuite/special_functions/13_ellint_3/check_value.cc
@@ -6121,7 +6121,6 @@ template<typename Ret, unsigned int Num>
void
test(const testcase_ellint_3<Ret> (&data)[Num], Ret toler)
{
- bool test __attribute__((unused)) = true;
const Ret eps = std::numeric_limits<Ret>::epsilon();
Ret max_abs_diff = -Ret(1);
Ret max_abs_frac = -Ret(1);
diff --git a/libstdc++-v3/testsuite/special_functions/14_expint/check_value.cc b/libstdc++-v3/testsuite/special_functions/14_expint/check_value.cc
index 6bf060a..92e9714 100644
--- a/libstdc++-v3/testsuite/special_functions/14_expint/check_value.cc
+++ b/libstdc++-v3/testsuite/special_functions/14_expint/check_value.cc
@@ -168,7 +168,6 @@ template<typename Ret, unsigned int Num>
void
test(const testcase_expint<Ret> (&data)[Num], Ret toler)
{
- bool test __attribute__((unused)) = true;
const Ret eps = std::numeric_limits<Ret>::epsilon();
Ret max_abs_diff = -Ret(1);
Ret max_abs_frac = -Ret(1);
diff --git a/libstdc++-v3/testsuite/special_functions/15_hermite/check_value.cc b/libstdc++-v3/testsuite/special_functions/15_hermite/check_value.cc
index a16073a..419fcb0 100644
--- a/libstdc++-v3/testsuite/special_functions/15_hermite/check_value.cc
+++ b/libstdc++-v3/testsuite/special_functions/15_hermite/check_value.cc
@@ -1904,7 +1904,6 @@ template<typename Ret, unsigned int Num>
void
test(const testcase_hermite<Ret> (&data)[Num], Ret toler)
{
- bool test __attribute__((unused)) = true;
const Ret eps = std::numeric_limits<Ret>::epsilon();
Ret max_abs_diff = -Ret(1);
Ret max_abs_frac = -Ret(1);
diff --git a/libstdc++-v3/testsuite/special_functions/16_laguerre/check_value.cc b/libstdc++-v3/testsuite/special_functions/16_laguerre/check_value.cc
index 89b9c94..03c6496 100644
--- a/libstdc++-v3/testsuite/special_functions/16_laguerre/check_value.cc
+++ b/libstdc++-v3/testsuite/special_functions/16_laguerre/check_value.cc
@@ -305,7 +305,6 @@ template<typename Ret, unsigned int Num>
void
test(const testcase_laguerre<Ret> (&data)[Num], Ret toler)
{
- bool test __attribute__((unused)) = true;
const Ret eps = std::numeric_limits<Ret>::epsilon();
Ret max_abs_diff = -Ret(1);
Ret max_abs_frac = -Ret(1);
diff --git a/libstdc++-v3/testsuite/special_functions/17_legendre/check_value.cc b/libstdc++-v3/testsuite/special_functions/17_legendre/check_value.cc
index b2c0077..7bfb98c 100644
--- a/libstdc++-v3/testsuite/special_functions/17_legendre/check_value.cc
+++ b/libstdc++-v3/testsuite/special_functions/17_legendre/check_value.cc
@@ -305,7 +305,6 @@ template<typename Ret, unsigned int Num>
void
test(const testcase_legendre<Ret> (&data)[Num], Ret toler)
{
- bool test __attribute__((unused)) = true;
const Ret eps = std::numeric_limits<Ret>::epsilon();
Ret max_abs_diff = -Ret(1);
Ret max_abs_frac = -Ret(1);
diff --git a/libstdc++-v3/testsuite/special_functions/18_riemann_zeta/check_value.cc b/libstdc++-v3/testsuite/special_functions/18_riemann_zeta/check_value.cc
index 1967bf7..c8589ff 100644
--- a/libstdc++-v3/testsuite/special_functions/18_riemann_zeta/check_value.cc
+++ b/libstdc++-v3/testsuite/special_functions/18_riemann_zeta/check_value.cc
@@ -273,7 +273,6 @@ template<typename Ret, unsigned int Num>
void
test(const testcase_riemann_zeta<Ret> (&data)[Num], Ret toler)
{
- bool test __attribute__((unused)) = true;
const Ret eps = std::numeric_limits<Ret>::epsilon();
Ret max_abs_diff = -Ret(1);
Ret max_abs_frac = -Ret(1);
diff --git a/libstdc++-v3/testsuite/special_functions/19_sph_bessel/check_value.cc b/libstdc++-v3/testsuite/special_functions/19_sph_bessel/check_value.cc
index 8116ac4..658a13b 100644
--- a/libstdc++-v3/testsuite/special_functions/19_sph_bessel/check_value.cc
+++ b/libstdc++-v3/testsuite/special_functions/19_sph_bessel/check_value.cc
@@ -504,7 +504,6 @@ template<typename Ret, unsigned int Num>
void
test(const testcase_sph_bessel<Ret> (&data)[Num], Ret toler)
{
- bool test __attribute__((unused)) = true;
const Ret eps = std::numeric_limits<Ret>::epsilon();
Ret max_abs_diff = -Ret(1);
Ret max_abs_frac = -Ret(1);
diff --git a/libstdc++-v3/testsuite/special_functions/20_sph_legendre/check_value.cc b/libstdc++-v3/testsuite/special_functions/20_sph_legendre/check_value.cc
index df417e6..5783ca9 100644
--- a/libstdc++-v3/testsuite/special_functions/20_sph_legendre/check_value.cc
+++ b/libstdc++-v3/testsuite/special_functions/20_sph_legendre/check_value.cc
@@ -1985,7 +1985,6 @@ template<typename Ret, unsigned int Num>
void
test(const testcase_sph_legendre<Ret> (&data)[Num], Ret toler)
{
- bool test __attribute__((unused)) = true;
const Ret eps = std::numeric_limits<Ret>::epsilon();
Ret max_abs_diff = -Ret(1);
Ret max_abs_frac = -Ret(1);
diff --git a/libstdc++-v3/testsuite/special_functions/20_sph_legendre/pr86655.cc b/libstdc++-v3/testsuite/special_functions/20_sph_legendre/pr86655.cc
index e397371..80809ee 100644
--- a/libstdc++-v3/testsuite/special_functions/20_sph_legendre/pr86655.cc
+++ b/libstdc++-v3/testsuite/special_functions/20_sph_legendre/pr86655.cc
@@ -37,7 +37,6 @@ template<typename _Tp>
void
test_m_gt_l()
{
- bool test __attribute__((unused)) = true;
for (auto l : {0u, 1u, 2u, 5u})
for (auto m : {l + 1u, l + 2u})
for (auto i : {-2, -1, 0, 1, 2})
diff --git a/libstdc++-v3/testsuite/special_functions/21_sph_neumann/check_value.cc b/libstdc++-v3/testsuite/special_functions/21_sph_neumann/check_value.cc
index 372ca39..c9873b6 100644
--- a/libstdc++-v3/testsuite/special_functions/21_sph_neumann/check_value.cc
+++ b/libstdc++-v3/testsuite/special_functions/21_sph_neumann/check_value.cc
@@ -554,7 +554,6 @@ template<typename Ret, unsigned int Num>
void
test(const testcase_sph_neumann<Ret> (&data)[Num], Ret toler)
{
- bool test __attribute__((unused)) = true;
const Ret eps = std::numeric_limits<Ret>::epsilon();
Ret max_abs_diff = -Ret(1);
Ret max_abs_frac = -Ret(1);
diff --git a/libstdc++-v3/testsuite/std/format/arguments/args.cc b/libstdc++-v3/testsuite/std/format/arguments/args.cc
index 4c50bc7..6029675 100644
--- a/libstdc++-v3/testsuite/std/format/arguments/args.cc
+++ b/libstdc++-v3/testsuite/std/format/arguments/args.cc
@@ -164,24 +164,6 @@ void test_visited_as_handle()
#endif
}
-template<typename E, typename S>
-void test_visited_as()
-{
- auto v = static_cast<S>(1.0);
- auto store = std::make_format_args(v);
- std::format_args args = store;
-
- auto is_expected_val = [v](auto arg) {
- if constexpr (std::is_same_v<decltype(arg), E>)
- return arg == static_cast<E>(v);
- return false;
- };
- VERIFY( std::visit_format_arg(is_expected_val, args.get(0)) );
-#if __cpp_lib_format >= 202306L // C++26 adds std::basic_format_arg::visit
- VERIFY( args.get(0).visit(is_expected_val) );
-#endif
-}
-
template<typename T>
concept can_format = std::is_default_constructible_v<std::formatter<T, char>>;
@@ -195,30 +177,31 @@ int main()
test_visited_as_handle<__int128>();
test_visited_as_handle<unsigned __int128>();
#endif
-// TODO: This should be visited as handle.
-#ifdef __STDCPP_FLOAT16_T__
- if constexpr (can_format<_Float16>)
- test_visited_as<float, _Float16>();
-#endif
-#ifdef __STDCPP_BFLOAT16_T__
+#ifdef __BFLT16_DIG__
if constexpr (can_format<__gnu_cxx::__bfloat16_t>)
- test_visited_as<float, __gnu_cxx::__bfloat16_t>();
+ test_visited_as_handle<__gnu_cxx::__bfloat16_t>();
+#endif
+#ifdef __FLT16_DIG__
+ if constexpr (can_format<_Float16>)
+ test_visited_as_handle<_Float16>();
#endif
#ifdef __FLT32_DIG__
if constexpr (can_format<_Float32>)
- test_visited_as<float, _Float32>();
+ test_visited_as_handle<_Float32>();
#endif
#ifdef __FLT64_DIG__
if constexpr (can_format<_Float64>)
- test_visited_as<double, _Float64>();
+ test_visited_as_handle<_Float64>();
#endif
#ifdef __FLT128_DIG__
if constexpr (can_format<_Float128>)
-# ifdef _GLIBCXX_LDOUBLE_IS_IEEE_BINARY128
- test_visited_as<long double, _Float128>();
-# else
test_visited_as_handle<_Float128>();
-# endif
+#endif
+#ifdef __SIZEOF_FLOAT128__
+ // __ieee128 is same type as __float128, and may be long double
+ if constexpr (!std::is_same_v<__float128, long double>)
+ if constexpr (can_format<__float128>)
+ test_visited_as_handle<__float128>();
#endif
#ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
if constexpr (!std::is_same_v<__ieee128, long double>)
diff --git a/libstdc++-v3/testsuite/std/format/debug.cc b/libstdc++-v3/testsuite/std/format/debug.cc
new file mode 100644
index 0000000..43e930c
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/format/debug.cc
@@ -0,0 +1,843 @@
+// { dg-options "-fexec-charset=UTF-8 -fwide-exec-charset=UTF-32LE -DUNICODE_ENC" { target le } }
+// { dg-options "-fexec-charset=UTF-8 -fwide-exec-charset=UTF-32BE -DUNICODE_ENC" { target be } }
+// { dg-do run { target c++23 } }
+// { dg-require-effective-target 4byte_wchar_t }
+// { dg-add-options no_pch }
+// { dg-timeout-factor 2 }
+
+#include <format>
+#include <testsuite_hooks.h>
+
+std::string
+fdebug(char t)
+{ return std::format("{:?}", t); }
+
+std::wstring
+fdebug(wchar_t t)
+{ return std::format(L"{:?}", t); }
+
+std::string
+fdebug(std::string_view t)
+{ return std::format("{:?}", t); }
+
+std::wstring
+fdebug(std::wstring_view t)
+{ return std::format(L"{:?}", t); }
+
+
+#define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S)
+#define WIDEN(S) WIDEN_(CharT, S)
+
+template<typename CharT>
+void
+test_basic_escapes()
+{
+ std::basic_string<CharT> res;
+
+ const auto tab = WIDEN("\t");
+ res = fdebug(tab);
+ VERIFY( res == WIDEN(R"("\t")") );
+ res = fdebug(tab[0]);
+ VERIFY( res == WIDEN(R"('\t')") );
+
+ const auto nline = WIDEN("\n");
+ res = fdebug(nline);
+ VERIFY( res == WIDEN(R"("\n")") );
+ res = fdebug(nline[0]);
+ VERIFY( res == WIDEN(R"('\n')") );
+
+ const auto carret = WIDEN("\r");
+ res = fdebug(carret);
+ VERIFY( res == WIDEN(R"("\r")") );
+ res = fdebug(carret[0]);
+ VERIFY( res == WIDEN(R"('\r')") );
+
+ const auto bslash = WIDEN("\\");
+ res = fdebug(bslash);
+ VERIFY( res == WIDEN(R"("\\")") );
+ res = fdebug(bslash[0]);
+ VERIFY( res == WIDEN(R"('\\')") );
+
+ const auto quote = WIDEN("\"");
+ res = fdebug(quote);
+ VERIFY( res == WIDEN(R"("\"")") );
+ res = fdebug(quote[0]);
+ VERIFY( res == WIDEN(R"('"')") );
+
+ const auto apos = WIDEN("\'");
+ res = fdebug(apos);
+ VERIFY( res == WIDEN(R"("'")") );
+ res = fdebug(apos[0]);
+ VERIFY( res == WIDEN(R"('\'')") );
+}
+
+template<typename CharT>
+void
+test_ascii_escapes()
+{
+ std::basic_string<CharT> res;
+
+ const auto in = WIDEN("\x10 abcde\x7f\t0123");
+ res = fdebug(in);
+ VERIFY( res == WIDEN(R"("\u{10} abcde\u{7f}\t0123")") );
+ res = fdebug(in[0]);
+ VERIFY( res == WIDEN(R"('\u{10}')") );
+ res = fdebug(in[1]);
+ VERIFY( res == WIDEN(R"(' ')") );
+ res = fdebug(in[2]);
+ VERIFY( res == WIDEN(R"('a')") );
+}
+
+template<typename CharT>
+void
+test_extended_ascii()
+{
+ std::basic_string<CharT> res;
+
+ const auto in = WIDEN("Åëÿ");
+ res = fdebug(in);
+ VERIFY( res == WIDEN(R"("Åëÿ")") );
+
+ static constexpr bool __test_characters
+#if UNICODE_ENC
+ = sizeof(CharT) >= 2;
+#else // ISO8859-1
+ = true;
+#endif // UNICODE_ENC
+
+ if constexpr (__test_characters)
+ {
+ res = fdebug(in[0]);
+ VERIFY( res == WIDEN(R"('Ã…')") );
+ res = fdebug(in[1]);
+ VERIFY( res == WIDEN(R"('ë')") );
+ res = fdebug(in[2]);
+ VERIFY( res == WIDEN(R"('ÿ')") );
+ }
+}
+
+template<typename CharT>
+void
+test_unicode_escapes()
+{
+#if UNICODE_ENC
+ std::basic_string<CharT> res;
+
+ const auto in = WIDEN(
+ "\u008a" // Cc, Control, Line Tabulation Set,
+ "\u00ad" // Cf, Format, Soft Hyphen
+ "\u1d3d" // Lm, Modifier letter, Modifier Letter Capital Ou
+ "\u00a0" // Zs, Space Separator, No-Break Space (NBSP)
+ "\u2029" // Zp, Paragraph Separator, Paragraph Separator
+ "\U0001f984" // So, Other Symbol, Unicorn Face
+ );
+ const auto out = WIDEN("\""
+ R"(\u{8a})"
+ R"(\u{ad})"
+ "\u1d3d"
+ R"(\u{a0})"
+ R"(\u{2029})"
+ "\U0001f984"
+ "\"");
+
+ res = fdebug(in);
+ VERIFY( res == out );
+
+ if constexpr (sizeof(CharT) >= 2)
+ {
+ res = fdebug(in[0]);
+ VERIFY( res == WIDEN(R"('\u{8a}')") );
+ res = fdebug(in[1]);
+ VERIFY( res == WIDEN(R"('\u{ad}')") );
+ res = fdebug(in[2]);
+ VERIFY( res == WIDEN("'\u1d3d'") );
+ res = fdebug(in[3]);
+ VERIFY( res == WIDEN(R"('\u{a0}')") );
+ res = fdebug(in[4]);
+ VERIFY( res == WIDEN(R"('\u{2029}')") );
+ }
+
+ if constexpr (sizeof(CharT) >= 4)
+ {
+ res = fdebug(in[5]);
+ VERIFY( res == WIDEN("'\U0001f984'") );
+ }
+#endif // UNICODE_ENC
+}
+
+template<typename CharT>
+void
+test_grapheme_extend()
+{
+#if UNICODE_ENC
+ std::basic_string<CharT> res;
+
+ const auto vin = WIDEN("o\u0302\u0323");
+ res = fdebug(vin);
+ VERIFY( res == WIDEN("\"o\u0302\u0323\"") );
+
+ std::basic_string_view<CharT> in = WIDEN("\t\u0302\u0323");
+ res = fdebug(in);
+ VERIFY( res == WIDEN(R"("\t\u{302}\u{323}")") );
+
+ res = fdebug(in.substr(1));
+ VERIFY( res == WIDEN(R"("\u{302}\u{323}")") );
+
+ if constexpr (sizeof(CharT) >= 2)
+ {
+ res = fdebug(in[1]);
+ VERIFY( res == WIDEN(R"('\u{302}')") );
+ }
+#endif // UNICODE_ENC
+}
+
+template<typename CharT>
+void
+test_replacement_char()
+{
+#if UNICODE_ENC
+ std::basic_string<CharT> repl = WIDEN("\uFFFD");
+ std::basic_string<CharT> res = fdebug(repl);
+ VERIFY( res == WIDEN("\"\uFFFD\"") );
+
+ repl = WIDEN("\uFFFD\uFFFD");
+ res = fdebug(repl);
+ VERIFY( res == WIDEN("\"\uFFFD\uFFFD\"") );
+#endif // UNICODE_ENC
+}
+
+void
+test_ill_formed_utf8_seq()
+{
+#if UNICODE_ENC
+ std::string_view seq = "\xf0\x9f\xa6\x84"; // \U0001F984
+ std::string res;
+
+ res = fdebug(seq);
+ VERIFY( res == "\"\U0001F984\"" );
+
+ res = fdebug(seq.substr(1));
+ VERIFY( res == R"("\x{9f}\x{a6}\x{84}")" );
+
+ res = fdebug(seq.substr(2));
+ VERIFY( res == R"("\x{a6}\x{84}")" );
+
+ res = fdebug(seq[0]);
+ VERIFY( res == R"('\x{f0}')" );
+ res = fdebug(seq.substr(0, 1));
+ VERIFY( res == R"("\x{f0}")" );
+
+ res = fdebug(seq[1]);
+ VERIFY( res == R"('\x{9f}')" );
+ res = fdebug(seq.substr(1, 1));
+ VERIFY( res == R"("\x{9f}")" );
+
+ res = fdebug(seq[2]);
+ VERIFY( res == R"('\x{a6}')" );
+ res = fdebug(seq.substr(2, 1));
+ VERIFY( res == R"("\x{a6}")" );
+
+ res = fdebug(seq[3]);
+ VERIFY( res == R"('\x{84}')" );
+ res = fdebug(seq.substr(3, 1));
+ VERIFY( res == R"("\x{84}")" );
+#endif // UNICODE_ENC
+}
+
+void
+test_ill_formed_utf32()
+{
+#if UNICODE_ENC
+ std::wstring res;
+
+ wchar_t ic1 = static_cast<wchar_t>(0xff'ffff);
+ res = fdebug(ic1);
+ VERIFY( res == LR"('\x{ffffff}')" );
+
+ std::wstring is1(1, ic1);
+ res = fdebug(is1);
+ VERIFY( res == LR"("\x{ffffff}")" );
+
+ wchar_t ic2 = static_cast<wchar_t>(0xffff'ffff);
+ res = fdebug(ic2);
+ VERIFY( res == LR"('\x{ffffffff}')" );
+
+ std::wstring is2(1, ic2);
+ res = fdebug(is2);
+ VERIFY( res == LR"("\x{ffffffff}")" );
+#endif // UNICODE_ENC
+}
+
+template<typename CharT>
+void
+test_fill()
+{
+ std::basic_string<CharT> res;
+
+ std::basic_string_view<CharT> in = WIDEN("a\t\x10\u00ad");
+ res = std::format(WIDEN("{:10?}"), in.substr(0, 1));
+ VERIFY( res == WIDEN(R"("a" )") );
+
+ res = std::format(WIDEN("{:->10?}"), in.substr(1, 1));
+ VERIFY( res == WIDEN(R"(------"\t")") );
+
+ res = std::format(WIDEN("{:+<10?}"), in.substr(2, 1));
+ VERIFY( res == WIDEN(R"("\u{10}"++)") );
+
+
+ res = std::format(WIDEN("{:10?}"), in[0]);
+ VERIFY( res == WIDEN(R"('a' )") );
+
+ res = std::format(WIDEN("{:->10?}"), in[1]);
+ VERIFY( res == WIDEN(R"(------'\t')") );
+
+ res = std::format(WIDEN("{:+<10?}"), in[2]);
+ VERIFY( res == WIDEN(R"('\u{10}'++)") );
+
+#if UNICODE_ENC
+ res = std::format(WIDEN("{:=^10?}"), in.substr(3));
+ VERIFY( res == WIDEN(R"(="\u{ad}"=)") );
+
+ // width is 2
+ std::basic_string_view<CharT> in2 = WIDEN("\u1100");
+ res = std::format(WIDEN("{:*^10?}"), in2);
+ VERIFY( res == WIDEN("***\"\u1100\"***") );
+
+ if constexpr (sizeof(CharT) >= 2)
+ {
+ res = std::format(WIDEN("{:=^10?}"), in[3]);
+ VERIFY( res == WIDEN(R"(='\u{ad}'=)") );
+
+ res = std::format(WIDEN("{:*^10?}"), in2[0]);
+ VERIFY( res == WIDEN("***'\u1100'***") );
+ }
+#endif // UNICODE_ENC
+}
+
+template<typename CharT>
+void
+test_prec()
+{
+ std::basic_string<CharT> res;
+ // with ? escpaed presentation is copied to ouput, same as source
+
+ std::basic_string_view<CharT> in = WIDEN("a\t\x10\u00ad");
+ res = std::format(WIDEN("{:.2?}"), in.substr(0, 1));
+ VERIFY( res == WIDEN(R"("a)") );
+
+ res = std::format(WIDEN("{:.4?}"), in.substr(1, 1));
+ VERIFY( res == WIDEN(R"("\t")") );
+
+ res = std::format(WIDEN("{:.5?}"), in.substr(2, 1));
+ VERIFY( res == WIDEN(R"("\u{1)") );
+
+#if UNICODE_ENC
+ res = std::format(WIDEN("{:.10?}"), in.substr(3));
+ VERIFY( res == WIDEN(R"("\u{ad}")") );
+
+ std::basic_string_view<CharT> in2 = WIDEN("\u1100");
+ res = std::format(WIDEN("{:.3?}"), in2);
+ VERIFY( res == WIDEN("\"\u1100") );
+#endif // UNICODE_ENC
+}
+
+bool strip_quote(std::string_view& v)
+{
+ if (!v.starts_with('"'))
+ return false;
+ v.remove_prefix(1);
+ return true;
+}
+
+bool strip_quotes(std::string_view& v)
+{
+ if (!v.starts_with('"') || !v.ends_with('"'))
+ return false;
+ v.remove_prefix(1);
+ v.remove_suffix(1);
+ return true;
+}
+
+bool strip_prefix(std::string_view& v, size_t n, char c)
+{
+ size_t pos = v.find_first_not_of(c);
+ if (pos == std::string_view::npos)
+ pos = v.size();
+ if (pos != n)
+ return false;
+ v.remove_prefix(n);
+ return true;
+}
+
+void test_padding()
+{
+ std::string res;
+ std::string_view resv;
+
+ // width and size are 26
+ std::string in = "abcdefghijklmnopqrstuvwxyz";
+ in += in; // width and size are 52
+ in += in; // width and size are 104
+ in += in; // width and size are 208
+ in += in; // width and size are 416
+ std::string_view inv = in;
+
+ resv = res = std::format("{}", in);
+ VERIFY( resv == inv );
+
+ resv = res = std::format("{:.500}", in);
+ VERIFY( resv == inv );
+
+ resv = res = std::format("{:.400}", in);
+ VERIFY( resv == inv.substr(0, 400) );
+
+ resv = res = std::format("{:.200}", in);
+ VERIFY( resv == inv.substr(0, 200) );
+
+ resv = res = std::format("{:.10}", in);
+ VERIFY( resv == inv.substr(0, 10) );
+
+ resv = res = std::format("{:.0}", in);
+ VERIFY( resv == "" );
+
+ resv = res = std::format("{:*>20}", in);
+ VERIFY( resv == inv );
+
+ resv = res = std::format("{:*>20.500}", in);
+ VERIFY( resv == inv );
+
+ resv = res = std::format("{:*>20.400}", in);
+ VERIFY( resv == inv.substr(0, 400) );
+
+ resv = res = std::format("{:*>20.200}", in);
+ VERIFY( resv == inv.substr(0, 200) );
+
+ resv = res = std::format("{:*>20.10}", in);
+ VERIFY( strip_prefix(resv, 10, '*') );
+ VERIFY( resv == inv.substr(0, 10) );
+
+ resv = res = std::format("{:*>20.0}", in);
+ VERIFY( strip_prefix(resv, 20, '*') );
+ VERIFY( resv == "" );
+
+ resv = res = std::format("{:*>450}", in);
+ VERIFY( strip_prefix(resv, 34, '*') );
+ VERIFY( resv == inv );
+
+ resv = res = std::format("{:*>450.500}", in);
+ VERIFY( strip_prefix(resv, 34, '*') );
+ VERIFY( resv == inv );
+
+ resv = res = std::format("{:*>450.420}", in);
+ VERIFY( strip_prefix(resv, 34, '*') );
+ VERIFY( resv == inv );
+
+ resv = res = std::format("{:*>450.400}", in);
+ VERIFY( strip_prefix(resv, 50, '*') );
+ VERIFY( resv == inv.substr(0, 400) );
+
+ resv = res = std::format("{:*>450.200}", in);
+ VERIFY( strip_prefix(resv, 250, '*') );
+ VERIFY( resv == inv.substr(0, 200) );
+
+ resv = res = std::format("{:*>450.10}", in);
+ VERIFY( strip_prefix(resv, 440, '*') );
+ VERIFY( resv == inv.substr(0, 10) );
+
+ resv = res = std::format("{:*>450.0}", in);
+ VERIFY( strip_prefix(resv, 450, '*') );
+ VERIFY( resv == "" );
+
+ resv = res = std::format("{:?}", in);
+ VERIFY( strip_quotes(resv) );
+ VERIFY( resv == inv );
+
+ resv = res = std::format("{:.500?}", in);
+ VERIFY( strip_quotes(resv) );
+ VERIFY( resv == inv );
+
+ resv = res = std::format("{:.400?}", in);
+ VERIFY( strip_quote(resv) );
+ VERIFY( resv == inv.substr(0, 399) );
+
+ resv = res = std::format("{:.200?}", in);
+ VERIFY( strip_quote(resv) );
+ VERIFY( resv == inv.substr(0, 199) );
+
+ resv = res = std::format("{:.10?}", in);
+ VERIFY( strip_quote(resv) );
+ VERIFY( resv == inv.substr(0, 9) );
+
+ resv = res = std::format("{:.1?}", in);
+ VERIFY( strip_quote(resv) );
+ VERIFY( resv == "" );
+
+ resv = res = std::format("{:.0?}", in);
+ VERIFY( resv == "" );
+
+ resv = res = std::format("{:*>20?}", in);
+ VERIFY( strip_quotes(resv) );
+ VERIFY( resv == inv );
+
+ resv = res = std::format("{:*>20.500?}", in);
+ VERIFY( strip_quotes(resv) );
+ VERIFY( resv == inv );
+
+ resv = res = std::format("{:*>20.400?}", in);
+ VERIFY( strip_quote(resv) );
+ VERIFY( resv == inv.substr(0, 399) );
+
+ resv = res = std::format("{:*>20.200?}", in);
+ VERIFY( strip_quote(resv) );
+ VERIFY( resv == inv.substr(0, 199) );
+
+ resv = res = std::format("{:*>20.10?}", in);
+ VERIFY( strip_prefix(resv, 10, '*') );
+ VERIFY( strip_quote(resv) );
+ VERIFY( resv == inv.substr(0, 9) );
+
+ resv = res = std::format("{:*>20.1?}", in);
+ VERIFY( strip_prefix(resv, 19, '*') );
+ VERIFY( strip_quote(resv) );
+ VERIFY( resv == "" );
+
+ resv = res = std::format("{:*>20.0?}", in);
+ VERIFY( strip_prefix(resv, 20, '*') );
+ VERIFY( resv == "" );
+
+ resv = res = std::format("{:*>450?}", in);
+ VERIFY( strip_prefix(resv, 32, '*') );
+ VERIFY( strip_quotes(resv) );
+ VERIFY( resv == inv );
+
+ resv = res = std::format("{:*>450.500?}", in);
+ VERIFY( strip_prefix(resv, 32, '*') );
+ VERIFY( strip_quotes(resv) );
+ VERIFY( resv == inv );
+
+ resv = res = std::format("{:*>450.420?}", in);
+ VERIFY( strip_prefix(resv, 32, '*') );
+ VERIFY( strip_quotes(resv) );
+ VERIFY( resv == inv );
+
+ resv = res = std::format("{:*>450.400?}", in);
+ VERIFY( strip_prefix(resv, 50, '*') );
+ VERIFY( strip_quote(resv) );
+ VERIFY( resv == inv.substr(0, 399) );
+
+ resv = res = std::format("{:*>450.200?}", in);
+ VERIFY( strip_prefix(resv, 250, '*') );
+ VERIFY( strip_quote(resv) );
+ VERIFY( resv == inv.substr(0, 199) );
+
+ resv = res = std::format("{:*>450.10?}", in);
+ VERIFY( strip_prefix(resv, 440, '*') );
+ VERIFY( strip_quote(resv) );
+ VERIFY( resv == inv.substr(0, 9) );
+
+ resv = res = std::format("{:*>450.1?}", in);
+ VERIFY( strip_prefix(resv, 449, '*') );
+ VERIFY( strip_quote(resv) );
+ VERIFY( resv == "" );
+
+ resv = res = std::format("{:*>450.0?}", in);
+ VERIFY( strip_prefix(resv, 450, '*') );
+ VERIFY( resv == "" );
+
+#if UNICODE_ENC
+ // width is 3, size is 15
+ in = "o\u0302\u0323i\u0302\u0323u\u0302\u0323";
+ in += in; // width is 6, size is 30
+ in += in; // width is 12, size is 60
+ in += in; // width is 24, size is 120
+ in += in; // width is 48, size is 240
+ in += in; // width is 96, size is 480
+ in += in; // width is 192, size is 960
+ inv = in;
+
+ resv = res = std::format("{:}", in);
+ VERIFY( resv == inv );
+
+ resv = res = std::format("{:.200}", in);
+ VERIFY( resv == inv );
+
+ resv = res = std::format("{:.96}", in);
+ VERIFY( resv == inv.substr(0, 480) );
+
+ resv = res = std::format("{:.12}", in);
+ VERIFY( resv == inv.substr(0, 60) );
+
+ resv = res = std::format("{:.3}", in);
+ VERIFY( resv == inv.substr(0, 15) );
+
+ resv = res = std::format("{:.0}", in);
+ VERIFY( resv == "" );
+
+ resv = res = std::format("{:*>10}", in);
+ VERIFY( resv == inv );
+
+ resv = res = std::format("{:*>10.200}", in);
+ VERIFY( resv == inv );
+
+ resv = res = std::format("{:*>10.96}", in);
+ VERIFY( resv == inv.substr(0, 480) );
+
+ resv = res = std::format("{:*>10.12}", in);
+ VERIFY( resv == inv.substr(0, 60) );
+
+ resv = res = std::format("{:*>10.3}", in);
+ VERIFY( strip_prefix(resv, 7, '*') );
+ VERIFY( resv == inv.substr(0, 15) );
+
+ resv = res = std::format("{:*>10.0}", in);
+ VERIFY( strip_prefix(resv, 10, '*') );
+ VERIFY( resv == "" );
+
+ resv = res = std::format("{:*>240s}", in);
+ VERIFY( strip_prefix(resv, 48, '*') );
+ VERIFY( resv == inv );
+
+ resv = res = std::format("{:*>300.200s}", in);
+ VERIFY( strip_prefix(resv, 108, '*') );
+ VERIFY( resv == inv );
+
+ resv = res = std::format("{:*>240.200s}", in);
+ VERIFY( strip_prefix(resv, 48, '*') );
+ VERIFY( resv == inv );
+
+ resv = res = std::format("{:*>240.96s}", in);
+ VERIFY( strip_prefix(resv, 144, '*') );
+ VERIFY( resv == inv.substr(0, 480) );
+
+ resv = res = std::format("{:*>240.12}", in);
+ VERIFY( strip_prefix(resv, 228, '*') );
+ VERIFY( resv == inv.substr(0, 60) );
+
+ resv = res = std::format("{:*>240.3s}", in);
+ VERIFY( strip_prefix(resv, 237, '*') );
+ VERIFY( resv == inv.substr(0, 15) );
+
+ resv = res = std::format("{:*>240.0s}", in);
+ VERIFY( strip_prefix(resv, 240, '*') );
+ VERIFY( resv == "" );
+
+ resv = res = std::format("{:?}", in);
+ VERIFY( strip_quotes(resv) );
+ VERIFY( resv == inv );
+
+ resv = res = std::format("{:.200?}", in);
+ VERIFY( strip_quotes(resv) );
+ VERIFY( resv == inv );
+
+ resv = res = std::format("{:.97?}", in);
+ VERIFY( strip_quote(resv) );
+ VERIFY( resv == inv.substr(0, 480) );
+
+ resv = res = std::format("{:.13?}", in);
+ VERIFY( strip_quote(resv) );
+ VERIFY( resv == inv.substr(0, 60) );
+
+ resv = res = std::format("{:.4?}", in);
+ VERIFY( strip_quote(resv) );
+ VERIFY( resv == inv.substr(0, 15) );
+
+ resv = res = std::format("{:.1?}", in);
+ VERIFY( strip_quote(resv) );
+ VERIFY( resv == "" );
+
+ resv = res = std::format("{:.0?}", in);
+ VERIFY( resv == "" );
+
+ resv = res = std::format("{:*>10?}", in);
+ VERIFY( strip_quotes(resv) );
+ VERIFY( resv == inv );
+
+ resv = res = std::format("{:*>10.200?}", in);
+ VERIFY( strip_quotes(resv) );
+ VERIFY( resv == inv );
+
+ resv = res = std::format("{:*>10.97?}", in);
+ VERIFY( strip_quote(resv) );
+ VERIFY( resv == inv.substr(0, 480) );
+
+ resv = res = std::format("{:*>10.13?}", in);
+ VERIFY( strip_quote(resv) );
+ VERIFY( resv == inv.substr(0, 60) );
+
+ resv = res = std::format("{:*>10.4?}", in);
+ VERIFY( strip_prefix(resv, 6, '*') );
+ VERIFY( strip_quote(resv) );
+ VERIFY( resv == inv.substr(0, 15) );
+
+ resv = res = std::format("{:*>10.1?}", in);
+ VERIFY( strip_prefix(resv, 9, '*') );
+ VERIFY( strip_quote(resv) );
+ VERIFY( resv == "" );
+
+ resv = res = std::format("{:*>10.0?}", in);
+ VERIFY( strip_prefix(resv, 10, '*') );
+ VERIFY( resv == "" );
+
+ resv = res = std::format("{:*>240?}", in);
+ VERIFY( strip_prefix(resv, 46, '*') );
+ VERIFY( strip_quotes(resv) );
+ VERIFY( resv == inv );
+
+ resv = res = std::format("{:*>300.200?}", in);
+ VERIFY( strip_prefix(resv, 106, '*') );
+ VERIFY( strip_quotes(resv) );
+ VERIFY( resv == inv );
+
+ resv = res = std::format("{:*>240.200?}", in);
+ VERIFY( strip_prefix(resv, 46, '*') );
+ VERIFY( strip_quotes(resv) );
+ VERIFY( resv == inv );
+
+ resv = res = std::format("{:*>240.97?}", in);
+ VERIFY( strip_prefix(resv, 143, '*') );
+ VERIFY( strip_quote(resv) );
+ VERIFY( resv == inv.substr(0, 480) );
+
+ resv = res = std::format("{:*>240.13?}", in);
+ VERIFY( strip_prefix(resv, 227, '*') );
+ VERIFY( strip_quote(resv) );
+ VERIFY( resv == inv.substr(0, 60) );
+
+ resv = res = std::format("{:*>240.4?}", in);
+ VERIFY( strip_prefix(resv, 236, '*') );
+ VERIFY( strip_quote(resv) );
+ VERIFY( resv == inv.substr(0, 15) );
+
+ resv = res = std::format("{:*>240.1?}", in);
+ VERIFY( strip_prefix(resv, 239, '*') );
+ VERIFY( strip_quote(resv) );
+ VERIFY( resv == "" );
+
+ resv = res = std::format("{:*>240.0?}", in);
+ VERIFY( strip_prefix(resv, 240, '*') );
+ VERIFY( resv == "" );
+#endif // UNICODE_ENC
+}
+
+void test_char_as_wchar()
+{
+ std::wstring res;
+
+ res = std::format(L"{:?}", 'a');
+ VERIFY( res == LR"('a')" );
+
+ res = std::format(L"{:?}", '\t');
+ VERIFY( res == LR"('\t')" );
+
+ res = std::format(L"{:+<10?}", '\x10');
+ VERIFY( res == LR"('\u{10}'++)" );
+}
+
+template<typename T>
+struct DebugWrapper
+{
+ T val;
+};
+
+template<typename T, typename CharT>
+struct std::formatter<DebugWrapper<T>, CharT>
+{
+ constexpr std::basic_format_parse_context<CharT>::iterator
+ parse(std::basic_format_parse_context<CharT>& pc)
+ {
+ auto out = under.parse(pc);
+ under.set_debug_format();
+ return out;
+ }
+
+ template<typename Out>
+ Out format(DebugWrapper<T> const& t,
+ std::basic_format_context<Out, CharT>& fc) const
+ { return under.format(t.val, fc); }
+
+private:
+ std::formatter<T, CharT> under;
+};
+
+template<typename CharT, typename StrT>
+void
+test_formatter_str()
+{
+ CharT buf[]{ 'a', 'b', 'c', 0 };
+ DebugWrapper<StrT> in{ buf };
+ std::basic_string<CharT> res = std::format(WIDEN("{:?}"), in );
+ VERIFY( res == WIDEN(R"("abc")") );
+}
+
+template<typename CharT>
+void
+test_formatter_arr()
+{
+ std::basic_string<CharT> res;
+
+ DebugWrapper<CharT[3]> in3{ 'a', 'b', 'c' };
+ res = std::format(WIDEN("{:?}"), in3 );
+ VERIFY( res == WIDEN(R"("abc")") );
+
+ // We print all characters, including null-terminator
+ DebugWrapper<CharT[4]> in4{ 'a', 'b', 'c', 0 };
+ res = std::format(WIDEN("{:?}"), in4 );
+ VERIFY( res == WIDEN(R"("abc\u{0}")") );
+}
+
+template<typename CharT, typename SrcT>
+void
+test_formatter_char()
+{
+ DebugWrapper<SrcT> in{ 'a' };
+ std::basic_string<CharT> res = std::format(WIDEN("{:?}"), in);
+ VERIFY( res == WIDEN(R"('a')") );
+}
+
+template<typename CharT>
+void
+test_formatters()
+{
+ test_formatter_char<CharT, CharT>();
+ test_formatter_str<CharT, CharT*>();
+ test_formatter_str<CharT, const CharT*>();
+ test_formatter_str<CharT, std::basic_string<CharT>>();
+ test_formatter_str<CharT, std::basic_string_view<CharT>>();
+ test_formatter_arr<CharT>();
+}
+
+void
+test_formatters_c()
+{
+ test_formatters<char>();
+ test_formatters<wchar_t>();
+ test_formatter_char<wchar_t, char>();
+}
+
+int main()
+{
+ test_basic_escapes<char>();
+ test_basic_escapes<wchar_t>();
+ test_ascii_escapes<char>();
+ test_ascii_escapes<wchar_t>();
+ test_extended_ascii<char>();
+ test_extended_ascii<wchar_t>();
+
+ test_unicode_escapes<char>();
+ test_unicode_escapes<wchar_t>();
+ test_grapheme_extend<char>();
+ test_grapheme_extend<wchar_t>();
+ test_replacement_char<char>();
+ test_replacement_char<wchar_t>();
+ test_ill_formed_utf8_seq();
+ test_ill_formed_utf32();
+
+ test_fill<char>();
+ test_fill<wchar_t>();
+ test_prec<char>();
+ test_prec<wchar_t>();
+
+ test_padding();
+
+ test_formatters_c();
+}
diff --git a/libstdc++-v3/testsuite/std/format/debug_nonunicode.cc b/libstdc++-v3/testsuite/std/format/debug_nonunicode.cc
new file mode 100644
index 0000000..2ac7e75
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/format/debug_nonunicode.cc
@@ -0,0 +1,5 @@
+// { dg-options "-fexec-charset=ISO8859-1" }
+// { dg-do run { target c++23 } }
+// { dg-add-options no_pch }
+
+#include "debug.cc"
diff --git a/libstdc++-v3/testsuite/std/format/formatter/120625.cc b/libstdc++-v3/testsuite/std/format/formatter/120625.cc
new file mode 100644
index 0000000..6b03af9
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/format/formatter/120625.cc
@@ -0,0 +1,19 @@
+// { dg-do compile { target c++20 } }
+
+// Bug libstdc++/120625
+// std::formatter<__disabled> specializations cause errors in user code
+
+#include <format>
+
+enum X { };
+
+// A concept that cannot be used with incomplete types:
+template<typename T>
+concept is_X = !std::is_empty_v<T> && std::is_same_v<X, T>;
+
+// A valid program-defined specialization:
+template<typename T, typename C> requires is_X<T>
+struct std::formatter<T, C> : std::formatter<int, C> { };
+
+// Instantiate the program-defined formatter specialization:
+auto s = sizeof(std::formatter<X, char>);
diff --git a/libstdc++-v3/testsuite/std/format/formatter/lwg3944.cc b/libstdc++-v3/testsuite/std/format/formatter/lwg3944.cc
index ff5f075..07e63af 100644
--- a/libstdc++-v3/testsuite/std/format/formatter/lwg3944.cc
+++ b/libstdc++-v3/testsuite/std/format/formatter/lwg3944.cc
@@ -4,6 +4,7 @@
// LWG 3944. Formatters converting sequences of char to sequences of wchar_t
#include <format>
+#include <vector>
void test_lwg3944()
{
@@ -14,7 +15,6 @@ void test_lwg3944()
std::format(L"{}",cstr); // { dg-error "here" }
// Ill-formed in C++20
- // In C++23 they give L"['h', 'e', 'l', 'l', 'o']"
std::format(L"{}", "hello"); // { dg-error "here" }
std::format(L"{}", std::string_view("hello")); // { dg-error "here" }
std::format(L"{}", std::string("hello")); // { dg-error "here" }
diff --git a/libstdc++-v3/testsuite/std/format/formatter/requirements.cc b/libstdc++-v3/testsuite/std/format/formatter/requirements.cc
index 416b9a8..1c9a0a5 100644
--- a/libstdc++-v3/testsuite/std/format/formatter/requirements.cc
+++ b/libstdc++-v3/testsuite/std/format/formatter/requirements.cc
@@ -70,12 +70,14 @@ test_specializations() // [format.formatter.spec]
// LWG 3833. Remove specialization
// template<size_t N> struct formatter<const charT[N], charT>
- using Farr = std::format_context::formatter_type<const char[1]>;
- static_assert( ! std::is_default_constructible_v<Farr> );
- static_assert( ! std::is_copy_constructible_v<Farr> );
- static_assert( ! std::is_move_constructible_v<Farr> );
- static_assert( ! std::is_copy_assignable_v<Farr> );
- static_assert( ! std::is_move_assignable_v<Farr> );
+ // Formatter is only expected to be instantiated with only cv-unqual types
+ // and attempting to instantiate this specialization is ill-formed
+ // using Farr = std::format_context::formatter_type<const char[1]>;
+ // static_assert( ! std::is_default_constructible_v<Farr> );
+ // static_assert( ! std::is_copy_constructible_v<Farr> );
+ // static_assert( ! std::is_move_constructible_v<Farr> );
+ // static_assert( ! std::is_copy_assignable_v<Farr> );
+ // static_assert( ! std::is_move_assignable_v<Farr> );
}
int main()
diff --git a/libstdc++-v3/testsuite/std/format/functions/format.cc b/libstdc++-v3/testsuite/std/format/functions/format.cc
index 7fc4201..d342114 100644
--- a/libstdc++-v3/testsuite/std/format/functions/format.cc
+++ b/libstdc++-v3/testsuite/std/format/functions/format.cc
@@ -1,6 +1,7 @@
// { dg-options "-fexec-charset=UTF-8" }
// { dg-do run { target c++20 } }
// { dg-add-options no_pch }
+// { dg-additional-options "-DUNICODE" { target 4byte_wchar_t } }
#include <format>
@@ -260,6 +261,16 @@ test_locale()
s = std::format(eloc, "{0:Le} {0:Lf} {0:Lg}", -nan);
VERIFY( s == "-nan -nan -nan" );
+ // PR libstdc++/120548 format confuses a negative sign for a thousands digit
+ s = std::format(bloc, "{:L}", -123.45);
+ VERIFY( s == "-123.45" );
+ s = std::format(bloc, "{:-L}", -876543.21);
+ VERIFY( s == "-876,543.21" );
+ s = std::format(bloc, "{:+L}", 333.22);
+ VERIFY( s == "+333.22" );
+ s = std::format(bloc, "{: L}", 999.44);
+ VERIFY( s == " 999.44" );
+
// Restore
std::locale::global(cloc);
}
@@ -370,6 +381,18 @@ test_wchar()
// P2909R4 Fix formatting of code units as integers (Dude, where’s my char?)
s = std::format(L"{:d} {:d}", wchar_t(-1), char(-1));
VERIFY( s.find('-') == std::wstring::npos );
+
+ auto ws = std::format(L"{:L}", 0.5);
+ VERIFY( ws == L"0.5" );
+ // The default C locale.
+ std::locale cloc = std::locale::classic();
+ // PR libstdc++/119671 use-after-free formatting floating-point to wstring
+ ws = std::format(cloc, L"{:L}", 0.5);
+ VERIFY( ws == L"0.5" );
+ // A locale with no name, but with the same facets as the C locale.
+ std::locale locx(cloc, &std::use_facet<std::ctype<char>>(cloc));
+ ws = std::format(locx, L"{:L}", 0.5);
+ VERIFY( ws == L"0.5" );
}
void
@@ -499,11 +522,17 @@ test_bool()
void
test_unicode()
{
+#ifdef UNICODE
// Similar to sC example in test_std_examples, but not from the standard.
// Verify that the character "🤡" has estimated field width 2,
- // rather than estimated field width equal to strlen("🤡"), which would be 4.
+ // rather than estimated field width equal to strlen("🤡"), which would be 4,
+ // or just width 1 for single character.
std::string sC = std::format("{:*<3}", "🤡");
VERIFY( sC == "🤡*" );
+ std::wstring wsC = std::format(L"{:*<3}", L"🤡");
+ VERIFY( wsC == L"🤡*" );
+ wsC = std::format(L"{:*<3}", L'🤡');
+ VERIFY( wsC == L"🤡*" );
// Verify that "£" has estimated field width 1, not strlen("£") == 2.
std::string sL = std::format("{:*<3}", "£");
@@ -547,6 +576,7 @@ test_unicode()
std::string sA = std::format("{:>5}", input[0]);
VERIFY( sA == input[1] );
}
+#endif
}
int main()
diff --git a/libstdc++-v3/testsuite/std/format/parse_ctx.cc b/libstdc++-v3/testsuite/std/format/parse_ctx.cc
index b5dd7cd..6294dcf 100644
--- a/libstdc++-v3/testsuite/std/format/parse_ctx.cc
+++ b/libstdc++-v3/testsuite/std/format/parse_ctx.cc
@@ -443,6 +443,8 @@ test_custom()
}
#if __cpp_lib_format >= 202305
+#include <stdfloat>
+
struct X { };
template<>
@@ -458,13 +460,20 @@ struct std::formatter<X, char>
if (spec == "int")
{
pc.check_dynamic_spec_integral(pc.next_arg_id());
- integer = true;
+ type = Type::integral;
}
else if (spec == "str")
{
pc.check_dynamic_spec_string(pc.next_arg_id());
- integer = false;
+ type = Type::string;
+ }
+ else if (spec == "float")
+ {
+ pc.check_dynamic_spec<float, double, long double>(pc.next_arg_id());
+ type = Type::floating;
}
+ else if (spec == "other")
+ type = Type::other;
else
throw std::format_error("invalid format-spec");
return pc.begin() + spec.size();
@@ -474,13 +483,44 @@ struct std::formatter<X, char>
format(X, std::format_context& c) const
{
std::visit_format_arg([this]<typename T>(T) { // { dg-warning "deprecated" "" { target c++26 } }
- if (is_integral_v<T> != this->integer)
- throw std::format_error("invalid argument type");
+ constexpr bool is_handle
+ = std::is_same_v<std::basic_format_arg<std::format_context>::handle, T>;
+ constexpr bool is_integral
+ = std::is_same_v<int, T> || std::is_same_v<unsigned int, T>
+ || is_same_v<long long, T> || std::is_same_v<unsigned long long, T>;
+ constexpr bool is_string
+ = std::is_same_v<const char*, T> || std::is_same_v<std::string_view, T>;
+ constexpr bool is_floating
+ = std::is_same_v<float, T> || std::is_same_v<double, T>
+ || std::is_same_v<long double, T>;
+ switch (this->type)
+ {
+ case Type::other:
+ if (is_handle) return;
+ break;
+ case Type::integral:
+ if (is_integral) return;
+ break;
+ case Type::string:
+ if (is_string) return;
+ break;
+ case Type::floating:
+ if (is_floating) return;
+ break;
+ }
+ throw std::format_error("invalid argument type");
}, c.arg(1));
return c.out();
}
private:
- bool integer = false;
+ enum class Type
+ {
+ other,
+ integral,
+ string,
+ floating,
+ };
+ Type type = Type::other;
};
#endif
@@ -497,6 +537,28 @@ test_dynamic_type_check()
(void) std::format("{:int}", X{}, 42L);
(void) std::format("{:str}", X{}, "H2G2");
+ (void) std::format("{:float}", X{}, 10.0);
+
+#ifdef __STDCPP_BFLOAT16_T__
+ if constexpr (std::formattable<std::bfloat16_t, char>)
+ (void) std::format("{:other}", X{}, 10.0bf16);
+#endif
+#ifdef __STDCPP_FLOAT16_T__
+ if constexpr (std::formattable<std::float16_t, char>)
+ (void) std::format("{:other}", X{}, 10.0f16);
+#endif
+#ifdef __STDCPP_FLOAT32_T__
+ if constexpr (std::formattable<std::float32_t, char>)
+ (void) std::format("{:other}", X{}, 10.0f32);
+#endif
+#ifdef __STDCPP_FLOAT64_T__
+ if constexpr (std::formattable<std::float64_t, char>)
+ (void) std::format("{:other}", X{}, 10.0f64);
+#endif
+#ifdef __STDCPP_FLOAT128_T__
+ if constexpr (std::formattable<std::float128_t, char>)
+ (void) std::format("{:other}", X{}, 10.0f128);
+#endif
#endif
}
diff --git a/libstdc++-v3/testsuite/std/format/ranges/adaptors.cc b/libstdc++-v3/testsuite/std/format/ranges/adaptors.cc
new file mode 100644
index 0000000..a4e2dfb
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/format/ranges/adaptors.cc
@@ -0,0 +1,156 @@
+// { dg-do run { target c++23 } }
+// { dg-timeout-factor 2 }
+
+#include <format>
+#include <queue>
+#include <stack>
+#include <testsuite_hooks.h>
+
+template<typename... Args>
+bool
+is_format_string_for(const char* str, Args&&... args)
+{
+ try {
+ (void) std::vformat(str, std::make_format_args(args...));
+ return true;
+ } catch (const std::format_error&) {
+ return false;
+ }
+}
+
+#define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S)
+#define WIDEN(S) WIDEN_(CharT, S)
+
+template<template<typename Tp> class Adaptor>
+void
+test_format_string()
+{
+ Adaptor<int> q;
+ VERIFY( !is_format_string_for("{:?}", q) );
+ VERIFY( !is_format_string_for("{:P}", q) );
+
+ // width needs to be integer type
+ VERIFY( !is_format_string_for("{:{}}", q, 1.0f) );
+}
+
+struct NoFormat
+{
+ friend auto operator<=>(NoFormat, NoFormat) = default;
+};
+
+struct MutFormat
+{
+ MutFormat() = default;
+ MutFormat(int p) : x(p) {}
+
+ int x;
+ friend auto operator<=>(MutFormat, MutFormat) = default;
+};
+
+template<typename CharT>
+struct std::formatter<MutFormat, CharT>
+ : std::formatter<int, CharT>
+{
+ template<typename Out>
+ Out format(MutFormat& mf, basic_format_context<Out, CharT>& ctx) const
+ { return std::formatter<int, CharT>::format(mf.x, ctx); }
+};
+
+template<typename T>
+struct NotFormattableCont : std::vector<T>
+{
+ using std::vector<T>::vector;
+};
+
+template<typename T>
+constexpr auto std::format_kind<NotFormattableCont<T>>
+ = std::range_format::disabled;
+
+template<typename CharT,
+ template<typename Tp, typename Cont = std::vector<Tp>> class Adaptor>
+void
+test_output()
+{
+ const std::vector<int> v{3, 2, 1};
+ std::basic_string<CharT> res;
+ Adaptor<int, std::vector<int>> q(std::from_range, v);
+
+ res = std::format(WIDEN("{}"), q);
+ VERIFY( res == WIDEN("[3, 2, 1]") );
+
+ res = std::format(WIDEN("{}"), std::as_const(q));
+ VERIFY( res == WIDEN("[3, 2, 1]") );
+
+ res = std::format(WIDEN("{:n:#x}"), q);
+ VERIFY( res == WIDEN("0x3, 0x2, 0x1") );
+
+ res = std::format(WIDEN("{:=^23:#04x}"), q);
+ VERIFY( res == WIDEN("==[0x03, 0x02, 0x01]===") );
+
+ // Sequence output is always used
+ Adaptor<CharT, std::basic_string<CharT>> qs(
+ std::from_range,
+ std::basic_string_view<CharT>(WIDEN("321")));
+
+ res = std::format(WIDEN("{}"), qs);
+ VERIFY( res == WIDEN("['3', '2', '1']") );
+
+ res = std::format(WIDEN("{::}"), std::as_const(qs));
+ VERIFY( res == WIDEN("[3, 2, 1]") );
+
+ res = std::format(WIDEN("{:?s}"), qs);
+ VERIFY( res == WIDEN(R"("321")") );
+
+ Adaptor<int, std::deque<int>> qd(std::from_range, v);
+
+ res = std::format(WIDEN("{}"), qd);
+ VERIFY( res == WIDEN("[3, 2, 1]") );
+
+ res = std::format(WIDEN("{}"), std::as_const(qd));
+ VERIFY( res == WIDEN("[3, 2, 1]") );
+
+ Adaptor<MutFormat> mq(std::from_range, v);
+
+ res = std::format(WIDEN("{}"), mq);
+ VERIFY( res == WIDEN("[3, 2, 1]") );
+
+ static_assert(!std::formattable<const Adaptor<MutFormat>, CharT>);
+
+ static_assert(!std::formattable<Adaptor<NoFormat>, CharT>);
+ static_assert(!std::formattable<const Adaptor<NoFormat>, CharT>);
+
+ // Formatter check if container is formattable, not container elements.
+ static_assert(!std::formattable<Adaptor<int, NotFormattableCont<int>>, CharT>);
+}
+
+template<template<typename Tp, typename Cont = std::vector<Tp>> class Adaptor>
+void
+test_adaptor()
+{
+ test_format_string<Adaptor>();
+ test_output<char, Adaptor>();
+ test_output<wchar_t, Adaptor>();
+
+ static_assert(!std::formattable<Adaptor<int>, int>);
+ static_assert(!std::formattable<Adaptor<int>, char32_t>);
+}
+
+template<typename CharT>
+void
+test_compare()
+{
+ const std::vector<int> v{3, 2, 1};
+ std::basic_string<CharT> res;
+ std::priority_queue<int, std::vector<int>, std::greater<>> q(
+ std::from_range, v);
+
+ res = std::format(WIDEN("{}"), q);
+ VERIFY( res == WIDEN("[1, 2, 3]") );
+}
+
+int main()
+{
+ test_adaptor<std::queue>();
+ test_adaptor<std::priority_queue>();
+ test_compare<char>();
+}
diff --git a/libstdc++-v3/testsuite/std/format/ranges/feature_test.cc b/libstdc++-v3/testsuite/std/format/ranges/feature_test.cc
new file mode 100644
index 0000000..80d2cea
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/format/ranges/feature_test.cc
@@ -0,0 +1,9 @@
+// { dg-do preprocess { target c++23 } }
+
+#include <format>
+
+#ifndef __cpp_lib_format_ranges
+# error "Feature-test macro __cpp_lib_format_ranges missing in <format>"
+#elif __cpp_lib_format_ranges != 202207L
+# error "Feature-test macro __cpp_lib_format_ranges has wrong value in <format>"
+#endif
diff --git a/libstdc++-v3/testsuite/std/format/ranges/format_kind.cc b/libstdc++-v3/testsuite/std/format/ranges/format_kind.cc
new file mode 100644
index 0000000..14b9ff2
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/format/ranges/format_kind.cc
@@ -0,0 +1,94 @@
+// { dg-do run { target c++23 } }
+
+#include <deque>
+#include <flat_map>
+#include <flat_set>
+#include <format>
+#include <list>
+#include <map>
+#include <set>
+#include <testsuite_hooks.h>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+static_assert( std::format_kind<std::vector<int>> == std::range_format::sequence );
+static_assert( std::format_kind<std::deque<int>> == std::range_format::sequence );
+static_assert( std::format_kind<std::list<int>> == std::range_format::sequence );
+
+static_assert( std::format_kind<std::set<int>> == std::range_format::set );
+static_assert( std::format_kind<std::multiset<int>> == std::range_format::set );
+static_assert( std::format_kind<std::unordered_set<int>> == std::range_format::set );
+static_assert( std::format_kind<std::unordered_multiset<int>> == std::range_format::set );
+static_assert( std::format_kind<std::flat_set<int>> == std::range_format::set );
+static_assert( std::format_kind<std::flat_multiset<int>> == std::range_format::set );
+
+static_assert( std::format_kind<std::map<int, int>> == std::range_format::map );
+static_assert( std::format_kind<std::multimap<int, int>> == std::range_format::map );
+static_assert( std::format_kind<std::unordered_map<int, int>> == std::range_format::map );
+static_assert( std::format_kind<std::unordered_multimap<int, int>> == std::range_format::map );
+static_assert( std::format_kind<std::flat_map<int, int>> == std::range_format::map );
+static_assert( std::format_kind<std::flat_multimap<int, int>> == std::range_format::map );
+
+template<typename T>
+struct MyVec : std::vector<T>
+{};
+
+static_assert( std::format_kind<MyVec<int>> == std::range_format::sequence );
+
+template<typename T>
+struct MySet : std::vector<T>
+{
+ using key_type = T;
+};
+
+static_assert( std::format_kind<MySet<int>> == std::range_format::set );
+
+template<typename T>
+struct MyMap : std::vector<T>
+{
+ using key_type = T;
+ using mapped_type = int;
+};
+
+static_assert( std::format_kind<MyMap<std::pair<int, int>>> == std::range_format::map );
+static_assert( std::format_kind<MyMap<std::tuple<int, int>>> == std::range_format::map );
+static_assert( std::format_kind<MyMap<int>> == std::range_format::set );
+
+template<typename T, std::range_format rf>
+struct CustFormat : std::vector<T>
+{
+ using std::vector<T>::vector;
+};
+
+template<typename T, std::range_format rf>
+constexpr auto std::format_kind<CustFormat<T, rf>> = rf;
+
+void test_override()
+{
+ CustFormat<int, std::range_format::disabled> disabledf;
+ static_assert( !std::formattable<decltype(disabledf), char> );
+
+ CustFormat<int, std::range_format::sequence> seqf{1, 2, 3};
+ VERIFY( std::format("{}", seqf) == "[1, 2, 3]" );
+
+ CustFormat<int, std::range_format::set> setf{1, 2, 3};
+ VERIFY( std::format("{}", setf) == "{1, 2, 3}" );
+
+ // TODO test map once formatter for pair is implenented
+
+ CustFormat<char, std::range_format::string> stringf{'a', 'b', 'c', 'd'};
+ VERIFY( std::format("{}", stringf) == "abcd" );
+ // Support precision as string do
+ VERIFY( std::format("{:.2}", stringf) == "ab" );
+
+ CustFormat<char, std::range_format::debug_string> debugf{'a', 'b', 'c', 'd'};
+ VERIFY( std::format("{}", debugf) == R"("abcd")" );
+ // Support precision as string do
+ VERIFY( std::format("{:.3}", debugf) == R"("ab)" );
+}
+
+int main()
+{
+ test_override();
+}
diff --git a/libstdc++-v3/testsuite/std/format/ranges/format_kind_neg.cc b/libstdc++-v3/testsuite/std/format/ranges/format_kind_neg.cc
new file mode 100644
index 0000000..0d761ae
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/format/ranges/format_kind_neg.cc
@@ -0,0 +1,18 @@
+// { dg-do compile { target c++23 } }
+
+// C++23 22.14.7.1 [format.range.fmtkind] p1: A program that instantiates
+// the primary template of format_kind is ill-formed.
+
+#include <format>
+
+void test()
+{
+ (void) std::format_kind<void>; // { dg-error "here" }
+ (void) std::format_kind<const void>; // { dg-error "here" }
+ (void) std::format_kind<int>; // { dg-error "here" }
+ (void) std::format_kind<int&>; // { dg-error "here" }
+ (void) std::format_kind<const int(&)[10]>; // { dg-error "here" }
+ (void) std::format_kind<void()>; // { dg-error "here" }
+}
+
+// { dg-error "cannot use primary template of 'std::format_kind'" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/std/format/ranges/formatter.cc b/libstdc++-v3/testsuite/std/format/ranges/formatter.cc
new file mode 100644
index 0000000..d3e0897
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/format/ranges/formatter.cc
@@ -0,0 +1,170 @@
+// { dg-do run { target c++23 } }
+
+#include <flat_map>
+#include <format>
+#include <testsuite_hooks.h>
+#include <vector>
+
+#define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S)
+#define WIDEN(S) WIDEN_(CharT, S)
+
+template<typename T,
+ template<typename, typename> class Formatter = std::range_formatter>
+struct MyVector : std::vector<T>
+{
+ using std::vector<T>::vector;
+};
+
+template<typename T,
+ template<typename, typename> class Formatter,
+ typename CharT>
+struct std::formatter<MyVector<T, Formatter>, CharT>
+{
+ constexpr formatter() noexcept
+ {
+ _formatter.set_brackets(WIDEN("<"), WIDEN(">"));
+ _formatter.set_separator(WIDEN("; "));
+ }
+
+ constexpr std::basic_format_parse_context<CharT>::iterator
+ parse(std::basic_format_parse_context<CharT>& pc)
+ { return _formatter.parse(pc); }
+
+ template<typename Out>
+ typename std::basic_format_context<Out, CharT>::iterator
+ format(const MyVector<T, Formatter>& mv,
+ std::basic_format_context<Out, CharT>& fc) const
+ { return _formatter.format(mv, fc); }
+
+private:
+ Formatter<T, CharT> _formatter;
+};
+
+template<typename CharT, template<typename, typename> class Formatter>
+void
+test_default()
+{
+ MyVector<int, Formatter> vec{1, 2, 3};
+ std::basic_string<CharT> res;
+
+ res = std::format(WIDEN("{}"), vec);
+ VERIFY( res == WIDEN("<1; 2; 3>") );
+ res = std::format(WIDEN("{:}"), vec);
+ VERIFY( res == WIDEN("<1; 2; 3>") );
+ res = std::format(WIDEN("{:n}"), vec);
+ VERIFY( res == WIDEN("1; 2; 3") );
+
+ res = std::format(WIDEN("{:3}"), vec);
+ VERIFY( res == WIDEN("<1; 2; 3>") );
+
+ res = std::format(WIDEN("{:10}"), vec);
+ VERIFY( res == WIDEN("<1; 2; 3> ") );
+
+ res = std::format(WIDEN("{:{}}"), vec, 10);
+ VERIFY( res == WIDEN("<1; 2; 3> ") );
+
+ res = std::format(WIDEN("{1:{0}}"), 10, vec);
+ VERIFY( res == WIDEN("<1; 2; 3> ") );
+
+ res = std::format(WIDEN("{:10n}"), vec);
+ VERIFY( res == WIDEN("1; 2; 3 ") );
+
+ res = std::format(WIDEN("{:*<11}"), vec);
+ VERIFY( res == WIDEN("<1; 2; 3>**") );
+
+ res = std::format(WIDEN("{:->12}"), vec);
+ VERIFY( res == WIDEN("---<1; 2; 3>") );
+
+ res = std::format(WIDEN("{:=^13}"), vec);
+ VERIFY( res == WIDEN("==<1; 2; 3>==") );
+
+ res = std::format(WIDEN("{:=^13n}"), vec);
+ VERIFY( res == WIDEN("===1; 2; 3===") );
+
+ res = std::format(WIDEN("{::#x}"), vec);
+ VERIFY( res == WIDEN("<0x1; 0x2; 0x3>") );
+
+ res = std::format(WIDEN("{:|^25n:#05x}"), vec);
+ VERIFY( res == WIDEN("|||0x001; 0x002; 0x003|||") );
+
+ // ':' is start of the format string for element
+ res = std::format(WIDEN("{::^+4}"), vec);
+ VERIFY( res == WIDEN("< +1 ; +2 ; +3 >") );
+}
+
+template<typename CharT, template<typename, typename> class Formatter>
+void
+test_override()
+{
+ MyVector<CharT, Formatter> vc{'a', 'b', 'c', 'd'};
+ MyVector<std::pair<int, int>, Formatter> vp{{1, 11}, {2, 21}};
+ std::basic_string<CharT> res;
+
+ res = std::format(WIDEN("{:s}"), vc);
+ VERIFY( res == WIDEN("abcd") );
+ res = std::format(WIDEN("{:?s}"), vc);
+ VERIFY( res == WIDEN("\"abcd\"") );
+ res = std::format(WIDEN("{:+^6s}"), vc);
+ VERIFY( res == WIDEN("+abcd+") );
+
+ res = std::format(WIDEN("{:m}"), vp);
+ VERIFY( res == WIDEN("{1: 11, 2: 21}") );
+ res = std::format(WIDEN("{:=^20m}"), vp);
+ VERIFY( res == WIDEN("==={1: 11, 2: 21}===") );
+}
+
+template<template<typename, typename> class Formatter>
+void test_outputs()
+{
+ test_default<char, Formatter>();
+ test_default<wchar_t, Formatter>();
+ test_override<char, Formatter>();
+ test_override<wchar_t, Formatter>();
+}
+
+void
+test_nested()
+{
+ MyVector<MyVector<int>> v
+ {
+ {1, 2},
+ {11, 12}
+ };
+
+ std::string res = std::format("{}", v);
+ VERIFY( res == "<<1; 2>; <11; 12>>" );
+
+ res = std::format("{:+^18:n:02}", v);
+ VERIFY( res == "+<01; 02; 11; 12>+" );
+}
+
+struct MyFlatMap : std::flat_map<int, int>
+{
+ using std::flat_map<int, int>::flat_map;
+};
+
+template<typename CharT>
+struct std::formatter<MyFlatMap, CharT>
+ // This cannot apply format BitVector const&, because formatted type would
+ // be std::pair<int const&, int const&>, and formatter for
+ // pair<int const&, int> cannot format it.
+ : std::range_formatter<MyFlatMap::reference>
+{};
+
+void test_const_ref_type_mismatch()
+{
+ MyFlatMap m{{1, 11}, {2, 22}};
+ std::string res = std::format("{:m}", m);
+ VERIFY( res == "{1: 11, 2: 22}" );
+}
+
+template<typename T, typename CharT>
+using VectorFormatter = std::formatter<std::vector<T>, CharT>;
+
+int main()
+{
+ test_outputs<std::range_formatter>();
+ test_outputs<VectorFormatter>();
+ test_nested();
+ test_const_ref_type_mismatch();
+}
diff --git a/libstdc++-v3/testsuite/std/format/ranges/map.cc b/libstdc++-v3/testsuite/std/format/ranges/map.cc
new file mode 100644
index 0000000..5e1b98f
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/format/ranges/map.cc
@@ -0,0 +1,210 @@
+// { dg-do run { target c++23 } }
+// { dg-timeout-factor 2 }
+
+#include <flat_map>
+#include <format>
+#include <list>
+#include <map>
+#include <span>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+#include <vector>
+
+struct NotFormattable
+{
+ friend auto operator<=>(NotFormattable, NotFormattable) = default;
+};
+
+static_assert( !std::formattable<std::map<int, NotFormattable>, char> );
+static_assert( !std::formattable<std::map<NotFormattable, int>, wchar_t> );
+
+template<typename... Args>
+bool
+is_format_string_for(const char* str, Args&&... args)
+{
+ try {
+ (void) std::vformat(str, std::make_format_args(args...));
+ return true;
+ } catch (const std::format_error&) {
+ return false;
+ }
+}
+
+template<typename... Args>
+bool
+is_format_string_for(const wchar_t* str, Args&&... args)
+{
+ try {
+ (void) std::vformat(str, std::make_wformat_args(args...));
+ return true;
+ } catch (const std::format_error&) {
+ return false;
+ }
+}
+
+template<typename Rg, typename CharT>
+bool is_range_formatter_spec_for(CharT const* spec, Rg&& rg)
+{
+ using V = std::remove_cvref_t<std::ranges::range_reference_t<Rg>>;
+ std::range_formatter<V, CharT> fmt;
+ std::basic_format_parse_context<CharT> pc(spec);
+ try {
+ (void)fmt.parse(pc);
+ return true;
+ } catch (const std::format_error&) {
+ return false;
+ }
+}
+
+#define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S)
+#define WIDEN(S) WIDEN_(CharT, S)
+
+void
+test_format_string()
+{
+ // only pair<T, U> amd tuple<T, U> value types are supported
+ VERIFY( !is_range_formatter_spec_for("m", std::vector<int>()) );
+ VERIFY( !is_format_string_for("{:m}", std::vector<int>()) );
+ VERIFY( !is_range_formatter_spec_for("m", std::vector<std::tuple<int, int, int>>()) );
+ VERIFY( !is_format_string_for("{:m}", std::vector<std::tuple<int, int, int>>()) );
+
+ // invalid format stringss
+ VERIFY( !is_range_formatter_spec_for("?m", std::vector<std::pair<int, int>>()) );
+ VERIFY( !is_format_string_for("{:?m}", std::vector<std::pair<int, int>>()) );
+ VERIFY( !is_range_formatter_spec_for("m:", std::vector<std::pair<int, int>>()) );
+ VERIFY( !is_format_string_for("{:m:}", std::vector<std::pair<int, int>>()) );
+
+ // precision is not supported
+ VERIFY( !is_range_formatter_spec_for(".10m", std::vector<std::pair<int, int>>()) );
+ VERIFY( !is_format_string_for("{:.10m}", std::vector<std::pair<int, int>>()) );
+ VERIFY( !is_format_string_for("{:.{}m}", std::vector<std::pair<int, int>>(), 10) );
+
+ // width needs to be integer type
+ VERIFY( !is_format_string_for("{:{}m}", std::vector<std::pair<int, int>>(), 1.0f) );
+}
+
+template<typename CharT, typename Range>
+void test_output(bool mapIsDefault)
+{
+ using Sv = std::basic_string_view<CharT>;
+ using Pt = std::ranges::range_value_t<Range>;
+ using Ft = std::remove_cvref_t<std::tuple_element_t<0, Pt>>;
+ using St = std::remove_cvref_t<std::tuple_element_t<1, Pt>>;
+ auto makeRange = [](std::span<Pt> s) {
+ return Range(s.data(), s.data() + s.size());
+ };
+
+ std::basic_string<CharT> res;
+ size_t size = 0;
+
+ Ft f1[]{1, 2, 3};
+ St s1[]{11, 22, 33};
+ Pt v1[]{{f1[0], s1[0]}, {f1[1], s1[1]}, {f1[2], s1[2]}};
+
+ res = std::format(WIDEN("{}"), makeRange(v1));
+ if (mapIsDefault)
+ VERIFY( res == WIDEN("{1: 11, 2: 22, 3: 33}") );
+ else
+ VERIFY( res == WIDEN("[(1, 11), (2, 22), (3, 33)]") );
+
+ res = std::format(WIDEN("{:m}"), makeRange(v1));
+ VERIFY( res == WIDEN("{1: 11, 2: 22, 3: 33}") );
+ res = std::format(WIDEN("{:nm}"), makeRange(v1));
+ VERIFY( res == WIDEN("1: 11, 2: 22, 3: 33") );
+
+ res = std::format(WIDEN("{:3m}"), makeRange(v1));
+ VERIFY( res == WIDEN("{1: 11, 2: 22, 3: 33}") );
+
+ res = std::format(WIDEN("{:25m}"), makeRange(v1));
+ VERIFY( res == WIDEN("{1: 11, 2: 22, 3: 33} ") );
+
+ res = std::format(WIDEN("{:{}m}"), makeRange(v1), 25);
+ VERIFY( res == WIDEN("{1: 11, 2: 22, 3: 33} ") );
+
+ res = std::format(WIDEN("{1:{0}m}"), 25, makeRange(v1));
+ VERIFY( res == WIDEN("{1: 11, 2: 22, 3: 33} ") );
+
+ res = std::format(WIDEN("{:25nm}"), makeRange(v1));
+ VERIFY( res == WIDEN("1: 11, 2: 22, 3: 33 ") );
+
+ res = std::format(WIDEN("{:*<23m}"), makeRange(v1));
+ VERIFY( res == WIDEN("{1: 11, 2: 22, 3: 33}**") );
+
+ res = std::format(WIDEN("{:->24m}"), makeRange(v1));
+ VERIFY( res == WIDEN("---{1: 11, 2: 22, 3: 33}") );
+
+ res = std::format(WIDEN("{:=^25m}"), makeRange(v1));
+ VERIFY( res == WIDEN("=={1: 11, 2: 22, 3: 33}==") );
+
+ res = std::format(WIDEN("{:=^25nm}"), makeRange(v1));
+ VERIFY( res == WIDEN("===1: 11, 2: 22, 3: 33===") );
+
+ size = std::formatted_size(WIDEN("{:m}"), makeRange(v1));
+ VERIFY( size == Sv(WIDEN("{1: 11, 2: 22, 3: 33}")).size() );
+
+ size = std::formatted_size(WIDEN("{:3m}"), makeRange(v1));
+ VERIFY( size == Sv(WIDEN("{1: 11, 2: 22, 3: 33}")).size() );
+
+ size = std::formatted_size(WIDEN("{:25m}"), makeRange(v1));
+ VERIFY( size == 25 );
+}
+
+template<class Range>
+void test_output_c(bool mapIsDefault = false)
+{
+ test_output<char, Range>(mapIsDefault);
+ test_output<wchar_t, Range>(mapIsDefault);
+}
+
+template<template<typename> class RangeT>
+void test_output_pc()
+{
+ test_output_c<RangeT<std::pair<int, int>>>();
+ test_output_c<RangeT<std::pair<const int, int>>>();
+ test_output_c<RangeT<std::tuple<const int&, int&>>>();
+}
+
+void
+test_outputs()
+{
+ using namespace __gnu_test;
+ test_output_c<std::map<int, int>>(true);
+ test_output_c<std::flat_map<int, int>>(true);
+
+ test_output_pc<std::vector>();
+ test_output_pc<std::list>();
+ test_output_pc<std::span>();
+
+ test_output_pc<test_forward_range>();
+ test_output_pc<test_input_range>();
+ test_output_pc<test_input_range_nocopy>();
+}
+
+void
+test_nested()
+{
+ std::vector<std::map<int, std::string>> vm{
+ {{1, "one"}, {2, "two"}},
+ {{1, "jeden"}, {2, "dwa"}},
+ };
+ std::string res;
+
+ res = std::format("{}", vm);
+ VERIFY( res == R"([{1: "one", 2: "two"}, {1: "jeden", 2: "dwa"}])" );
+ res = std::format("{:n:n}", vm);
+ VERIFY( res == R"(1: "one", 2: "two", 1: "jeden", 2: "dwa")" );
+
+ std::map<std::string, std::vector<std::string>> mv{
+ {"english", {"zero", "one", "two"}},
+ {"polish", {"zero", "jeden", "dwa"}},
+ };
+ res = std::format("{}", mv);
+ VERIFY( res == R"({"english": ["zero", "one", "two"], "polish": ["zero", "jeden", "dwa"]})" );
+}
+
+int main()
+{
+ test_format_string();
+ test_outputs();
+ test_nested();
+}
diff --git a/libstdc++-v3/testsuite/std/format/ranges/sequence.cc b/libstdc++-v3/testsuite/std/format/ranges/sequence.cc
new file mode 100644
index 0000000..7fb65f9
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/format/ranges/sequence.cc
@@ -0,0 +1,332 @@
+// { dg-do run { target c++23 } }
+// { dg-options "-fexec-charset=UTF-8" }
+// { dg-timeout-factor 2 }
+
+#include <array>
+#include <format>
+#include <list>
+#include <ranges>
+#include <span>
+#include <string>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+#include <vector>
+
+struct NotFormattable
+{};
+
+static_assert(!std::formattable<std::vector<NotFormattable>, char>);
+static_assert(!std::formattable<std::span<NotFormattable>, wchar_t>);
+
+template<typename... Args>
+bool
+is_format_string_for(const char* str, Args&&... args)
+{
+ try {
+ (void) std::vformat(str, std::make_format_args(args...));
+ return true;
+ } catch (const std::format_error&) {
+ return false;
+ }
+}
+
+template<typename... Args>
+bool
+is_format_string_for(const wchar_t* str, Args&&... args)
+{
+ try {
+ (void) std::vformat(str, std::make_wformat_args(args...));
+ return true;
+ } catch (const std::format_error&) {
+ return false;
+ }
+}
+
+template<typename Rg, typename CharT>
+bool is_range_formatter_spec_for(CharT const* spec, Rg&& rg)
+{
+ using V = std::remove_cvref_t<std::ranges::range_reference_t<Rg>>;
+ std::range_formatter<V, CharT> fmt;
+ std::basic_format_parse_context<CharT> pc(spec);
+ try {
+ (void)fmt.parse(pc);
+ return true;
+ } catch (const std::format_error&) {
+ return false;
+ }
+}
+
+void
+test_format_string()
+{
+ // invalid format spec 'p'
+ VERIFY( !is_range_formatter_spec_for("p", std::vector<int>()) );
+ VERIFY( !is_format_string_for("{:p}", std::vector<int>()) );
+ VERIFY( !is_range_formatter_spec_for("np", std::vector<int>()) );
+ VERIFY( !is_format_string_for("{:np}", std::vector<int>()) );
+
+ // width needs to be integer type
+ VERIFY( !is_format_string_for("{:{}}", std::vector<int>(), 1.0f) );
+
+ // element format needs to be valid
+ VERIFY( !is_range_formatter_spec_for(":p", std::vector<int>()) );
+ VERIFY( !is_format_string_for("{::p}", std::vector<int>()) );
+ VERIFY( !is_range_formatter_spec_for("n:p", std::vector<int>()) );
+ VERIFY( !is_format_string_for("{:n:p}", std::vector<int>()) );
+}
+
+#define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S)
+#define WIDEN(S) WIDEN_(CharT, S)
+
+template<typename CharT, typename Range, typename Storage>
+void test_output()
+{
+ using Sv = std::basic_string_view<CharT>;
+ using T = std::ranges::range_value_t<Range>;
+ auto makeRange = [](Storage& s) -> Range {
+ if constexpr (std::is_same_v<std::remove_cvref_t<Range>, Storage>)
+ return s;
+ else
+ return Range(std::ranges::data(s),
+ std::ranges::data(s) + std::ranges::size(s));
+ };
+
+ std::basic_string<CharT> res;
+ size_t size = 0;
+
+ Storage v1{1, 2, 3};
+ res = std::format(WIDEN("{}"), makeRange(v1));
+ VERIFY( res == WIDEN("[1, 2, 3]") );
+ res = std::format(WIDEN("{:}"), makeRange(v1));
+ VERIFY( res == WIDEN("[1, 2, 3]") );
+ res = std::format(WIDEN("{:n}"), makeRange(v1));
+ VERIFY( res == WIDEN("1, 2, 3") );
+
+ res = std::format(WIDEN("{:3}"), makeRange(v1));
+ VERIFY( res == WIDEN("[1, 2, 3]") );
+
+ res = std::format(WIDEN("{:10}"), makeRange(v1));
+ VERIFY( res == WIDEN("[1, 2, 3] ") );
+
+ res = std::format(WIDEN("{:{}}"), makeRange(v1), 10);
+ VERIFY( res == WIDEN("[1, 2, 3] ") );
+
+ res = std::format(WIDEN("{1:{0}}"), 10, makeRange(v1));
+ VERIFY( res == WIDEN("[1, 2, 3] ") );
+
+ res = std::format(WIDEN("{:10n}"), makeRange(v1));
+ VERIFY( res == WIDEN("1, 2, 3 ") );
+
+ res = std::format(WIDEN("{:*<11}"), makeRange(v1));
+ VERIFY( res == WIDEN("[1, 2, 3]**") );
+
+ res = std::format(WIDEN("{:->12}"), makeRange(v1));
+ VERIFY( res == WIDEN("---[1, 2, 3]") );
+
+ res = std::format(WIDEN("{:=^13}"), makeRange(v1));
+ VERIFY( res == WIDEN("==[1, 2, 3]==") );
+
+ res = std::format(WIDEN("{:=^13n}"), makeRange(v1));
+ VERIFY( res == WIDEN("===1, 2, 3===") );
+
+ res = std::format(WIDEN("{::#x}"), makeRange(v1));
+ VERIFY( res == WIDEN("[0x1, 0x2, 0x3]") );
+
+ res = std::format(WIDEN("{:|^25n:#05x}"), makeRange(v1));
+ VERIFY( res == WIDEN("|||0x001, 0x002, 0x003|||") );
+
+ // ':' is start of the format string for element
+ res = std::format(WIDEN("{::^+04}"), makeRange(v1));
+ VERIFY( res == WIDEN("[ +1 , +2 , +3 ]") );
+
+ size = std::formatted_size(WIDEN("{:}"), makeRange(v1));
+ VERIFY( size == Sv(WIDEN("[1, 2, 3]")).size() );
+
+ size = std::formatted_size(WIDEN("{:3}"), makeRange(v1));
+ VERIFY( size == Sv(WIDEN("[1, 2, 3]")).size() );
+
+ size = std::formatted_size(WIDEN("{:10}"), makeRange(v1));
+ VERIFY( size == 10 );
+
+ size = std::formatted_size(WIDEN("{:|^25n:#05x}"), makeRange(v1));
+ VERIFY( size == 25 );
+}
+
+template<typename Cont>
+void test_output_cont()
+{
+ test_output<char, Cont&, Cont>();
+ test_output<wchar_t, Cont const&, Cont>();
+}
+
+template<typename View>
+void test_output_view()
+{
+ test_output<char, View, int[3]>();
+ test_output<wchar_t, View, int[3]>();
+}
+
+void
+test_outputs()
+{
+ using namespace __gnu_test;
+ test_output_cont<std::vector<int>>();
+ test_output_cont<std::list<int>>();
+ test_output_cont<std::array<int, 3>>();
+
+ test_output_view<std::span<int>>();
+ test_output_view<std::ranges::subrange<int*>>();
+ test_output_view<test_forward_range<int>>();
+ test_output_view<test_input_range<int>>();
+ test_output_view<test_input_range_nocopy<int>>();
+
+ test_output_view<std::span<const int>>();
+ test_output_view<std::ranges::subrange<const int*>>();
+ test_output_view<test_forward_range<const int>>();
+}
+
+void
+test_nested()
+{
+ std::vector<std::vector<int>> v
+ {
+ {1, 2},
+ {11, 12}
+ };
+
+ std::string res = std::format("{}", v);
+ VERIFY( res == "[[1, 2], [11, 12]]" );
+
+ res = std::format("{:+^18:n:02}", v);
+ VERIFY( res == "+[01, 02, 11, 12]+" );
+}
+
+bool strip_quote(std::string_view& v)
+{
+ if (!v.starts_with('"'))
+ return false;
+ v.remove_prefix(1);
+ return true;
+}
+
+bool strip_prefix(std::string_view& v, std::string_view expected, bool quoted = false)
+{
+ if (quoted && !strip_quote(v))
+ return false;
+ if (!v.starts_with(expected))
+ return false;
+ v.remove_prefix(expected.size());
+ if (quoted && !strip_quote(v))
+ return false;
+ return true;
+}
+
+bool strip_squares(std::string_view& v)
+{
+ if (!v.starts_with('[') || !v.ends_with(']'))
+ return false;
+ v.remove_prefix(1);
+ v.remove_suffix(1);
+ return true;
+}
+
+bool strip_prefix(std::string_view& v, size_t n, char c)
+{
+ size_t pos = v.find_first_not_of(c);
+ if (pos == std::string_view::npos)
+ pos = v.size();
+ if (pos != n)
+ return false;
+ v.remove_prefix(n);
+ return true;
+}
+
+void test_padding()
+{
+ std::string res;
+ std::string_view resv;
+
+ // width is 3, size is 15
+ std::string in = "o\u0302\u0323i\u0302\u0323u\u0302\u0323";
+ in += in; // width is 6, size is 30
+ in += in; // width is 12, size is 60
+ in += in; // width is 24, size is 120
+ in += in; // width is 48, size is 240
+ // width is 192, size is 960
+ std::vector<std::string> const vs{in, in, in, in};
+
+ auto const check_elems = [=](std::string_view& v, bool quoted)
+ {
+ VERIFY( strip_prefix(v, in, quoted) );
+ VERIFY( strip_prefix(v, ", ", false) );
+ VERIFY( strip_prefix(v, in, quoted) );
+ VERIFY( strip_prefix(v, ", ", false) );
+ VERIFY( strip_prefix(v, in, quoted) );
+ VERIFY( strip_prefix(v, ", ", false) );
+ VERIFY( strip_prefix(v, in, quoted) );
+ return v.empty();
+ };
+
+ resv = res = std::format("{}", vs);
+ VERIFY( strip_squares(resv) );
+ VERIFY( check_elems(resv, true) );
+
+ resv = res = std::format("{:n}", vs);
+ VERIFY( check_elems(resv, true) );
+
+ resv = res = std::format("{::}", vs);
+ VERIFY( strip_squares(resv) );
+ VERIFY( check_elems(resv, false) );
+
+ resv = res = std::format("{:n:}", vs);
+ VERIFY( check_elems(resv, false) );
+
+ resv = res = std::format("{:*>10}", vs);
+ VERIFY( strip_squares(resv) );
+ VERIFY( check_elems(resv, true) );
+
+ resv = res = std::format("{:*>10n}", vs);
+ VERIFY( check_elems(resv, true) );
+
+ resv = res = std::format("{:*>10:}", vs);
+ VERIFY( strip_squares(resv) );
+ VERIFY( check_elems(resv, false) );
+
+ resv = res = std::format("{:*>10n:}", vs);
+ VERIFY( check_elems(resv, false) );
+
+ resv = res = std::format("{:*>256}", vs);
+ VERIFY( strip_prefix(resv, 48, '*') );
+ VERIFY( strip_squares(resv) );
+ VERIFY( check_elems(resv, true) );
+
+ resv = res = std::format("{:*>256n}", vs);
+ VERIFY( strip_prefix(resv, 50, '*') );
+ VERIFY( check_elems(resv, true) );
+
+ resv = res = std::format("{:*>240}", vs);
+ VERIFY( strip_prefix(resv, 32, '*') );
+ VERIFY( strip_squares(resv) );
+ VERIFY( check_elems(resv, true) );
+
+ resv = res = std::format("{:*>240n}", vs);
+ VERIFY( strip_prefix(resv, 34, '*') );
+ VERIFY( check_elems(resv, true) );
+
+ resv = res = std::format("{:*>240:}", vs);
+ VERIFY( strip_prefix(resv, 40, '*') );
+ VERIFY( strip_squares(resv) );
+ VERIFY( check_elems(resv, false) );
+
+ resv = res = std::format("{:*>240n:}", vs);
+ VERIFY( strip_prefix(resv, 42, '*') );
+ VERIFY( check_elems(resv, false) );
+}
+
+int main()
+{
+ test_format_string();
+ test_outputs();
+ test_nested();
+ test_padding();
+}
diff --git a/libstdc++-v3/testsuite/std/format/ranges/string.cc b/libstdc++-v3/testsuite/std/format/ranges/string.cc
new file mode 100644
index 0000000..99e5eaf
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/format/ranges/string.cc
@@ -0,0 +1,290 @@
+// { dg-do run { target c++23 } }
+// { dg-options "-fexec-charset=UTF-8" }
+// { dg-timeout-factor 2 }
+
+#include <format>
+#include <forward_list>
+#include <span>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+#include <vector>
+
+template<typename... Args>
+bool
+is_format_string_for(const char* str, Args&&... args)
+{
+ try {
+ (void) std::vformat(str, std::make_format_args(args...));
+ return true;
+ } catch (const std::format_error&) {
+ return false;
+ }
+}
+
+template<typename... Args>
+bool
+is_format_string_for(const wchar_t* str, Args&&... args)
+{
+ try {
+ (void) std::vformat(str, std::make_wformat_args(args...));
+ return true;
+ } catch (const std::format_error&) {
+ return false;
+ }
+}
+
+template<typename Rg, typename CharT>
+bool is_range_formatter_spec_for(CharT const* spec, Rg&& rg)
+{
+ using V = std::remove_cvref_t<std::ranges::range_reference_t<Rg>>;
+ std::range_formatter<V, CharT> fmt;
+ std::basic_format_parse_context<CharT> pc(spec);
+ try {
+ (void)fmt.parse(pc);
+ return true;
+ } catch (const std::format_error&) {
+ return false;
+ }
+}
+
+#define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S)
+#define WIDEN(S) WIDEN_(CharT, S)
+
+void
+test_format_string()
+{
+ // only CharT value types are supported
+ VERIFY( !is_range_formatter_spec_for(L"s", std::vector<char>()) );
+ VERIFY( !is_format_string_for(L"{:s}", std::vector<char>()) );
+ VERIFY( !is_range_formatter_spec_for(L"s", std::vector<char>()) );
+ VERIFY( !is_format_string_for(L"{:s}", std::vector<char>()) );
+ VERIFY( !is_range_formatter_spec_for("s", std::vector<int>()) );
+ VERIFY( !is_format_string_for("{:s}", std::vector<int>()) );
+
+ // invalid format stringss
+ VERIFY( !is_range_formatter_spec_for("?", std::vector<char>()) );
+ VERIFY( !is_format_string_for("{:?}", std::vector<char>()) );
+ VERIFY( !is_range_formatter_spec_for("ns", std::vector<char>()) );
+ VERIFY( !is_format_string_for("{:ns}", std::vector<char>()) );
+ VERIFY( !is_range_formatter_spec_for("s:", std::vector<char>()) );
+ VERIFY( !is_format_string_for("{:s:}", std::vector<char>()) );
+
+ // precision is not supported, even for s
+ VERIFY( !is_range_formatter_spec_for(".10s", std::vector<char>()) );
+ VERIFY( !is_format_string_for("{:.10s}", std::vector<char>()) );
+ VERIFY( !is_format_string_for("{:.{}s}", std::vector<char>(), 10) );
+
+ // width needs to be integer type
+ VERIFY( !is_format_string_for("{:{}s}", std::vector<char>(), 1.0f) );
+}
+
+template<typename Range>
+void test_output()
+{
+ using CharT = std::ranges::range_value_t<Range>;
+ auto makeRange = [](std::basic_string<CharT>& s) {
+ return Range(s.data(), s.data() + s.size());
+ };
+ std::basic_string<CharT> res;
+ size_t size = 0;
+
+ std::basic_string<CharT> s1 = WIDEN("abcd");
+ res = std::format(WIDEN("{}"), makeRange(s1));
+ VERIFY( res == WIDEN("['a', 'b', 'c', 'd']") );
+
+ res = std::format(WIDEN("{::}"), makeRange(s1));
+ VERIFY( res == WIDEN("[a, b, c, d]") );
+
+ res = std::format(WIDEN("{:s}"), makeRange(s1));
+ VERIFY( res == WIDEN("abcd") );
+
+ res = std::format(WIDEN("{:?s}"), makeRange(s1));
+ VERIFY( res == WIDEN(R"("abcd")") );
+
+ res = std::format(WIDEN("{:3s}"), makeRange(s1));
+ VERIFY( res == WIDEN("abcd") );
+
+ res = std::format(WIDEN("{:7s}"), makeRange(s1));
+ VERIFY( res == WIDEN("abcd ") );
+
+ res = std::format(WIDEN("{:{}s}"), makeRange(s1), 7);
+ VERIFY( res == WIDEN("abcd ") );
+
+ res = std::format(WIDEN("{1:{0}s}"), 7, makeRange(s1));
+ VERIFY( res == WIDEN("abcd ") );
+
+ res = std::format(WIDEN("{:*>6s}"), makeRange(s1));
+ VERIFY( res == WIDEN("**abcd") );
+
+ res = std::format(WIDEN("{:-<5s}"), makeRange(s1));
+ VERIFY( res == WIDEN("abcd-") );
+
+ res = std::format(WIDEN("{:=^8s}"), makeRange(s1));
+ VERIFY( res == WIDEN("==abcd==") );
+
+ std::basic_string<CharT> s2(512, static_cast<CharT>('a'));
+ res = std::format(WIDEN("{:=^8s}"), makeRange(s2));
+ VERIFY( res == s2 );
+
+ size = std::formatted_size(WIDEN("{:s}"), makeRange(s1));
+ VERIFY( size == 4 );
+
+ size = std::formatted_size(WIDEN("{:3s}"), makeRange(s1));
+ VERIFY( size == 4 );
+
+ size = std::formatted_size(WIDEN("{:7s}"), makeRange(s1));
+ VERIFY( size == 7 );
+
+ size = std::formatted_size(WIDEN("{:s}"), makeRange(s2));
+ VERIFY( size == 512 );
+}
+
+template<typename CharT>
+struct cstr_view
+{
+ cstr_view() = default;
+ explicit cstr_view(CharT* f, CharT* l)
+ : ptr(f)
+ { VERIFY(!*l); }
+
+ struct sentinel
+ {
+ friend constexpr
+ bool operator==(CharT const* ptr, sentinel) noexcept
+ { return !*ptr; }
+ };
+
+ constexpr
+ CharT* begin() const noexcept
+ { return ptr; };
+ static constexpr
+ sentinel end() noexcept
+ { return {}; }
+
+private:
+ CharT* ptr = "";
+};
+
+template<typename CharT>
+void
+test_outputs()
+{
+ using namespace __gnu_test;
+ test_output<std::vector<CharT>>();
+ test_output<std::span<CharT>>();
+ test_output<cstr_view<CharT>>();
+
+ test_output<test_forward_range<CharT>>();
+ test_output<test_forward_sized_range<CharT>>();
+
+ test_output<test_input_range<CharT>>();
+ test_output<test_input_sized_range<CharT>>();
+
+ test_output<test_range_nocopy<CharT, input_iterator_wrapper_nocopy>>();
+ test_output<test_sized_range<CharT, input_iterator_wrapper_nocopy>>();
+
+ test_output<std::span<const CharT>>();
+ test_output<cstr_view<const CharT>>();
+ test_output<test_forward_range<const CharT>>();
+
+ static_assert(!std::formattable<std::span<volatile CharT>, CharT>);
+ static_assert(!std::formattable<std::span<const volatile CharT>, CharT>);
+}
+
+void
+test_nested()
+{
+ std::string_view s1 = "str1";
+ std::string_view s2 = "str2";
+
+ std::vector<std::string> vs;
+ vs.emplace_back(s1);
+ vs.emplace_back(s2);
+
+ VERIFY( std::format("{}", vs) == R"(["str1", "str2"])" );
+ VERIFY( std::format("{:}", vs) == R"(["str1", "str2"])" );
+ VERIFY( std::format("{::?}", vs) == R"(["str1", "str2"])" );
+ VERIFY( std::format("{::}", vs) == R"([str1, str2])" );
+
+ std::vector<std::vector<char>> vv;
+ vv.emplace_back(s1.begin(), s1.end());
+ vv.emplace_back(s2.begin(), s2.end());
+ std::string_view escaped = R"([['s', 't', 'r', '1'], ['s', 't', 'r', '2']])";
+
+ VERIFY( std::format("{}", vv) == escaped );
+ VERIFY( std::format("{:}", vv) == escaped );
+ VERIFY( std::format("{::}", vv) == escaped );
+ VERIFY( std::format("{:::?}", vv) == escaped );
+ VERIFY( std::format("{:::}", vv) == R"([[s, t, r, 1], [s, t, r, 2]])" );
+ VERIFY( std::format("{::s}", vv) == R"([str1, str2])" );
+ VERIFY( std::format("{::?s}", vv) == R"(["str1", "str2"])" );
+}
+
+bool strip_quotes(std::string_view& v)
+{
+ if (!v.starts_with('"') || !v.ends_with('"'))
+ return false;
+ v.remove_prefix(1);
+ v.remove_suffix(1);
+ return true;
+}
+
+bool strip_prefix(std::string_view& v, size_t n, char c)
+{
+ size_t pos = v.find_first_not_of(c);
+ if (pos == std::string_view::npos)
+ pos = v.size();
+ if (pos != n)
+ return false;
+ v.remove_prefix(n);
+ return true;
+}
+
+
+void test_padding()
+{
+ std::string res;
+ std::string_view resv;
+
+ // width is 3, size is 15
+ std::string in = "o\u0302\u0323i\u0302\u0323u\u0302\u0323";
+ in += in; // width is 6, size is 30
+ in += in; // width is 12, size is 60
+ in += in; // width is 24, size is 120
+ in += in; // width is 48, size is 240
+ in += in; // width is 96, size is 480
+ in += in; // width is 192, size is 960
+
+ std::forward_list<char> lc(std::from_range, in);
+
+ resv = res = std::format("{:s}", lc);
+ VERIFY( resv == in );
+
+ resv = res = std::format("{:*>10s}", lc);
+ VERIFY( resv == in );
+
+ resv = res = std::format("{:*>240s}", lc);
+ VERIFY( strip_prefix(resv, 48, '*') );
+ VERIFY( resv == in );
+
+ resv = res = std::format("{:?s}", lc);
+ VERIFY( strip_quotes(resv) );
+ VERIFY( resv == in );
+
+ resv = res = std::format("{:*>10?s}", lc);
+ VERIFY( strip_quotes(resv) );
+ VERIFY( resv == in );
+
+ resv = res = std::format("{:*>240?s}", lc);
+ VERIFY( strip_prefix(resv, 46, '*') );
+ VERIFY( strip_quotes(resv) );
+ VERIFY( resv == in );
+}
+
+int main()
+{
+ test_format_string();
+ test_outputs<char>();
+ test_outputs<wchar_t>();
+ test_nested();
+}
diff --git a/libstdc++-v3/testsuite/std/format/tuple.cc b/libstdc++-v3/testsuite/std/format/tuple.cc
new file mode 100644
index 0000000..ba6dae8
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/format/tuple.cc
@@ -0,0 +1,351 @@
+// { dg-do run { target c++23 } }
+// { dg-options "-fexec-charset=UTF-8" }
+// { dg-timeout-factor 2 }
+
+#include <format>
+#include <string>
+#include <testsuite_hooks.h>
+#include <tuple>
+#include <utility>
+
+struct NotFormattable
+{};
+
+static_assert( !std::formattable<std::pair<int, NotFormattable>, char> );
+static_assert( !std::formattable<std::tuple<int, NotFormattable, int>, wchar_t> );
+
+template<typename... Args>
+bool
+is_format_string_for(const char* str, Args&&... args)
+{
+ try {
+ (void) std::vformat(str, std::make_format_args(args...));
+ return true;
+ } catch (const std::format_error&) {
+ return false;
+ }
+}
+
+template<typename... Args>
+bool
+is_format_string_for(const wchar_t* str, Args&&... args)
+{
+ try {
+ (void) std::vformat(str, std::make_wformat_args(args...));
+ return true;
+ } catch (const std::format_error&) {
+ return false;
+ }
+}
+
+#define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S)
+#define WIDEN(S) WIDEN_(CharT, S)
+
+void
+test_format_string()
+{
+ // invalid format stringss
+ VERIFY( !is_format_string_for("{:p}", std::tuple<>()) );
+ VERIFY( !is_format_string_for("{:nm}", std::tuple<>()) );
+
+ // 'm' is only valid for 2 elemenst
+ VERIFY( !is_format_string_for("{:m}", std::tuple<>()) );
+ VERIFY( !is_format_string_for("{:m}", std::tuple<int, int, int>()) );
+
+ // element specifier is not supported
+ VERIFY( !is_format_string_for("{::}", std::tuple<>()) );
+
+ // precision is not supported
+ VERIFY( !is_format_string_for("{:.10}", std::tuple<>()) );
+
+ // width needs to be integer type
+ VERIFY( !is_format_string_for("{:{}}", std::tuple<>(), 1.0f) );
+}
+
+template<typename CharT>
+void test_multi()
+{
+ using Sv = std::basic_string_view<CharT>;
+ using Str = std::basic_string<CharT>;
+
+ std::basic_string<CharT> res;
+ std::size_t size = 0;
+ std::tuple<int, Str, float> t1(1, WIDEN("test"), 2.1);
+
+ res = std::format(WIDEN("{}"), t1);
+ VERIFY( res == WIDEN(R"((1, "test", 2.1))") );
+ res = std::format(WIDEN("{:}"), t1);
+ VERIFY( res == WIDEN(R"((1, "test", 2.1))") );
+ res = std::format(WIDEN("{:n}"), t1);
+ VERIFY( res == WIDEN(R"(1, "test", 2.1)") );
+
+ res = std::format(WIDEN("{:3}"), t1);
+ VERIFY( res == WIDEN(R"((1, "test", 2.1))") );
+
+ res = std::format(WIDEN("{:20}"), t1);
+ VERIFY( res == WIDEN(R"((1, "test", 2.1) )") );
+
+ res = std::format(WIDEN("{:{}}"), t1, 20);
+ VERIFY( res == WIDEN(R"((1, "test", 2.1) )") );
+
+ res = std::format(WIDEN("{1:{0}}"), 20, t1);
+ VERIFY( res == WIDEN(R"((1, "test", 2.1) )") );
+
+ res = std::format(WIDEN("{:^>17}"), t1);
+ VERIFY( res == WIDEN(R"(^(1, "test", 2.1))") );
+
+ res = std::format(WIDEN("{:$<18}"), t1);
+ VERIFY( res == WIDEN(R"((1, "test", 2.1)$$)") );
+
+ res = std::format(WIDEN("{:+^19}"), t1);
+ VERIFY( res == WIDEN(R"(+(1, "test", 2.1)++)") );
+
+ res = std::format(WIDEN("{:|^19n}"), t1);
+ VERIFY( res == WIDEN(R"(||1, "test", 2.1|||)") );
+
+ size = std::formatted_size(WIDEN("{}"), t1);
+ VERIFY( size == Sv(WIDEN(R"((1, "test", 2.1))")).size() );
+
+ size = std::formatted_size(WIDEN("{:3}"), t1);
+ VERIFY( size == Sv(WIDEN(R"((1, "test", 2.1))")).size() );
+
+ size = std::formatted_size(WIDEN("{:20}"), t1);
+ VERIFY( size == 20 );
+
+ std::tuple<int&, Str&, float&> t2 = t1;
+ res = std::format(WIDEN("{}"), t2);
+ VERIFY( res == WIDEN(R"((1, "test", 2.1))") );
+
+ std::tuple<int, int, int, int> t3(1, 2, 3, 4);
+ res = std::format(WIDEN("{}"), t3);
+ VERIFY( res == WIDEN(R"((1, 2, 3, 4))") );
+
+}
+
+template<typename CharT, typename Tuple>
+void test_empty()
+{
+ std::basic_string<CharT> res;
+
+ Tuple e1;
+ res = std::format(WIDEN("{}"), e1);
+ VERIFY( res == WIDEN(R"(())") );
+
+ res = std::format(WIDEN("{:}"), e1);
+ VERIFY( res == WIDEN(R"(())") );
+
+ res = std::format(WIDEN("{:n}"), e1);
+ VERIFY( res == WIDEN(R"()") );
+
+ res = std::format(WIDEN("{:^>6}"), e1);
+ VERIFY( res == WIDEN(R"(^^^^())") );
+}
+
+template<typename CharT, typename Pair>
+void test_pair()
+{
+ using Ft = std::remove_cvref_t<std::tuple_element_t<0, Pair>>;
+ using St = std::remove_cvref_t<std::tuple_element_t<1, Pair>>;
+
+ std::basic_string<CharT> res;
+
+ Ft f1 = 1;
+ St s1 = WIDEN("abc");
+ Pair p1(f1, s1);
+
+ res = std::format(WIDEN("{}"), p1);
+ VERIFY( res == WIDEN(R"((1, "abc"))") );
+
+ res = std::format(WIDEN("{:}"), p1);
+ VERIFY( res == WIDEN(R"((1, "abc"))") );
+
+ res = std::format(WIDEN("{:m}"), p1);
+ VERIFY( res == WIDEN(R"(1: "abc")") );
+
+ res = std::format(WIDEN("{:|^12m}"), p1);
+ VERIFY( res == WIDEN(R"(||1: "abc"||)") );
+}
+
+template<typename CharT, template<typename, typename> class PairT>
+void test_pair_e()
+{
+ test_pair<CharT, PairT<int, std::basic_string<CharT>>>();
+ test_pair<CharT, PairT<int, const CharT*>>();
+ test_pair<CharT, PairT<const int, std::basic_string<CharT>>>();
+ test_pair<CharT, PairT<int&, std::basic_string<CharT>&>>();
+ test_pair<CharT, PairT<const int&, const std::basic_string<CharT>&>>();
+}
+
+template<typename Pair>
+struct MyPair : Pair
+{
+ using Pair::Pair;
+};
+
+template<typename Pair, typename CharT>
+struct std::formatter<MyPair<Pair>, CharT>
+{
+ constexpr formatter() noexcept
+ {
+ _formatter.set_brackets(WIDEN("<"), WIDEN(">"));
+ _formatter.set_separator(WIDEN("; "));
+ }
+
+ constexpr std::basic_format_parse_context<CharT>::iterator
+ parse(std::basic_format_parse_context<CharT>& pc)
+ { return _formatter.parse(pc); }
+
+ template<typename Out>
+ typename std::basic_format_context<Out, CharT>::iterator
+ format(const MyPair<Pair>& mp,
+ std::basic_format_context<Out, CharT>& fc) const
+ { return _formatter.format(mp, fc); }
+
+private:
+ std::formatter<Pair, CharT> _formatter;
+};
+
+template<typename CharT, template<typename, typename> class PairT>
+void test_custom()
+{
+ std::basic_string<CharT> res;
+ MyPair<PairT<int, const CharT*>> c1(1, WIDEN("abc"));
+
+ res = std::format(WIDEN("{}"), c1);
+ VERIFY( res == WIDEN(R"(<1; "abc">)") );
+
+ res = std::format(WIDEN("{:}"), c1);
+ VERIFY( res == WIDEN(R"(<1; "abc">)") );
+
+ res = std::format(WIDEN("{:n}"), c1);
+ VERIFY( res == WIDEN(R"(1; "abc")") );
+
+ res = std::format(WIDEN("{:m}"), c1);
+ VERIFY( res == WIDEN(R"(1: "abc")") );
+
+ res = std::format(WIDEN("{:|^14}"), c1);
+ VERIFY( res == WIDEN(R"(||<1; "abc">||)") );
+}
+
+template<typename CharT>
+void test_outputs()
+{
+ test_multi<CharT>();
+ test_empty<CharT, std::tuple<>>();
+ test_pair_e<CharT, std::pair>();
+ test_pair_e<CharT, std::tuple>();
+ test_custom<CharT, std::pair>();
+ test_custom<CharT, std::tuple>();
+}
+
+void test_nested()
+{
+ std::string res;
+ std::tuple<std::tuple<>, std::pair<int, std::string>> tt{{}, {1, "abc"}};
+
+ res = std::format("{}", tt);
+ VERIFY( res == R"(((), (1, "abc")))" );
+ res = std::format("{:n}", tt);
+ VERIFY( res == R"((), (1, "abc"))" );
+ res = std::format("{:m}", tt);
+ VERIFY( res == R"((): (1, "abc"))" );
+}
+
+bool strip_quote(std::string_view& v)
+{
+ if (!v.starts_with('"'))
+ return false;
+ v.remove_prefix(1);
+ return true;
+}
+
+bool strip_prefix(std::string_view& v, std::string_view expected, bool quoted = false)
+{
+ if (quoted && !strip_quote(v))
+ return false;
+ if (!v.starts_with(expected))
+ return false;
+ v.remove_prefix(expected.size());
+ if (quoted && !strip_quote(v))
+ return false;
+ return true;
+}
+
+bool strip_parens(std::string_view& v)
+{
+ if (!v.starts_with('(') || !v.ends_with(')'))
+ return false;
+ v.remove_prefix(1);
+ v.remove_suffix(1);
+ return true;
+}
+
+bool strip_prefix(std::string_view& v, size_t n, char c)
+{
+ size_t pos = v.find_first_not_of(c);
+ if (pos == std::string_view::npos)
+ pos = v.size();
+ if (pos != n)
+ return false;
+ v.remove_prefix(n);
+ return true;
+}
+
+void test_padding()
+{
+ std::string res;
+ std::string_view resv;
+
+ // width is 3, size is 15
+ std::string in = "o\u0302\u0323i\u0302\u0323u\u0302\u0323";
+ in += in; // width is 6, size is 30
+ in += in; // width is 12, size is 60
+ in += in; // width is 24, size is 120
+ in += in; // width is 48, size is 240
+ // width is 192, size is 960
+ auto const ts = std::make_tuple(in, in, in, in);
+
+ auto const check_elems = [=](std::string_view& v)
+ {
+ VERIFY( strip_prefix(v, in, true) );
+ VERIFY( strip_prefix(v, ", ", false) );
+ VERIFY( strip_prefix(v, in, true) );
+ VERIFY( strip_prefix(v, ", ", false) );
+ VERIFY( strip_prefix(v, in, true) );
+ VERIFY( strip_prefix(v, ", ", false) );
+ VERIFY( strip_prefix(v, in, true) );
+ return v.empty();
+ };
+
+ resv = res = std::format("{}", ts);
+ VERIFY( strip_parens(resv) );
+ VERIFY( check_elems(resv) );
+
+ resv = res = std::format("{:n}", ts);
+ VERIFY( check_elems(resv) );
+
+ resv = res = std::format("{:*>10}", ts);
+ VERIFY( strip_parens(resv) );
+ VERIFY( check_elems(resv) );
+
+ resv = res = std::format("{:*>10n}", ts);
+ VERIFY( check_elems(resv) );
+
+ resv = res = std::format("{:*>240}", ts);
+ VERIFY( strip_prefix(resv, 32, '*') );
+ VERIFY( strip_parens(resv) );
+ VERIFY( check_elems(resv) );
+
+ resv = res = std::format("{:*>240n}", ts);
+ VERIFY( strip_prefix(resv, 34, '*') );
+ VERIFY( check_elems(resv) );
+}
+
+int main()
+{
+ test_format_string();
+ test_outputs<char>();
+ test_outputs<wchar_t>();
+ test_nested();
+ test_padding();
+}
diff --git a/libstdc++-v3/testsuite/std/memory/indirect/copy.cc b/libstdc++-v3/testsuite/std/memory/indirect/copy.cc
new file mode 100644
index 0000000..0ac6e92
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/memory/indirect/copy.cc
@@ -0,0 +1,121 @@
+// { dg-do run { target c++26 } }
+
+#include <memory>
+#include <scoped_allocator>
+#include <utility>
+#include <vector>
+
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+using __gnu_test::tracker_allocator;
+using Counter = __gnu_test::tracker_allocator_counter;
+using Vector = std::vector<int>;
+using Indirect = std::indirect<Vector, tracker_allocator<Vector>>;
+const Indirect src(std::in_place, {1, 2, 3});
+
+constexpr void
+test_ctor()
+{
+ Counter::reset();
+ Indirect i1(src);
+ VERIFY( *i1 == *src );
+ VERIFY( &*i1 != &*src );
+ VERIFY( Counter::get_allocation_count() == sizeof(Vector) );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 1 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+
+ Counter::reset();
+ Indirect i2(std::allocator_arg, {}, src);
+ VERIFY( *i2 == *src );
+ VERIFY( &*i2 != &*src );
+ VERIFY( Counter::get_allocation_count() == sizeof(Vector) );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 1 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+}
+
+constexpr void
+test_assign()
+{
+ Indirect i1;
+ Counter::reset();
+
+ i1 = src;
+ VERIFY( *i1 == *src );
+ VERIFY( &*i1 != &*src );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+
+ auto(std::move(i1));
+ Counter::reset();
+
+ i1 = src;
+ VERIFY( *i1 == *src );
+ VERIFY( &*i1 != &*src );
+ VERIFY( Counter::get_allocation_count() == sizeof(Vector) );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 1 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+}
+
+constexpr void
+test_valueless()
+{
+ Indirect e;
+ auto(std::move(e));
+ VERIFY( e.valueless_after_move() );
+
+ Counter::reset();
+ Indirect i1(e);
+ VERIFY( i1.valueless_after_move() );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+
+ Indirect i2(std::allocator_arg, {}, e);
+ VERIFY( i2.valueless_after_move() );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+
+ Indirect i3(src);
+ Counter::reset();
+ i3 = e;
+ VERIFY( i3.valueless_after_move() );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() == sizeof(Vector) );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 1 );
+
+ Counter::reset();
+ i3 = e;
+ VERIFY( i3.valueless_after_move() );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+}
+
+constexpr void
+test_all()
+{
+ test_ctor();
+ test_assign();
+ test_valueless();
+}
+
+int main()
+{
+ test_all();
+
+ static_assert([] {
+ test_all();
+ return true;
+ });
+}
diff --git a/libstdc++-v3/testsuite/std/memory/indirect/copy_alloc.cc b/libstdc++-v3/testsuite/std/memory/indirect/copy_alloc.cc
new file mode 100644
index 0000000..d5865b9
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/memory/indirect/copy_alloc.cc
@@ -0,0 +1,228 @@
+// { dg-do run { target c++26 } }
+
+#include <memory>
+#include <scoped_allocator>
+#include <utility>
+#include <vector>
+
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+using __gnu_test::propagating_allocator;
+using __gnu_test::tracker_allocator;
+using Counter = __gnu_test::tracker_allocator_counter;
+
+template<bool Propagate>
+constexpr void
+test_ctor()
+{
+ using PropAlloc = propagating_allocator<int, Propagate>;
+ using Vector = std::vector<int, PropAlloc>;
+ using ScopedAlloc = std::scoped_allocator_adaptor<
+ propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>,
+ PropAlloc>;
+ using Indirect = std::indirect<Vector, ScopedAlloc>;
+
+ const Indirect src(std::allocator_arg, ScopedAlloc{11, 22},
+ std::in_place, {1, 2, 3});
+
+ Counter::reset();
+ Indirect i1(src);
+ VERIFY( *i1 == *src );
+ VERIFY( &*i1 != &*src );
+ if (Propagate)
+ {
+ VERIFY( i1->get_allocator().get_personality() == 22 );
+ VERIFY( i1.get_allocator().get_personality() == 11 );
+ }
+ else
+ {
+ VERIFY( i1->get_allocator().get_personality() == 0 );
+ VERIFY( i1.get_allocator().get_personality() == 0 );
+ }
+ VERIFY( Counter::get_allocation_count() == sizeof(Vector) );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 1 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+
+
+ Counter::reset();
+ Indirect i2(std::allocator_arg, ScopedAlloc{33, 44}, src);
+ VERIFY( *i2 == *src );
+ VERIFY( &*i2 != &*src );
+ VERIFY( i2->get_allocator().get_personality() == 44 );
+ VERIFY( i2.get_allocator().get_personality() == 33 );
+ VERIFY( Counter::get_allocation_count() == sizeof(Vector) );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 1 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+}
+
+template<bool Propagate>
+constexpr void
+test_assign()
+{
+ using PropAlloc = propagating_allocator<int, Propagate>;
+ using Vector = std::vector<int, PropAlloc>;
+ using ScopedAlloc = std::scoped_allocator_adaptor<
+ propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>,
+ PropAlloc>;
+ using Indirect = std::indirect<Vector, ScopedAlloc>;
+
+ const Indirect src(std::allocator_arg, ScopedAlloc{11, 22},
+ std::in_place, {1, 2, 3});
+
+ Indirect i1(std::allocator_arg, ScopedAlloc{11, 22});
+ Counter::reset();
+
+ i1 = src;
+ VERIFY( *i1 == *src );
+ VERIFY( &*i1 != &*src );
+ VERIFY( i1->get_allocator().get_personality() == 22 );
+ VERIFY( i1.get_allocator().get_personality() == 11 );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+
+ Indirect i2(std::allocator_arg, ScopedAlloc{33, 44});
+ Counter::reset();
+
+ i2 = src;
+ VERIFY( *i2 == *src );
+ VERIFY( &*i2 != &*src );
+ if (Propagate)
+ {
+ VERIFY( i2->get_allocator().get_personality() == 22 );
+ VERIFY( i2.get_allocator().get_personality() == 11 );
+ }
+ else
+ {
+ VERIFY( i2->get_allocator().get_personality() == 44 );
+ VERIFY( i2.get_allocator().get_personality() == 33 );
+ }
+ VERIFY( Counter::get_allocation_count() == sizeof(Vector) );
+ VERIFY( Counter::get_deallocation_count() == sizeof(Vector) );
+ VERIFY( Counter::get_construct_count() == 1 );
+ VERIFY( Counter::get_destruct_count() == 1 );
+
+ Indirect i3(std::allocator_arg, ScopedAlloc{11, 22});
+ auto(std::move(i3));
+ Counter::reset();
+
+ i3 = src;
+ VERIFY( *i3 == *src );
+ VERIFY( &*i3 != &*src );
+ VERIFY( i3->get_allocator().get_personality() == 22 );
+ VERIFY( i3.get_allocator().get_personality() == 11 );
+ VERIFY( Counter::get_allocation_count() == sizeof(Vector) );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 1 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+
+ Indirect i4(std::allocator_arg, ScopedAlloc{33, 44});
+ auto(std::move(i4));
+ Counter::reset();
+
+ i4 = src;
+ VERIFY( *i4 == *src );
+ VERIFY( &*i4 != &*src );
+ if (Propagate)
+ {
+ VERIFY( i4->get_allocator().get_personality() == 22 );
+ VERIFY( i4.get_allocator().get_personality() == 11 );
+ }
+ else
+ {
+ VERIFY( i4->get_allocator().get_personality() == 44 );
+ VERIFY( i4.get_allocator().get_personality() == 33 );
+ }
+ VERIFY( Counter::get_allocation_count() == sizeof(Vector) );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 1 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+}
+
+template<bool Propagate>
+constexpr void
+test_valueless()
+{
+ using PropAlloc = propagating_allocator<int, Propagate>;
+ using Vector = std::vector<int, PropAlloc>;
+ using ScopedAlloc = std::scoped_allocator_adaptor<
+ propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>,
+ PropAlloc>;
+ using Indirect = std::indirect<Vector, ScopedAlloc>;
+
+ Indirect e(std::allocator_arg, ScopedAlloc{11, 22});
+ auto(std::move(e));
+ VERIFY( e.valueless_after_move() );
+
+ Counter::reset();
+ Indirect i1(e);
+ VERIFY( i1.valueless_after_move() );
+ if (Propagate)
+ VERIFY( i1.get_allocator().get_personality() == 11 );
+ else
+ VERIFY( i1.get_allocator().get_personality() == 0 );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+
+ Counter::reset();
+ Indirect i2(std::allocator_arg, ScopedAlloc{33, 44}, e);
+ VERIFY( i2.valueless_after_move() );
+ VERIFY( i2.get_allocator().get_personality() == 33 );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+
+ Indirect i3(std::allocator_arg, ScopedAlloc{33, 44});
+ Counter::reset();
+
+ i3 = e;
+ VERIFY( i3.valueless_after_move() );
+ if (Propagate)
+ VERIFY( i3.get_allocator().get_personality() == 11 );
+ else
+ VERIFY( i3.get_allocator().get_personality() == 33 );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() == sizeof(Vector) );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 1 );
+
+ Counter::reset();
+ i2 = e;
+ VERIFY( i2.valueless_after_move() );
+ if (Propagate)
+ VERIFY( i2.get_allocator().get_personality() == 11 );
+ else
+ VERIFY( i2.get_allocator().get_personality() == 33 );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+}
+
+template<bool Propagate>
+constexpr void
+test_all()
+{
+ test_ctor<Propagate>();
+ test_assign<Propagate>();
+ test_valueless<Propagate>();
+}
+
+int main()
+{
+ test_all<true>();
+ test_all<false>();
+
+ static_assert([] {
+ test_all<true>();
+ test_all<false>();
+ return true;
+ });
+}
diff --git a/libstdc++-v3/testsuite/std/memory/indirect/ctor.cc b/libstdc++-v3/testsuite/std/memory/indirect/ctor.cc
new file mode 100644
index 0000000..124874d
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/memory/indirect/ctor.cc
@@ -0,0 +1,204 @@
+// { dg-do run { target c++26 } }
+
+#include <memory>
+#include <scoped_allocator>
+#include <utility>
+#include <vector>
+
+#ifndef __cpp_lib_indirect
+# error __cpp_lib_indirect feature test macro missing in <memory>
+#elif __cpp_lib_indirect != 202502
+# error __cpp_lib_indirect feature test macro has wrong value in <memory>
+#endif
+
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+using __gnu_test::uneq_allocator;
+using UneqAlloc = uneq_allocator<int>;
+using ScopedAlloc = std::scoped_allocator_adaptor<
+ uneq_allocator<std::vector<int, UneqAlloc>>,
+ UneqAlloc>;
+
+struct Obj
+{
+ int i;
+ char c[2];
+};
+
+constexpr void
+test_deduction_guides()
+{
+ const Obj o{};
+ std::indirect i1(o);
+ static_assert(std::is_same_v<decltype(i1), std::indirect<Obj>>);
+
+ using Alloc = __gnu_test::SimpleAllocator<Obj>;
+ Alloc a;
+ std::indirect i2(std::allocator_arg, a, o);
+ static_assert(std::is_same_v<decltype(i2), std::indirect<Obj, Alloc>>);
+}
+
+constexpr void
+test_default_ctor()
+{
+ using __gnu_test::default_init_allocator;
+
+ std::indirect<Obj, default_init_allocator<Obj>> i1;
+ default_init_allocator<int> a{};
+
+ // The contained object and the allocator should be value-initialized.
+ VERIFY( i1->i == 0 );
+ VERIFY( i1->c[0] == 0 );
+ VERIFY( i1->c[1] == 0 );
+ VERIFY( i1.get_allocator() == a );
+
+ a.state = 5;
+ // Allocator-extended default constructor:
+ std::indirect<Obj, default_init_allocator<Obj>> i2(std::allocator_arg, a);
+ VERIFY( i2.get_allocator() == a );
+
+ // Object is constructed using allocator-aware constructor.
+ std::indirect<std::vector<int, UneqAlloc>, ScopedAlloc>
+ i3(std::allocator_arg, ScopedAlloc(11, 22));
+ VERIFY( i3->empty() );
+ VERIFY( i3->get_allocator().get_personality() == 22 );
+ VERIFY( i3.get_allocator().get_personality() == 11 );
+}
+
+constexpr void
+test_forwarding_ctor()
+{
+ Obj obj{1, {'2', '3'}};
+ auto verify = [](std::indirect<Obj> const& i)
+ {
+ VERIFY( i->i == 1 );
+ VERIFY( i->c[0] == '2' );
+ VERIFY( i->c[1] == '3' );
+ };
+
+ std::indirect<Obj> i1(std::as_const(obj));
+ verify(i1);
+ std::indirect<Obj> i2(std::move(std::as_const(obj)));
+ verify(i2);
+ std::indirect<Obj> i3(obj);
+ verify(i3);
+ std::indirect<Obj> i4(std::move(obj));
+ verify(i4);
+
+ std::indirect<Obj> i5({1, {'2', '3'}});
+ verify(i5);
+
+ // Aggregate parens init
+ std::indirect<Obj> i6(7);
+ VERIFY( i6->i == 7 );
+
+ std::vector<int, UneqAlloc> v{1, 2, 3, 4, 5};
+ // Object is constructed using allocator-aware constructor.
+ std::indirect<std::vector<int, UneqAlloc>, ScopedAlloc>
+ i7(std::allocator_arg, ScopedAlloc(11, 22), v);
+ VERIFY( i7->size() == 5 );
+ VERIFY( v.size() == 5 );
+ VERIFY( i7->get_allocator().get_personality() == 22 );
+ VERIFY( i7.get_allocator().get_personality() == 11 );
+
+ std::indirect<std::vector<int, UneqAlloc>, ScopedAlloc>
+ i8(std::allocator_arg, ScopedAlloc(11, 22), std::move(v));
+ VERIFY( i8->size() == 5 );
+ VERIFY( v.size() == 0 );
+ VERIFY( i8->get_allocator().get_personality() == 22 );
+ VERIFY( i8.get_allocator().get_personality() == 11 );
+}
+
+constexpr void
+test_inplace_ctor()
+{
+ std::indirect<Obj> i1(std::in_place);
+ VERIFY( i1->i == 0 );
+ VERIFY( i1->c[0] == 0 );
+ VERIFY( i1->c[1] == 0 );
+
+ std::indirect<Obj> i2(std::in_place, 10);
+ VERIFY( i2->i == 10 );
+ VERIFY( i2->c[0] == 0 );
+ VERIFY( i2->c[1] == 0 );
+
+ std::indirect<Obj, uneq_allocator<Obj>>
+ i3(std::allocator_arg, 42, std::in_place);
+ VERIFY( i3->i == 0 );
+ VERIFY( i3->c[0] == 0 );
+ VERIFY( i3->c[1] == 0 );
+ VERIFY( i3.get_allocator().get_personality() == 42 );
+
+ std::indirect<Obj, uneq_allocator<Obj>>
+ i4(std::allocator_arg, 42, std::in_place, 10);
+ VERIFY( i4->i == 10 );
+ VERIFY( i4->c[0] == 0 );
+ VERIFY( i4->c[1] == 0 );
+ VERIFY( i4.get_allocator().get_personality() == 42 );
+
+ std::indirect<std::vector<int>> i5(std::in_place);
+ VERIFY( i5->size() == 0 );
+
+ std::indirect<std::vector<int>> i6(std::in_place, 5, 13);
+ VERIFY( i6->size() == 5 );
+ VERIFY( i6->at(0) == 13 );
+
+ std::indirect<std::vector<int>> i7(std::in_place, {1, 2, 3, 4});
+ VERIFY( i7->size() == 4 );
+ VERIFY( i7->at(2) == 3 );
+
+ std::indirect<std::vector<int, UneqAlloc>>
+ i8(std::in_place, UneqAlloc{42});
+ VERIFY( i8->size() == 0 );
+ VERIFY( i8->get_allocator().get_personality() == 42 );
+
+ std::indirect<std::vector<int, UneqAlloc>>
+ i9(std::in_place, 5, 13, UneqAlloc{42});
+ VERIFY( i9->size() == 5 );
+ VERIFY( i9->at(0) == 13 );
+ VERIFY( i9->get_allocator().get_personality() == 42 );
+
+ std::indirect<std::vector<int, UneqAlloc>>
+ i10(std::in_place, {1, 2, 3, 4}, UneqAlloc{42});
+ VERIFY( i10->size() == 4 );
+ VERIFY( i10->at(2) == 3 );
+ VERIFY( i10->get_allocator().get_personality() == 42 );
+
+ std::indirect<std::vector<int, UneqAlloc>, ScopedAlloc>
+ i14(std::allocator_arg, ScopedAlloc(11, 22),
+ std::in_place);
+ VERIFY( i14->size() == 0 );
+ VERIFY( i14->get_allocator().get_personality() == 22 );
+ VERIFY( i14.get_allocator().get_personality() == 11 );
+
+ std::indirect<std::vector<int, UneqAlloc>, ScopedAlloc>
+ i15(std::allocator_arg, ScopedAlloc(11, 22),
+ std::in_place, 5, 13);
+ VERIFY( i15->size() == 5 );
+ VERIFY( i15->at(0) == 13 );
+ VERIFY( i15->get_allocator().get_personality() == 22 );
+ VERIFY( i15.get_allocator().get_personality() == 11 );
+
+ std::indirect<std::vector<int, UneqAlloc>, ScopedAlloc>
+ i16(std::allocator_arg, ScopedAlloc(11, 22),
+ std::in_place, {1, 2, 3, 4});
+ VERIFY( i16->size() == 4 );
+ VERIFY( i16->at(2) == 3 );
+ VERIFY( i16->get_allocator().get_personality() == 22 );
+ VERIFY( i16.get_allocator().get_personality() == 11 );
+}
+
+int main()
+{
+ test_default_ctor();
+ test_forwarding_ctor();
+ test_inplace_ctor();
+
+ static_assert([] {
+ test_default_ctor();
+ test_forwarding_ctor();
+ test_inplace_ctor();
+ return true;
+ });
+}
diff --git a/libstdc++-v3/testsuite/std/memory/indirect/incomplete.cc b/libstdc++-v3/testsuite/std/memory/indirect/incomplete.cc
new file mode 100644
index 0000000..1faf13d
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/memory/indirect/incomplete.cc
@@ -0,0 +1,38 @@
+// { dg-do compile { target c++26 } }
+
+#include <memory>
+
+struct Incomplete;
+bool operator==(const Incomplete&, const Incomplete&);
+std::strong_ordering operator<=>(const Incomplete&, const Incomplete&);
+
+template<>
+struct std::hash<Incomplete>
+{
+ static std::size_t operator()(const Incomplete& c);
+};
+
+std::indirect<Incomplete>*
+test_move(std::indirect<Incomplete>& i1, std::indirect<Incomplete>& i2)
+{
+ i2.swap(i2);
+ return new std::indirect<Incomplete>(std::move(i1));
+}
+
+void
+test_relops(std::indirect<Incomplete> const& i1, Incomplete const& o)
+{
+ void(i1 == i1);
+ void(i1 < i1);
+ void(i1 >= i1);
+
+ void(i1 != o);
+ void(i1 < o);
+}
+
+void
+test_hash(std::indirect<Incomplete> const& i1)
+{
+ std::hash<std::indirect<Incomplete>> h;
+ h(i1);
+}
diff --git a/libstdc++-v3/testsuite/std/memory/indirect/invalid_neg.cc b/libstdc++-v3/testsuite/std/memory/indirect/invalid_neg.cc
new file mode 100644
index 0000000..82e7e84
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/memory/indirect/invalid_neg.cc
@@ -0,0 +1,28 @@
+// { dg-do compile { target c++26 } }
+
+#include <memory>
+
+// In every specialization indirect<T, Allocator>, if the type
+// allocator_traits<Allocator>::value_type is not the same type as T,
+// the program is ill-formed.
+using T1 = std::indirect<int, std::allocator<long>>::value_type; // { dg-error "here" }
+
+// A program that instantiates the definition of the template
+// indirect<T, Allocator> with a type for the T parameter that is
+// a non-object type, an array type, in_place_t,
+// a specialization of in_place_type_t, or a cv-qualified type is ill-formed.
+
+using T2 = std::indirect<int&>::value_type; // { dg-error "here" }
+
+using T3 = std::indirect<int[1]>::value_type; // { dg-error "here" }
+
+using T4 = std::indirect<std::in_place_t>::value_type; // { dg-error "here" }
+
+using T5 = std::indirect<std::in_place_type_t<int>>::value_type; // { dg-error "here" }
+
+using T6 = std::indirect<const int>::value_type; // { dg-error "here" }
+
+using T7 = std::indirect<volatile int>::value_type; // { dg-error "here" }
+
+// { dg-error "static assertion failed" "" { target *-*-* } 0 }
+// { dg-prune-output "forming pointer to reference" }
diff --git a/libstdc++-v3/testsuite/std/memory/indirect/move.cc b/libstdc++-v3/testsuite/std/memory/indirect/move.cc
new file mode 100644
index 0000000..6e87c60
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/memory/indirect/move.cc
@@ -0,0 +1,144 @@
+// { dg-do run { target c++26 } }
+
+#include <memory>
+#include <scoped_allocator>
+#include <utility>
+#include <vector>
+#include <optional>
+
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+using __gnu_test::tracker_allocator;
+using Counter = __gnu_test::tracker_allocator_counter;
+using Vector = std::vector<int>;
+using Indirect = std::indirect<Vector, tracker_allocator<Vector>>;
+const Indirect val(std::in_place, {1, 2, 3});
+
+constexpr void
+verifyNoAllocations()
+{
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+}
+
+constexpr void
+test_ctor()
+{
+ std::optional<Indirect> src;
+ auto make = [&src] -> Indirect&& {
+ src.emplace(val);
+ Counter::reset();
+ return std::move(*src);
+ };
+
+ Indirect i1(make());
+ VERIFY( src->valueless_after_move() );
+ VERIFY( *i1 == *val );
+ verifyNoAllocations();
+
+ Indirect i2(std::allocator_arg, {}, make());
+ VERIFY( src->valueless_after_move() );
+ VERIFY( *i2 == *val );
+ verifyNoAllocations();
+}
+
+constexpr void
+test_assign()
+{
+ std::optional<Indirect> src;
+ auto make = [&src] -> Indirect&& {
+ src.emplace(val);
+ Counter::reset();
+ return std::move(*src);
+ };
+
+ Indirect i1;
+
+ i1 = make();
+ VERIFY( src->valueless_after_move() );
+ VERIFY( *i1 == *val );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() == sizeof(Vector) );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 1 );
+
+ auto(std::move(i1));
+ i1 = make();
+ VERIFY( *i1 == *val );
+ VERIFY( src->valueless_after_move() );
+ verifyNoAllocations();
+}
+
+constexpr void
+test_swap()
+{
+ const Indirect val1(std::in_place, {1, 2, 3});
+ const Indirect val2(std::in_place, {2, 4, 6});
+
+ Indirect i1(val1);
+ Indirect i2(val2);
+ Counter::reset();
+ i1.swap(i2);
+ VERIFY( *i2 == *val1 );
+ VERIFY( *i1 == *val2 );
+ verifyNoAllocations();
+
+ auto(std::move(i1));
+
+ Counter::reset();
+ i1.swap(i2);
+ VERIFY( *i1 == *val1 );
+ VERIFY( i2.valueless_after_move() );
+ verifyNoAllocations();
+}
+
+constexpr void
+test_valueless()
+{
+ auto e = [] {
+ Indirect res;
+ auto(std::move(res));
+ Counter::reset();
+ return res;
+ };
+
+ Indirect i1(e());
+ VERIFY( i1.valueless_after_move() );
+ verifyNoAllocations();
+
+ Indirect i2(std::allocator_arg, {}, e());
+ VERIFY( i2.valueless_after_move() );
+ verifyNoAllocations();
+
+ Indirect i3(val);
+ i3 = e();
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() == sizeof(Vector) );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 1 );
+
+ i3 = e();
+ verifyNoAllocations();
+}
+
+constexpr void
+test_all()
+{
+ test_ctor();
+ test_assign();
+ test_swap();
+ test_valueless();
+}
+
+int main()
+{
+ test_all();
+
+ static_assert([] {
+ test_all();
+ return true;
+ });
+}
diff --git a/libstdc++-v3/testsuite/std/memory/indirect/move_alloc.cc b/libstdc++-v3/testsuite/std/memory/indirect/move_alloc.cc
new file mode 100644
index 0000000..cd6f90d
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/memory/indirect/move_alloc.cc
@@ -0,0 +1,296 @@
+// { dg-do run { target c++26 } }
+
+#include <memory>
+#include <scoped_allocator>
+#include <utility>
+#include <vector>
+#include <optional>
+
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+using __gnu_test::propagating_allocator;
+using __gnu_test::tracker_allocator;
+using Counter = __gnu_test::tracker_allocator_counter;
+
+constexpr void
+verifyNoAllocations()
+{
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+}
+
+template<bool Propagate>
+constexpr void
+test_ctor()
+{
+ using PropAlloc = propagating_allocator<int, Propagate>;
+ using Vector = std::vector<int, PropAlloc>;
+ using ScopedAlloc = std::scoped_allocator_adaptor<
+ propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>,
+ PropAlloc>;
+ using Indirect = std::indirect<Vector, ScopedAlloc>;
+
+ const Indirect val(std::in_place, {1, 2, 3});
+ std::optional<Indirect> src;
+ auto make = [&val, &src] -> Indirect&& {
+ src.emplace(std::allocator_arg, ScopedAlloc{11, 22}, val);
+ Counter::reset();
+ return std::move(*src);
+ };
+
+ Indirect i1(make());
+ VERIFY( src->valueless_after_move() );
+ VERIFY( *i1 == *val );
+ VERIFY( i1->get_allocator().get_personality() == 22 );
+ VERIFY( i1.get_allocator().get_personality() == 11 );
+ verifyNoAllocations();
+
+ Indirect i2(std::allocator_arg, ScopedAlloc{11, 22}, make());
+ VERIFY( src->valueless_after_move() );
+ VERIFY( *i2 == *val );
+ VERIFY( i2->get_allocator().get_personality() == 22 );
+ VERIFY( i2.get_allocator().get_personality() == 11 );
+ verifyNoAllocations();
+
+ Indirect i3(std::allocator_arg, ScopedAlloc{33, 44}, make());
+ // We move-from contained object
+ VERIFY( !src->valueless_after_move() );
+ VERIFY( *i3 == *val );
+ VERIFY( i3->get_allocator().get_personality() == 44 );
+ VERIFY( i3.get_allocator().get_personality() == 33 );
+ VERIFY( Counter::get_allocation_count() == sizeof(Vector) );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 1 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+}
+
+template<bool Propagate>
+constexpr void
+test_assign()
+{
+ using PropAlloc = propagating_allocator<int, Propagate>;
+ using Vector = std::vector<int, PropAlloc>;
+ using ScopedAlloc = std::scoped_allocator_adaptor<
+ propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>,
+ PropAlloc>;
+ using Indirect = std::indirect<Vector, ScopedAlloc>;
+
+ const Indirect val(std::in_place, {1, 2, 3});
+ std::optional<Indirect> src;
+ auto make = [&val, &src] -> Indirect&& {
+ src.emplace(std::allocator_arg, ScopedAlloc{11, 22}, val);
+ Counter::reset();
+ return std::move(*src);
+ };
+
+ Indirect i1(std::allocator_arg, ScopedAlloc{11, 22});
+
+ i1 = make();
+ VERIFY( src->valueless_after_move() );
+ VERIFY( *i1 == *val );
+ VERIFY( i1->get_allocator().get_personality() == 22 );
+ VERIFY( i1.get_allocator().get_personality() == 11 );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() == sizeof(Vector) );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 1 );
+
+ Indirect i2(std::allocator_arg, ScopedAlloc{33, 44});
+
+ i2 = make();
+ VERIFY( *i2 == *val );
+ if (Propagate)
+ {
+ VERIFY( src->valueless_after_move() );
+ VERIFY( i2->get_allocator().get_personality() == 22 );
+ VERIFY( i2.get_allocator().get_personality() == 11 );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 0 );
+ }
+ else
+ {
+ // We allocate new holder and move-from contained object
+ VERIFY( !src->valueless_after_move() );
+ VERIFY( i2->get_allocator().get_personality() == 44 );
+ VERIFY( i2.get_allocator().get_personality() == 33 );
+ VERIFY( Counter::get_allocation_count() == sizeof(Vector) );
+ VERIFY( Counter::get_construct_count() == 1 );
+ }
+ VERIFY( Counter::get_deallocation_count() == sizeof(Vector) );
+ VERIFY( Counter::get_destruct_count() == 1 );
+
+ Indirect i3(std::allocator_arg, ScopedAlloc{11, 22});
+ auto(std::move(i3));
+
+ i3 = make();
+ VERIFY( *i3 == *val );
+ VERIFY( src->valueless_after_move() );
+ VERIFY( i3->get_allocator().get_personality() == 22 );
+ VERIFY( i3.get_allocator().get_personality() == 11 );
+ verifyNoAllocations();
+
+ Indirect i4(std::allocator_arg, ScopedAlloc{33, 44});
+ auto(std::move(i4));
+
+ i4 = make();
+ VERIFY( *i4 == *val );
+ if (Propagate)
+ {
+ VERIFY( src->valueless_after_move() );
+ VERIFY( i4->get_allocator().get_personality() == 22 );
+ VERIFY( i4.get_allocator().get_personality() == 11 );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 0 );
+ }
+ else
+ {
+ // We allocate new holder and move-from contained object
+ VERIFY( !src->valueless_after_move() );
+ VERIFY( i4->get_allocator().get_personality() == 44 );
+ VERIFY( i4.get_allocator().get_personality() == 33 );
+ VERIFY( Counter::get_allocation_count() == sizeof(Vector) );
+ VERIFY( Counter::get_construct_count() == 1 );
+ }
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+}
+
+template<bool Propagate>
+constexpr void
+test_swap()
+{
+ using PropAlloc = propagating_allocator<int, Propagate>;
+ using Vector = std::vector<int, PropAlloc>;
+ using ScopedAlloc = std::scoped_allocator_adaptor<
+ propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>,
+ PropAlloc>;
+ using Indirect = std::indirect<Vector, ScopedAlloc>;
+
+ const Indirect val1(std::in_place, {1, 2, 3});
+ const Indirect val2(std::in_place, {2, 4, 6});
+
+ Indirect i1(std::allocator_arg, ScopedAlloc{11, 22}, val1);
+ Indirect i2(std::allocator_arg, ScopedAlloc{11, 22}, val2);
+ Counter::reset();
+ i1.swap(i2);
+ VERIFY( *i2 == *val1 );
+ VERIFY( *i1 == *val2 );
+ verifyNoAllocations();
+
+ auto(std::move(i1));
+
+ Counter::reset();
+ i1.swap(i2);
+ VERIFY( *i1 == *val1 );
+ VERIFY( i2.valueless_after_move() );
+ verifyNoAllocations();
+
+ if (!Propagate)
+ return;
+
+ Indirect i3(std::allocator_arg, ScopedAlloc{33, 44}, val2);
+ Counter::reset();
+ i1.swap(i3);
+ VERIFY( *i1 == *val2 );
+ VERIFY( i1->get_allocator().get_personality() == 44 );
+ VERIFY( i1.get_allocator().get_personality() == 33 );
+ VERIFY( *i3 == *val1 );
+ VERIFY( i3->get_allocator().get_personality() == 22 );
+ VERIFY( i3.get_allocator().get_personality() == 11 );
+ verifyNoAllocations();
+
+ i1.swap(i2);
+ VERIFY( i1.valueless_after_move() );
+ VERIFY( i1.get_allocator().get_personality() == 11 );
+ VERIFY( *i2 == *val2 );
+ VERIFY( i2->get_allocator().get_personality() == 44 );
+ VERIFY( i2.get_allocator().get_personality() == 33 );
+ verifyNoAllocations();
+}
+
+template<bool Propagate>
+constexpr void
+test_valueless()
+{
+ using PropAlloc = propagating_allocator<int, Propagate>;
+ using Vector = std::vector<int, PropAlloc>;
+ using ScopedAlloc = std::scoped_allocator_adaptor<
+ propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>,
+ PropAlloc>;
+ using Indirect = std::indirect<Vector, ScopedAlloc>;
+
+ auto e = [] {
+ Indirect res(std::allocator_arg, ScopedAlloc{11, 22});
+ auto(std::move(res));
+ Counter::reset();
+ return res;
+ };
+
+ Indirect i1(e());
+ VERIFY( i1.valueless_after_move() );
+ VERIFY( i1.get_allocator().get_personality() == 11 );
+ verifyNoAllocations();
+
+ Indirect i2(std::allocator_arg, ScopedAlloc{33, 44}, e());
+ VERIFY( i2.valueless_after_move() );
+ VERIFY( i2.get_allocator().get_personality() == 33 );
+ verifyNoAllocations();
+
+ Indirect i3(std::allocator_arg, ScopedAlloc{33, 44});
+
+ i3 = e();
+ VERIFY( i3.valueless_after_move() );
+ if (Propagate)
+ VERIFY( i3.get_allocator().get_personality() == 11 );
+ else
+ VERIFY( i3.get_allocator().get_personality() == 33 );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() == sizeof(Vector) );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 1 );
+
+ i2 = e();
+ VERIFY( i2.valueless_after_move() );
+ if (Propagate)
+ VERIFY( i2.get_allocator().get_personality() == 11 );
+ else
+ VERIFY( i2.get_allocator().get_personality() == 33 );
+ verifyNoAllocations();
+
+ i3.swap(i2);
+ VERIFY( i2.valueless_after_move() );
+ VERIFY( i1.valueless_after_move() );
+ verifyNoAllocations();
+
+ if (!Propagate)
+ return;
+
+ Indirect i4(std::allocator_arg, ScopedAlloc{33, 44}, e());
+ i4.swap(i1);
+ verifyNoAllocations();
+}
+
+template<bool Propagate>
+constexpr void
+test_all()
+{
+ test_ctor<Propagate>();
+ test_assign<Propagate>();
+ test_swap<Propagate>();
+ test_valueless<Propagate>();
+}
+
+int main()
+{
+ test_all<true>();
+ test_all<false>();
+
+ static_assert([] {
+ test_all<true>();
+ test_all<false>();
+ return true;
+ });
+}
diff --git a/libstdc++-v3/testsuite/std/memory/indirect/relops.cc b/libstdc++-v3/testsuite/std/memory/indirect/relops.cc
new file mode 100644
index 0000000..d77fef2
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/memory/indirect/relops.cc
@@ -0,0 +1,82 @@
+// { dg-do run { target c++26 } }
+
+#include <memory>
+#include <testsuite_hooks.h>
+
+struct Obj
+{
+ int i;
+ constexpr auto operator<=>(const Obj&) const = default;
+};
+
+template<>
+struct std::hash<Obj>
+{
+ static size_t operator()(Obj const& obj)
+ { return std::hash<int>{}(obj.i); }
+};
+
+constexpr void
+test_relops()
+{
+ std::indirect<Obj> i1;
+ VERIFY( i1 == i1 );
+ VERIFY( i1 <= i1 );
+ VERIFY( i1 >= i1 );
+
+ std::indirect<Obj> i2 = std::move(i1); // make i1 valueless
+ VERIFY( i1 == i1 );
+ VERIFY( i2 == i2 );
+ VERIFY( i2 != i1 );
+ VERIFY( i1 < i2 );
+ VERIFY( i2 >= i1 );
+
+ std::indirect<Obj> i3 = std::move(i2); // make i2 valueless
+ VERIFY( i2 == i1 );
+ VERIFY( i2 >= i1 );
+ VERIFY( i2 <= i1 );
+ VERIFY( i3 > i2 );
+}
+
+constexpr void
+test_comp_with_t()
+{
+ std::indirect<Obj> i1;
+ Obj o{2};
+ VERIFY( i1 != o );
+ VERIFY( i1 < o );
+
+ std::indirect<Obj> i2(Obj{2});
+ VERIFY( i2 == o );
+ VERIFY( i2 <= o );
+ VERIFY( o <= i2 );
+
+ std::indirect<Obj> i3 = std::move(i2); // make i2 valueless
+ VERIFY( i2 != o );
+ VERIFY( i2 < o );
+}
+
+void
+test_hash()
+{
+ Obj o{5};
+ std::indirect<Obj> i(o);
+ VERIFY( std::hash<std::indirect<Obj>>{}(i)
+ == std::hash<Obj>{}(o) );
+
+ auto(std::move(i)); // make i valueless
+ (void)std::hash<std::indirect<Obj>>{}(i);
+}
+
+int main()
+{
+ test_relops();
+ test_comp_with_t();
+ test_hash();
+
+ static_assert([] {
+ test_relops();
+ test_comp_with_t();
+ return true;
+ });
+}
diff --git a/libstdc++-v3/testsuite/std/memory/polymorphic/copy.cc b/libstdc++-v3/testsuite/std/memory/polymorphic/copy.cc
new file mode 100644
index 0000000..bea05ac
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/memory/polymorphic/copy.cc
@@ -0,0 +1,157 @@
+// { dg-do run { target c++26 } }
+
+#include <memory>
+#include <scoped_allocator>
+#include <utility>
+#include <vector>
+
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct Base {
+ friend constexpr
+ bool operator==(const Base& lhs, const Base& rhs)
+ { return lhs.eq(rhs); }
+
+private:
+ constexpr virtual bool
+ eq(const Base& other) const = 0;
+};
+
+struct Derived : Base
+{
+ constexpr Derived()
+ : x(0), y(0), z(0)
+ { }
+
+ constexpr Derived(int a, int b, int c)
+ : x(a), y(b), z(c)
+ { }
+
+private:
+ constexpr bool
+ eq(const Base& other) const override
+ {
+ if (auto op = dynamic_cast<const Derived*>(&other))
+ return this->x == op->x && this->y == op->y && this->z == op->z;
+ return false;
+ }
+
+ int x;
+ int y;
+ int z;
+};
+
+using __gnu_test::tracker_allocator;
+using Counter = __gnu_test::tracker_allocator_counter;
+using Polymorhic = std::polymorphic<Base, tracker_allocator<Base>>;
+const Polymorhic src(std::in_place_type<Derived>, 1, 2, 3);
+
+constexpr void
+test_ctor()
+{
+ Counter::reset();
+ Polymorhic i1(src);
+ VERIFY( *i1 == *src );
+ VERIFY( &*i1 != &*src );
+ VERIFY( Counter::get_allocation_count() >= sizeof(Derived) );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 2 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+
+ Counter::reset();
+ Polymorhic i2(std::allocator_arg, {}, src);
+ VERIFY( *i2 == *src );
+ VERIFY( &*i2 != &*src );
+ VERIFY( Counter::get_allocation_count() >= sizeof(Derived) );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 2 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+}
+
+constexpr void
+test_assign()
+{
+ Counter::reset();
+ Polymorhic i1(std::in_place_type<Derived>);
+ const size_t holderSize = Counter::get_allocation_count();
+ VERIFY( holderSize >= sizeof(Derived) );
+ Counter::reset();
+
+ i1 = src;
+ VERIFY( *i1 == *src );
+ VERIFY( &*i1 != &*src );
+ VERIFY( Counter::get_allocation_count() == holderSize );
+ VERIFY( Counter::get_deallocation_count() == holderSize );
+ VERIFY( Counter::get_construct_count() == 2 );
+ VERIFY( Counter::get_destruct_count() == 1 );
+
+ auto(std::move(i1));
+ Counter::reset();
+
+ i1 = src;
+ VERIFY( *i1 == *src );
+ VERIFY( &*i1 != &*src );
+ VERIFY( Counter::get_allocation_count() == holderSize );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 2 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+}
+
+constexpr void
+test_valueless()
+{
+ Polymorhic e(std::in_place_type<Derived>);
+ auto(std::move(e));
+ VERIFY( e.valueless_after_move() );
+
+ Counter::reset();
+ Polymorhic i1(e);
+ VERIFY( i1.valueless_after_move() );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+
+ Polymorhic i2(std::allocator_arg, {}, e);
+ VERIFY( i2.valueless_after_move() );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+
+ Polymorhic i3(src);
+ Counter::reset();
+ i3 = e;
+ VERIFY( i3.valueless_after_move() );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() >= sizeof(Derived) );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 1 );
+
+ Counter::reset();
+ i3 = e;
+ VERIFY( i3.valueless_after_move() );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+}
+
+constexpr void
+test_all()
+{
+ test_ctor();
+ test_assign();
+ test_valueless();
+}
+
+int main()
+{
+ test_all();
+
+ static_assert([] {
+ test_all();
+ return true;
+ });
+}
diff --git a/libstdc++-v3/testsuite/std/memory/polymorphic/copy_alloc.cc b/libstdc++-v3/testsuite/std/memory/polymorphic/copy_alloc.cc
new file mode 100644
index 0000000..f41c32e
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/memory/polymorphic/copy_alloc.cc
@@ -0,0 +1,270 @@
+// { dg-do run { target c++26 } }
+
+#include <memory>
+#include <scoped_allocator>
+#include <utility>
+#include <vector>
+
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct Base {
+ friend constexpr
+ bool operator==(const Base& lhs, const Base& rhs)
+ { return lhs.eq(rhs); }
+
+ virtual constexpr int
+ get_alloc_personality() const
+ { return -1; }
+
+private:
+ constexpr virtual bool
+ eq(const Base& other) const = 0;
+};
+
+template<typename T, typename Allocator>
+struct VecDerived : Base, std::vector<T, Allocator>
+{
+ using VecBase = std::vector<T, Allocator>;
+
+ using VecBase::VecBase;
+
+ constexpr int
+ get_alloc_personality() const override
+ { return this->get_allocator().get_personality(); }
+
+private:
+
+ constexpr bool
+ eq(const Base& other) const override
+ {
+ if (auto op = dynamic_cast<const VecDerived*>(&other))
+ return *static_cast<const VecBase*>(this)
+ == *static_cast<const VecBase*>(op);
+ return false;
+ }
+};
+
+using __gnu_test::propagating_allocator;
+using __gnu_test::tracker_allocator;
+using Counter = __gnu_test::tracker_allocator_counter;
+
+template<bool Propagate>
+constexpr void
+test_ctor()
+{
+ using PropAlloc = propagating_allocator<int, Propagate>;
+ using Vector = VecDerived<int, PropAlloc>;
+ using ScopedAlloc = std::scoped_allocator_adaptor<
+ propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>,
+ PropAlloc>;
+ using Polymorphic = std::polymorphic<Vector, ScopedAlloc>;
+
+ const Polymorphic src(std::allocator_arg, ScopedAlloc{11, 22},
+ std::in_place_type<Vector>, {1, 2, 3});
+
+ Counter::reset();
+ Polymorphic i1(src);
+ VERIFY( *i1 == *src );
+ VERIFY( &*i1 != &*src );
+ if (Propagate)
+ {
+ VERIFY( i1->get_alloc_personality() == 22 );
+ VERIFY( i1.get_allocator().get_personality() == 11 );
+ }
+ else
+ {
+ VERIFY( i1->get_alloc_personality() == 0 );
+ VERIFY( i1.get_allocator().get_personality() == 0 );
+ }
+ VERIFY( Counter::get_allocation_count() >= sizeof(Vector) );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 2 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+
+
+ Counter::reset();
+ Polymorphic i2(std::allocator_arg, ScopedAlloc{33, 44}, src);
+ VERIFY( *i2 == *src );
+ VERIFY( &*i2 != &*src );
+ VERIFY( i2->get_alloc_personality() == 44 );
+ VERIFY( i2.get_allocator().get_personality() == 33 );
+ VERIFY( Counter::get_allocation_count() >= sizeof(Vector) );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 2 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+}
+
+template<bool Propagate>
+constexpr void
+test_assign()
+{
+ using PropAlloc = propagating_allocator<int, Propagate>;
+ using Vector = VecDerived<int, PropAlloc>;
+ using ScopedAlloc = std::scoped_allocator_adaptor<
+ propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>,
+ PropAlloc>;
+ using Polymorphic = std::polymorphic<Vector, ScopedAlloc>;
+
+ const Polymorphic src(std::allocator_arg, ScopedAlloc{11, 22},
+ std::in_place_type<Vector>, {1, 2, 3});
+
+ Counter::reset();
+ Polymorphic i1(std::allocator_arg, ScopedAlloc{11, 22},
+ std::in_place_type<Vector>);
+ const size_t holderSize = Counter::get_allocation_count();
+ VERIFY( holderSize >= sizeof(Vector) );
+ Counter::reset();
+
+ i1 = src;
+ VERIFY( *i1 == *src );
+ VERIFY( &*i1 != &*src );
+ VERIFY( i1->get_alloc_personality() == 22 );
+ VERIFY( i1.get_allocator().get_personality() == 11 );
+ VERIFY( Counter::get_allocation_count() == holderSize );
+ VERIFY( Counter::get_deallocation_count() == holderSize );
+ VERIFY( Counter::get_construct_count() == 2 );
+ VERIFY( Counter::get_destruct_count() == 1 );
+
+ Polymorphic i2(std::allocator_arg, ScopedAlloc{33, 44});
+ Counter::reset();
+
+ i2 = src;
+ VERIFY( *i2 == *src );
+ VERIFY( &*i2 != &*src );
+ if (Propagate)
+ {
+ VERIFY( i2->get_alloc_personality() == 22 );
+ VERIFY( i2.get_allocator().get_personality() == 11 );
+ }
+ else
+ {
+ VERIFY( i2->get_alloc_personality() == 44 );
+ VERIFY( i2.get_allocator().get_personality() == 33 );
+ }
+ VERIFY( Counter::get_allocation_count() == holderSize );
+ VERIFY( Counter::get_deallocation_count() == holderSize );
+ VERIFY( Counter::get_construct_count() == 2 );
+ VERIFY( Counter::get_destruct_count() == 1 );
+
+ Polymorphic i3(std::allocator_arg, ScopedAlloc{11, 22});
+ auto(std::move(i3));
+ Counter::reset();
+
+ i3 = src;
+ VERIFY( *i3 == *src );
+ VERIFY( &*i3 != &*src );
+ VERIFY( i3->get_alloc_personality() == 22 );
+ VERIFY( i3.get_allocator().get_personality() == 11 );
+ VERIFY( Counter::get_allocation_count() == holderSize );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 2 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+
+ Polymorphic i4(std::allocator_arg, ScopedAlloc{33, 44});
+ auto(std::move(i4));
+ Counter::reset();
+
+ i4 = src;
+ VERIFY( *i4 == *src );
+ VERIFY( &*i4 != &*src );
+ if (Propagate)
+ {
+ VERIFY( i4->get_alloc_personality() == 22 );
+ VERIFY( i4.get_allocator().get_personality() == 11 );
+ }
+ else
+ {
+ VERIFY( i4->get_alloc_personality() == 44 );
+ VERIFY( i4.get_allocator().get_personality() == 33 );
+ }
+ VERIFY( Counter::get_allocation_count() == holderSize );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 2 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+}
+
+template<bool Propagate>
+constexpr void
+test_valueless()
+{
+ using PropAlloc = propagating_allocator<int, Propagate>;
+ using Vector = VecDerived<int, PropAlloc>;
+ using ScopedAlloc = std::scoped_allocator_adaptor<
+ propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>,
+ PropAlloc>;
+ using Polymorphic = std::polymorphic<Vector, ScopedAlloc>;
+
+ Polymorphic e(std::allocator_arg, ScopedAlloc{11, 22},
+ std::in_place_type<Vector>);
+ auto(std::move(e));
+ VERIFY( e.valueless_after_move() );
+
+ Counter::reset();
+ Polymorphic i1(e);
+ VERIFY( i1.valueless_after_move() );
+ if (Propagate)
+ VERIFY( i1.get_allocator().get_personality() == 11 );
+ else
+ VERIFY( i1.get_allocator().get_personality() == 0 );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+
+ Counter::reset();
+ Polymorphic i2(std::allocator_arg, ScopedAlloc{33, 44}, e);
+ VERIFY( i2.valueless_after_move() );
+ VERIFY( i2.get_allocator().get_personality() == 33 );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+
+ Polymorphic i3(std::allocator_arg, ScopedAlloc{33, 44});
+ Counter::reset();
+
+ i3 = e;
+ VERIFY( i3.valueless_after_move() );
+ if (Propagate)
+ VERIFY( i3.get_allocator().get_personality() == 11 );
+ else
+ VERIFY( i3.get_allocator().get_personality() == 33 );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() >= sizeof(Vector) );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 1 );
+
+ Counter::reset();
+ i2 = e;
+ VERIFY( i2.valueless_after_move() );
+ if (Propagate)
+ VERIFY( i2.get_allocator().get_personality() == 11 );
+ else
+ VERIFY( i2.get_allocator().get_personality() == 33 );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+}
+
+template<bool Propagate>
+constexpr void
+test_all()
+{
+ test_ctor<Propagate>();
+ test_assign<Propagate>();
+ test_valueless<Propagate>();
+}
+
+int main()
+{
+ test_all<true>();
+ test_all<false>();
+
+ static_assert([] {
+ test_all<true>();
+ test_all<false>();
+ return true;
+ });
+}
diff --git a/libstdc++-v3/testsuite/std/memory/polymorphic/ctor.cc b/libstdc++-v3/testsuite/std/memory/polymorphic/ctor.cc
new file mode 100644
index 0000000..bb4c947
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/memory/polymorphic/ctor.cc
@@ -0,0 +1,190 @@
+// { dg-do run { target c++26 } }
+
+#include <memory>
+#include <scoped_allocator>
+#include <utility>
+#include <vector>
+
+#ifndef __cpp_lib_polymorphic
+# error __cpp_lib_polymorphic feature test macro missing in <memory>
+#elif __cpp_lib_polymorphic != 202502
+# error __cpp_lib_polymorphic feature test macro has wrong value in <memory>
+#endif
+
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+using __gnu_test::uneq_allocator;
+using UneqAlloc = uneq_allocator<int>;
+using ScopedAlloc = std::scoped_allocator_adaptor<
+ uneq_allocator<std::vector<int, UneqAlloc>>,
+ UneqAlloc>;
+
+struct Obj
+{
+ int i;
+ char c[2];
+};
+
+constexpr void
+test_default_ctor()
+{
+ using __gnu_test::default_init_allocator;
+
+ std::polymorphic<Obj, default_init_allocator<Obj>> i1;
+ default_init_allocator<int> a{};
+
+ // The contained object and the allocator should be value-initialized.
+ VERIFY( i1->i == 0 );
+ VERIFY( i1->c[0] == 0 );
+ VERIFY( i1->c[1] == 0 );
+ VERIFY( i1.get_allocator() == a );
+
+ a.state = 5;
+ // Allocator-extended default constructor:
+ std::polymorphic<Obj, default_init_allocator<Obj>> i2(std::allocator_arg, a);
+ VERIFY( i2.get_allocator() == a );
+
+ // Object is constructed using allocator-aware constructor.
+ std::polymorphic<std::vector<int, UneqAlloc>, ScopedAlloc>
+ i3(std::allocator_arg, ScopedAlloc(11, 22));
+ VERIFY( i3->empty() );
+ VERIFY( i3->get_allocator().get_personality() == 22 );
+ VERIFY( i3.get_allocator().get_personality() == 11 );
+}
+
+constexpr void
+test_forwarding_ctor()
+{
+ Obj obj{1, {'2', '3'}};
+ auto verify = [](std::polymorphic<Obj> const& i)
+ {
+ VERIFY( i->i == 1 );
+ VERIFY( i->c[0] == '2' );
+ VERIFY( i->c[1] == '3' );
+ };
+
+ std::polymorphic<Obj> i1(std::as_const(obj));
+ verify(i1);
+ std::polymorphic<Obj> i2(std::move(std::as_const(obj)));
+ verify(i2);
+ std::polymorphic<Obj> i3(obj);
+ verify(i3);
+ std::polymorphic<Obj> i4(std::move(obj));
+ verify(i4);
+
+ std::polymorphic<Obj> i5({1, {'2', '3'}});
+ verify(i5);
+
+ std::vector<int, UneqAlloc> v{1, 2, 3, 4, 5};
+ // Object is constructed using allocator-aware constructor.
+ std::polymorphic<std::vector<int, UneqAlloc>, ScopedAlloc>
+ i7(std::allocator_arg, ScopedAlloc(11, 22), v);
+ VERIFY( i7->size() == 5 );
+ VERIFY( v.size() == 5 );
+ VERIFY( i7->get_allocator().get_personality() == 22 );
+ VERIFY( i7.get_allocator().get_personality() == 11 );
+
+ std::polymorphic<std::vector<int, UneqAlloc>, ScopedAlloc>
+ i8(std::allocator_arg, ScopedAlloc(11, 22), std::move(v));
+ VERIFY( i8->size() == 5 );
+ VERIFY( v.size() == 0 );
+ VERIFY( i8->get_allocator().get_personality() == 22 );
+ VERIFY( i8.get_allocator().get_personality() == 11 );
+}
+
+constexpr void
+test_inplace_ctor()
+{
+ std::polymorphic<Obj> i1(std::in_place_type<Obj>);
+ VERIFY( i1->i == 0 );
+ VERIFY( i1->c[0] == 0 );
+ VERIFY( i1->c[1] == 0 );
+
+ std::polymorphic<Obj> i2(std::in_place_type<Obj>, 10);
+ VERIFY( i2->i == 10 );
+ VERIFY( i2->c[0] == 0 );
+ VERIFY( i2->c[1] == 0 );
+
+ std::polymorphic<Obj, uneq_allocator<Obj>>
+ i3(std::allocator_arg, 42, std::in_place_type<Obj>);
+ VERIFY( i3->i == 0 );
+ VERIFY( i3->c[0] == 0 );
+ VERIFY( i3->c[1] == 0 );
+ VERIFY( i3.get_allocator().get_personality() == 42 );
+
+ std::polymorphic<Obj, uneq_allocator<Obj>>
+ i4(std::allocator_arg, 42, std::in_place_type<Obj>, 10);
+ VERIFY( i4->i == 10 );
+ VERIFY( i4->c[0] == 0 );
+ VERIFY( i4->c[1] == 0 );
+ VERIFY( i4.get_allocator().get_personality() == 42 );
+
+ std::polymorphic<std::vector<int>>
+ i5(std::in_place_type<std::vector<int>>);
+ VERIFY( i5->size() == 0 );
+
+ std::polymorphic<std::vector<int>>
+ i6(std::in_place_type<std::vector<int>>, 5, 13);
+ VERIFY( i6->size() == 5 );
+ VERIFY( i6->at(0) == 13 );
+
+ std::polymorphic<std::vector<int>>
+ i7(std::in_place_type<std::vector<int>>, {1, 2, 3, 4});
+ VERIFY( i7->size() == 4 );
+ VERIFY( i7->at(2) == 3 );
+
+ std::polymorphic<std::vector<int, UneqAlloc>>
+ i8(std::in_place_type<std::vector<int, UneqAlloc>>, UneqAlloc{42});
+ VERIFY( i8->size() == 0 );
+ VERIFY( i8->get_allocator().get_personality() == 42 );
+
+ std::polymorphic<std::vector<int, UneqAlloc>>
+ i9(std::in_place_type<std::vector<int, UneqAlloc>>, 5, 13, UneqAlloc{42});
+ VERIFY( i9->size() == 5 );
+ VERIFY( i9->at(0) == 13 );
+ VERIFY( i9->get_allocator().get_personality() == 42 );
+
+ std::polymorphic<std::vector<int, UneqAlloc>>
+ i10(std::in_place_type<std::vector<int, UneqAlloc>>, {1, 2, 3, 4}, UneqAlloc{42});
+ VERIFY( i10->size() == 4 );
+ VERIFY( i10->at(2) == 3 );
+ VERIFY( i10->get_allocator().get_personality() == 42 );
+
+ std::polymorphic<std::vector<int, UneqAlloc>, ScopedAlloc>
+ i14(std::allocator_arg, ScopedAlloc(11, 22),
+ std::in_place_type<std::vector<int, UneqAlloc>>);
+ VERIFY( i14->size() == 0 );
+ VERIFY( i14->get_allocator().get_personality() == 22 );
+ VERIFY( i14.get_allocator().get_personality() == 11 );
+
+ std::polymorphic<std::vector<int, UneqAlloc>, ScopedAlloc>
+ i15(std::allocator_arg, ScopedAlloc(11, 22),
+ std::in_place_type<std::vector<int, UneqAlloc>>, 5, 13);
+ VERIFY( i15->size() == 5 );
+ VERIFY( i15->at(0) == 13 );
+ VERIFY( i15->get_allocator().get_personality() == 22 );
+ VERIFY( i15.get_allocator().get_personality() == 11 );
+
+ std::polymorphic<std::vector<int, UneqAlloc>, ScopedAlloc>
+ i16(std::allocator_arg, ScopedAlloc(11, 22),
+ std::in_place_type<std::vector<int, UneqAlloc>>, {1, 2, 3, 4});
+ VERIFY( i16->size() == 4 );
+ VERIFY( i16->at(2) == 3 );
+ VERIFY( i16->get_allocator().get_personality() == 22 );
+ VERIFY( i16.get_allocator().get_personality() == 11 );
+}
+
+int main()
+{
+ test_default_ctor();
+ test_forwarding_ctor();
+ test_inplace_ctor();
+
+ static_assert([] {
+ test_default_ctor();
+ test_forwarding_ctor();
+ test_inplace_ctor();
+ return true;
+ });
+}
diff --git a/libstdc++-v3/testsuite/std/memory/polymorphic/ctor_poly.cc b/libstdc++-v3/testsuite/std/memory/polymorphic/ctor_poly.cc
new file mode 100644
index 0000000..03519a1
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/memory/polymorphic/ctor_poly.cc
@@ -0,0 +1,220 @@
+// { dg-do run { target c++26 } }
+
+#include <memory>
+#include <scoped_allocator>
+#include <utility>
+#include <vector>
+
+#ifndef __cpp_lib_polymorphic
+# error __cpp_lib_polymorphic feature test macro missing in <memory>
+#elif __cpp_lib_polymorphic != 202502
+# error __cpp_lib_polymorphic feature test macro has wrong value in <memory>
+#endif
+
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct Base {
+ friend constexpr
+ bool operator==(const Base& lhs, const Base& rhs)
+ { return lhs.eq(rhs); }
+
+ virtual constexpr int
+ get_personality() const
+ { return -1; }
+
+private:
+ constexpr virtual bool
+ eq(const Base& other) const
+ { return true; }
+};
+
+struct ObjDerived : Base
+{
+ constexpr ObjDerived()
+ : x(0), y(0), z(0)
+ { }
+
+ constexpr ObjDerived(int a, int b, int c)
+ : x(a), y(b), z(c)
+ { }
+
+ virtual constexpr int
+ get_personality() const
+ { return -2; }
+
+private:
+ constexpr bool
+ eq(const Base& other) const override
+ {
+ if (auto op = dynamic_cast<const ObjDerived*>(&other))
+ return this->x == op->x && this->y == op->y && this->z == op->z;
+ return false;
+ }
+
+ int x;
+ int y;
+ int z;
+};
+
+template<typename T, typename Allocator>
+struct VecDerived : Base, std::vector<T, Allocator>
+{
+ using VecBase = std::vector<T, Allocator>;
+
+ using VecBase::VecBase;
+
+ constexpr int
+ get_personality() const override
+ { return this->get_allocator().get_personality(); }
+
+private:
+
+ constexpr bool
+ eq(const Base& other) const override
+ {
+ if (auto op = dynamic_cast<const VecDerived*>(&other))
+ return *static_cast<const VecBase*>(this)
+ == *static_cast<const VecBase*>(op);
+ return false;
+ }
+};
+
+using __gnu_test::uneq_allocator;
+using UneqAlloc = uneq_allocator<int>;
+using ScopedAlloc = std::scoped_allocator_adaptor<
+ uneq_allocator<Base>,
+ UneqAlloc>;
+
+constexpr void
+test_default_ctor()
+{
+ using __gnu_test::default_init_allocator;
+
+ std::polymorphic<Base, default_init_allocator<Base>> i1;
+ default_init_allocator<int> a{};
+
+ // The contained object and the allocator should be value-initialized.
+ VERIFY( *i1 == Base() );
+ VERIFY( i1->get_personality() == -1 );
+ VERIFY( i1.get_allocator() == a );
+
+ a.state = 5;
+ // Allocator-extended default constructor:
+ std::polymorphic<Base, default_init_allocator<Base>> i2(std::allocator_arg, a);
+ VERIFY( *i1 == Base() );
+ VERIFY( i1->get_personality() == -1 );
+}
+
+constexpr void
+test_forwarding_ctor()
+{
+ const ObjDerived src(1, 2, 3);
+
+ std::polymorphic<Base> i1(src);
+ VERIFY( *i1 == src );
+ VERIFY( i1->get_personality() == -2 );
+ std::polymorphic<Base> i2(std::move(src));
+ VERIFY( *i2 == src );
+ VERIFY( i2->get_personality() == -2 );
+
+ ObjDerived obj = src;
+ std::polymorphic<Base> i3(obj);
+ VERIFY( *i3 == src );
+ VERIFY( i3->get_personality() == -2 );
+ std::polymorphic<Base> i4(std::move(obj));
+ VERIFY( *i4 == src );
+ VERIFY( i4->get_personality() == -2 );
+
+ const VecDerived<int, UneqAlloc> v{1, 2, 3, 4, 5};
+ // Object is constructed using allocator-aware constructor.
+ std::polymorphic<Base, ScopedAlloc>
+ i5(std::allocator_arg, ScopedAlloc(11, 22), v);
+ VERIFY( *i5 == v );
+ VERIFY( i5->get_personality() == 22 );
+ VERIFY( i5.get_allocator().get_personality() == 11 );
+
+ std::polymorphic<Base, ScopedAlloc>
+ i6(std::allocator_arg, ScopedAlloc(11, 22), auto(v));
+ VERIFY( *i6 == v );
+ VERIFY( i6->get_personality() == 22 );
+ VERIFY( i6.get_allocator().get_personality() == 11 );
+}
+
+constexpr void
+test_inplace_ctor()
+{
+ std::polymorphic<Base> i1(std::in_place_type<ObjDerived>);
+ VERIFY( *i1 == ObjDerived() );
+ VERIFY( i1->get_personality() == -2 );
+
+ std::polymorphic<Base> i2(std::in_place_type<ObjDerived>, 10, 20, 30);
+ VERIFY( *i2 == ObjDerived(10, 20, 30) );
+ VERIFY( i2->get_personality() == -2 );
+
+ std::polymorphic<Base, uneq_allocator<Base>>
+ i3(std::allocator_arg, 42, std::in_place_type<ObjDerived>);
+ VERIFY( *i3 == ObjDerived() );
+ VERIFY( i3->get_personality() == -2 );
+ VERIFY( i3.get_allocator().get_personality() == 42 );
+
+ std::polymorphic<Base, uneq_allocator<Base>>
+ i4(std::allocator_arg, 42, std::in_place_type<ObjDerived>, 10, 20, 30);
+ VERIFY( *i4 == ObjDerived(10, 20, 30) );
+ VERIFY( i4->get_personality() == -2 );
+ VERIFY( i4.get_allocator().get_personality() == 42 );
+
+ const VecDerived<int, UneqAlloc> ze;
+ const VecDerived<int, UneqAlloc> fe(5, 13);
+ const VecDerived<int, UneqAlloc> il{1, 2, 3 ,4};
+
+ std::polymorphic<Base>
+ i5(std::in_place_type<VecDerived<int, UneqAlloc>>, UneqAlloc{42});
+ VERIFY( *i5 == ze );
+ VERIFY( i5->get_personality() == 42 );
+
+ std::polymorphic<Base>
+ i6(std::in_place_type<VecDerived<int, UneqAlloc>>, 5, 13, UneqAlloc{42});
+ VERIFY( *i6 == fe );
+ VERIFY( i6->get_personality() == 42 );
+
+ std::polymorphic<Base>
+ i7(std::in_place_type<VecDerived<int, UneqAlloc>>, {1, 2, 3, 4}, UneqAlloc{42});
+ VERIFY( *i7 == il );
+ VERIFY( i7->get_personality() == 42 );
+
+ std::polymorphic<Base, ScopedAlloc>
+ i8(std::allocator_arg, ScopedAlloc(11, 22),
+ std::in_place_type<VecDerived<int, UneqAlloc>>);
+ VERIFY( *i8 == ze );
+ VERIFY( i8->get_personality() == 22 );
+ VERIFY( i8.get_allocator().get_personality() == 11 );
+
+ std::polymorphic<Base, ScopedAlloc>
+ i9(std::allocator_arg, ScopedAlloc(11, 22),
+ std::in_place_type<VecDerived<int, UneqAlloc>>, 5, 13);
+ VERIFY( *i9 == fe );
+ VERIFY( i9->get_personality() == 22 );
+ VERIFY( i9.get_allocator().get_personality() == 11 );
+
+ std::polymorphic<Base, ScopedAlloc>
+ i10(std::allocator_arg, ScopedAlloc(11, 22),
+ std::in_place_type<VecDerived<int, UneqAlloc>>, {1, 2, 3, 4});
+ VERIFY( *i10 == il );
+ VERIFY( i10->get_personality() == 22 );
+ VERIFY( i10.get_allocator().get_personality() == 11 );
+}
+
+int main()
+{
+ test_default_ctor();
+ test_forwarding_ctor();
+ test_inplace_ctor();
+
+ static_assert([] {
+ test_default_ctor();
+ test_forwarding_ctor();
+ test_inplace_ctor();
+ return true;
+ });
+}
diff --git a/libstdc++-v3/testsuite/std/memory/polymorphic/incomplete.cc b/libstdc++-v3/testsuite/std/memory/polymorphic/incomplete.cc
new file mode 100644
index 0000000..e5dd78f
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/memory/polymorphic/incomplete.cc
@@ -0,0 +1,13 @@
+// { dg-do compile { target c++26 } }
+
+#include <memory>
+
+struct Incomplete;
+
+std::polymorphic<Incomplete>*
+test_move(std::polymorphic<Incomplete>& i1, std::polymorphic<Incomplete>& i2)
+{
+ i1 = std::move(i2);
+ swap(i1, i2);
+ return new std::polymorphic<Incomplete>(std::move(i1));
+}
diff --git a/libstdc++-v3/testsuite/std/memory/polymorphic/invalid_neg.cc b/libstdc++-v3/testsuite/std/memory/polymorphic/invalid_neg.cc
new file mode 100644
index 0000000..a01af3f
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/memory/polymorphic/invalid_neg.cc
@@ -0,0 +1,28 @@
+// { dg-do compile { target c++26 } }
+
+#include <memory>
+
+// In every specialization polymorphic<T, Allocator>, if the type
+// allocator_traits<Allocator>::value_type is not the same type as T,
+// the program is ill-formed.
+using T1 = std::polymorphic<int, std::allocator<long>>::value_type; // { dg-error "here" }
+
+// A program that instantiates the definition of the template
+// polymorphic<T, Allocator> with a type for the T parameter that is
+// a non-object type, an array type, in_place_t,
+// a specialization of in_place_type_t, or a cv-qualified type is ill-formed.
+
+using T2 = std::polymorphic<int&>::value_type; // { dg-error "here" }
+
+using T3 = std::polymorphic<int[1]>::value_type; // { dg-error "here" }
+
+using T4 = std::polymorphic<std::in_place_t>::value_type; // { dg-error "here" }
+
+using T5 = std::polymorphic<std::in_place_type_t<int>>::value_type; // { dg-error "here" }
+
+using T6 = std::polymorphic<const int>::value_type; // { dg-error "here" }
+
+using T7 = std::polymorphic<volatile int>::value_type; // { dg-error "here" }
+
+// { dg-error "static assertion failed" "" { target *-*-* } 0 }
+// { dg-prune-output "forming pointer to reference" }
diff --git a/libstdc++-v3/testsuite/std/memory/polymorphic/move.cc b/libstdc++-v3/testsuite/std/memory/polymorphic/move.cc
new file mode 100644
index 0000000..c802159
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/memory/polymorphic/move.cc
@@ -0,0 +1,177 @@
+// { dg-do run { target c++26 } }
+
+#include <memory>
+#include <scoped_allocator>
+#include <utility>
+#include <vector>
+#include <optional>
+
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct Base {
+ friend constexpr
+ bool operator==(const Base& lhs, const Base& rhs)
+ { return lhs.eq(rhs); }
+
+private:
+ constexpr virtual bool
+ eq(const Base& other) const = 0;
+};
+
+struct Derived : Base
+{
+ constexpr Derived()
+ : x(0), y(0), z(0)
+ { }
+
+ constexpr Derived(int a, int b, int c)
+ : x(a), y(b), z(c)
+ { }
+
+private:
+ constexpr bool
+ eq(const Base& other) const override
+ {
+ if (auto op = dynamic_cast<const Derived*>(&other))
+ return this->x == op->x && this->y == op->y && this->z == op->z;
+ return false;
+ }
+
+ int x;
+ int y;
+ int z;
+};
+
+using __gnu_test::tracker_allocator;
+using Counter = __gnu_test::tracker_allocator_counter;
+using Polymorphic = std::polymorphic<Base, tracker_allocator<Base>>;
+const Polymorphic val(std::in_place_type<Derived>, 1, 2, 3);
+
+constexpr void
+verifyNoAllocations()
+{
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+}
+
+constexpr void
+test_ctor()
+{
+ std::optional<Polymorphic> src;
+ auto make = [&src] -> Polymorphic&& {
+ src.emplace(val);
+ Counter::reset();
+ return std::move(*src);
+ };
+
+ Polymorphic i1(make());
+ VERIFY( src->valueless_after_move() );
+ VERIFY( *i1 == *val );
+ verifyNoAllocations();
+
+ Polymorphic i2(std::allocator_arg, {}, make());
+ VERIFY( src->valueless_after_move() );
+ VERIFY( *i2 == *val );
+ verifyNoAllocations();
+}
+
+constexpr void
+test_assign()
+{
+ std::optional<Polymorphic> src;
+ auto make = [&src] -> Polymorphic&& {
+ src.emplace(val);
+ Counter::reset();
+ return std::move(*src);
+ };
+
+ Polymorphic i1(std::in_place_type<Derived>);
+
+ i1 = make();
+ VERIFY( src->valueless_after_move() );
+ VERIFY( *i1 == *val );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() >= sizeof(Derived) );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 1 );
+
+ auto(std::move(i1));
+ i1 = make();
+ VERIFY( *i1 == *val );
+ VERIFY( src->valueless_after_move() );
+ verifyNoAllocations();
+}
+
+constexpr void
+test_swap()
+{
+ const Polymorphic val1(std::in_place_type<Derived>, 1, 2, 3);
+ const Polymorphic val2(std::in_place_type<Derived>, 2, 4, 6);
+
+ Polymorphic i1(val1);
+ Polymorphic i2(val2);
+ Counter::reset();
+ i1.swap(i2);
+ VERIFY( *i2 == *val1 );
+ VERIFY( *i1 == *val2 );
+ verifyNoAllocations();
+
+ auto(std::move(i1));
+
+ Counter::reset();
+ i1.swap(i2);
+ VERIFY( *i1 == *val1 );
+ VERIFY( i2.valueless_after_move() );
+ verifyNoAllocations();
+}
+
+constexpr void
+test_valueless()
+{
+ auto e = [] {
+ Polymorphic res(std::in_place_type<Derived>);
+ auto(std::move(res));
+ Counter::reset();
+ return res;
+ };
+
+ Polymorphic i1(e());
+ VERIFY( i1.valueless_after_move() );
+ verifyNoAllocations();
+
+ Polymorphic i2(std::allocator_arg, {}, e());
+ VERIFY( i2.valueless_after_move() );
+ verifyNoAllocations();
+
+ Polymorphic i3(val);
+ i3 = e();
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() >= sizeof(Derived) );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 1 );
+
+ i3 = e();
+ verifyNoAllocations();
+}
+
+constexpr void
+test_all()
+{
+ test_ctor();
+ test_assign();
+ test_swap();
+ test_valueless();
+}
+
+int main()
+{
+ test_all();
+
+ static_assert([] {
+ test_all();
+ return true;
+ });
+}
diff --git a/libstdc++-v3/testsuite/std/memory/polymorphic/move_alloc.cc b/libstdc++-v3/testsuite/std/memory/polymorphic/move_alloc.cc
new file mode 100644
index 0000000..09afedb
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/memory/polymorphic/move_alloc.cc
@@ -0,0 +1,339 @@
+// { dg-do run { target c++26 } }
+
+#include <memory>
+#include <scoped_allocator>
+#include <utility>
+#include <vector>
+#include <optional>
+
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct Base {
+ friend constexpr
+ bool operator==(const Base& lhs, const Base& rhs)
+ { return lhs.eq(rhs); }
+
+ virtual constexpr int
+ get_alloc_personality() const
+ { return -1; }
+
+private:
+ constexpr virtual bool
+ eq(const Base& other) const = 0;
+};
+
+template<typename T, typename Allocator>
+struct VecDerived : Base, std::vector<T, Allocator>
+{
+ using VecBase = std::vector<T, Allocator>;
+
+ using VecBase::VecBase;
+
+ constexpr int
+ get_alloc_personality() const override
+ { return this->get_allocator().get_personality(); }
+
+private:
+
+ constexpr bool
+ eq(const Base& other) const override
+ {
+ if (auto op = dynamic_cast<const VecDerived*>(&other))
+ return *static_cast<const VecBase*>(this)
+ == *static_cast<const VecBase*>(op);
+ return false;
+ }
+};
+
+using __gnu_test::propagating_allocator;
+using __gnu_test::tracker_allocator;
+using Counter = __gnu_test::tracker_allocator_counter;
+
+constexpr void
+verifyNoAllocations()
+{
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+}
+
+template<bool Propagate>
+constexpr void
+test_ctor()
+{
+ using PropAlloc = propagating_allocator<int, Propagate>;
+ using Vector = VecDerived<int, PropAlloc>;
+ using ScopedAlloc = std::scoped_allocator_adaptor<
+ propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>,
+ PropAlloc>;
+ using Polymorphic = std::polymorphic<Vector, ScopedAlloc>;
+
+ const Polymorphic val(std::in_place_type<Vector>, {1, 2, 3});
+ std::optional<Polymorphic> src;
+ auto make = [&val, &src] -> Polymorphic&& {
+ src.emplace(std::allocator_arg, ScopedAlloc{11, 22}, val);
+ Counter::reset();
+ return std::move(*src);
+ };
+
+ Polymorphic i1(make());
+ VERIFY( src->valueless_after_move() );
+ VERIFY( *i1 == *val );
+ VERIFY( i1->get_alloc_personality() == 22 );
+ VERIFY( i1.get_allocator().get_personality() == 11 );
+ verifyNoAllocations();
+
+ Polymorphic i2(std::allocator_arg, ScopedAlloc{11, 22}, make());
+ VERIFY( src->valueless_after_move() );
+ VERIFY( *i2 == *val );
+ VERIFY( i2->get_alloc_personality() == 22 );
+ VERIFY( i2.get_allocator().get_personality() == 11 );
+ verifyNoAllocations();
+
+ Polymorphic i3(std::allocator_arg, ScopedAlloc{33, 44}, make());
+ // We move-from contained object
+ VERIFY( !src->valueless_after_move() );
+ VERIFY( *i3 == *val );
+ VERIFY( i3->get_alloc_personality() == 44 );
+ VERIFY( i3.get_allocator().get_personality() == 33 );
+ VERIFY( Counter::get_allocation_count() >= sizeof(Vector) );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 2 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+}
+
+template<bool Propagate>
+constexpr void
+test_assign()
+{
+ using PropAlloc = propagating_allocator<int, Propagate>;
+ using Vector = VecDerived<int, PropAlloc>;
+ using ScopedAlloc = std::scoped_allocator_adaptor<
+ propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>,
+ PropAlloc>;
+ using Polymorphic = std::polymorphic<Vector, ScopedAlloc>;
+
+ const Polymorphic val(std::in_place_type<Vector>, {1, 2, 3});
+ std::optional<Polymorphic> src;
+ auto make = [&val, &src] -> Polymorphic&& {
+ src.emplace(std::allocator_arg, ScopedAlloc{11, 22}, val);
+ Counter::reset();
+ return std::move(*src);
+ };
+
+ Counter::reset();
+ Polymorphic i1(std::allocator_arg, ScopedAlloc{11, 22});
+ const std::size_t holderSize = Counter::get_allocation_count();
+ VERIFY( holderSize >= sizeof(Vector) );
+
+ i1 = make();
+ VERIFY( src->valueless_after_move() );
+ VERIFY( *i1 == *val );
+ VERIFY( i1->get_alloc_personality() == 22 );
+ VERIFY( i1.get_allocator().get_personality() == 11 );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() == holderSize );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 1 );
+
+ Polymorphic i2(std::allocator_arg, ScopedAlloc{33, 44});
+
+ i2 = make();
+ VERIFY( *i2 == *val );
+ if (Propagate)
+ {
+ VERIFY( src->valueless_after_move() );
+ VERIFY( i2->get_alloc_personality() == 22 );
+ VERIFY( i2.get_allocator().get_personality() == 11 );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 0 );
+ }
+ else
+ {
+ // We allocate new holder and move-from contained object
+ VERIFY( !src->valueless_after_move() );
+ VERIFY( i2->get_alloc_personality() == 44 );
+ VERIFY( i2.get_allocator().get_personality() == 33 );
+ VERIFY( Counter::get_allocation_count() == holderSize );
+ VERIFY( Counter::get_construct_count() == 2 );
+ }
+ VERIFY( Counter::get_deallocation_count() == holderSize );
+ VERIFY( Counter::get_destruct_count() == 1 );
+
+ Polymorphic i3(std::allocator_arg, ScopedAlloc{11, 22},
+ std::in_place_type<Vector>);
+ auto(std::move(i3));
+
+ i3 = make();
+ VERIFY( *i3 == *val );
+ VERIFY( src->valueless_after_move() );
+ VERIFY( i3->get_alloc_personality() == 22 );
+ VERIFY( i3.get_allocator().get_personality() == 11 );
+ verifyNoAllocations();
+
+ Polymorphic i4(std::allocator_arg, ScopedAlloc{33, 44},
+ std::in_place_type<Vector>);
+ auto(std::move(i4));
+
+ i4 = make();
+ VERIFY( *i4 == *val );
+ if (Propagate)
+ {
+ VERIFY( src->valueless_after_move() );
+ VERIFY( i4->get_alloc_personality() == 22 );
+ VERIFY( i4.get_allocator().get_personality() == 11 );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 0 );
+ }
+ else
+ {
+ // We allocate new holder and move-from contained object
+ VERIFY( !src->valueless_after_move() );
+ VERIFY( i4->get_alloc_personality() == 44 );
+ VERIFY( i4.get_allocator().get_personality() == 33 );
+ VERIFY( Counter::get_allocation_count() == holderSize );
+ VERIFY( Counter::get_construct_count() == 2 );
+ }
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+}
+
+template<bool Propagate>
+constexpr void
+test_swap()
+{
+ using PropAlloc = propagating_allocator<int, Propagate>;
+ using Vector = VecDerived<int, PropAlloc>;
+ using ScopedAlloc = std::scoped_allocator_adaptor<
+ propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>,
+ PropAlloc>;
+ using Polymorphic = std::polymorphic<Vector, ScopedAlloc>;
+
+ const Polymorphic val1(std::in_place_type<Vector>, {1, 2, 3});
+ const Polymorphic val2(std::in_place_type<Vector>, {2, 4, 6});
+
+ Polymorphic i1(std::allocator_arg, ScopedAlloc{11, 22}, val1);
+ Polymorphic i2(std::allocator_arg, ScopedAlloc{11, 22}, val2);
+ Counter::reset();
+ i1.swap(i2);
+ VERIFY( *i2 == *val1 );
+ VERIFY( *i1 == *val2 );
+ verifyNoAllocations();
+
+ auto(std::move(i1));
+
+ Counter::reset();
+ i1.swap(i2);
+ VERIFY( *i1 == *val1 );
+ VERIFY( i2.valueless_after_move() );
+ verifyNoAllocations();
+
+ if (!Propagate)
+ return;
+
+ Polymorphic i3(std::allocator_arg, ScopedAlloc{33, 44}, val2);
+ Counter::reset();
+ i1.swap(i3);
+ VERIFY( *i1 == *val2 );
+ VERIFY( i1->get_alloc_personality() == 44 );
+ VERIFY( i1.get_allocator().get_personality() == 33 );
+ VERIFY( *i3 == *val1 );
+ VERIFY( i3->get_alloc_personality() == 22 );
+ VERIFY( i3.get_allocator().get_personality() == 11 );
+ verifyNoAllocations();
+
+ i1.swap(i2);
+ VERIFY( i1.valueless_after_move() );
+ VERIFY( i1.get_allocator().get_personality() == 11 );
+ VERIFY( *i2 == *val2 );
+ VERIFY( i2->get_alloc_personality() == 44 );
+ VERIFY( i2.get_allocator().get_personality() == 33 );
+ verifyNoAllocations();
+}
+
+template<bool Propagate>
+constexpr void
+test_valueless()
+{
+ using PropAlloc = propagating_allocator<int, Propagate>;
+ using Vector = VecDerived<int, PropAlloc>;
+ using ScopedAlloc = std::scoped_allocator_adaptor<
+ propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>,
+ PropAlloc>;
+ using Polymorphic = std::polymorphic<Vector, ScopedAlloc>;
+
+ auto e = [] {
+ Polymorphic res(std::allocator_arg, ScopedAlloc{11, 22},
+ std::in_place_type<Vector>);
+ auto(std::move(res));
+ Counter::reset();
+ return res;
+ };
+
+ Polymorphic i1(e());
+ VERIFY( i1.valueless_after_move() );
+ VERIFY( i1.get_allocator().get_personality() == 11 );
+ verifyNoAllocations();
+
+ Polymorphic i2(std::allocator_arg, ScopedAlloc{33, 44}, e());
+ VERIFY( i2.valueless_after_move() );
+ VERIFY( i2.get_allocator().get_personality() == 33 );
+ verifyNoAllocations();
+
+ Polymorphic i3(std::allocator_arg, ScopedAlloc{33, 44});
+
+ i3 = e();
+ VERIFY( i3.valueless_after_move() );
+ if (Propagate)
+ VERIFY( i3.get_allocator().get_personality() == 11 );
+ else
+ VERIFY( i3.get_allocator().get_personality() == 33 );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() >= sizeof(Vector) );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 1 );
+
+ i2 = e();
+ VERIFY( i2.valueless_after_move() );
+ if (Propagate)
+ VERIFY( i2.get_allocator().get_personality() == 11 );
+ else
+ VERIFY( i2.get_allocator().get_personality() == 33 );
+ verifyNoAllocations();
+
+ i3.swap(i2);
+ VERIFY( i2.valueless_after_move() );
+ VERIFY( i1.valueless_after_move() );
+ verifyNoAllocations();
+
+ if (!Propagate)
+ return;
+
+ Polymorphic i4(std::allocator_arg, ScopedAlloc{33, 44}, e());
+ i4.swap(i1);
+ verifyNoAllocations();
+}
+
+template<bool Propagate>
+constexpr void
+test_all()
+{
+ test_ctor<Propagate>();
+ test_assign<Propagate>();
+ test_swap<Propagate>();
+ test_valueless<Propagate>();
+}
+
+int main()
+{
+ test_all<true>();
+ test_all<false>();
+
+ static_assert([] {
+ test_all<true>();
+ test_all<false>();
+ return true;
+ });
+}
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc
index 3f1f8eb..5ccf47d 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc
@@ -69,10 +69,23 @@ test03()
auto r2 = views::as_const(views::all(v));
}
+void
+test04()
+{
+ // PR libstdc++/115046 - meta-recursion with join_view and as_const_view
+ int x[3] = {1,2,3};
+ auto v = x
+ | views::chunk(3)
+ | views::transform(views::as_const)
+ | views::join;
+ VERIFY( ranges::equal(v, x) );
+}
+
int
main()
{
static_assert(test01());
static_assert(test02());
test03();
+ test04();
}
diff --git a/libstdc++-v3/testsuite/std/ranges/concat/1.cc b/libstdc++-v3/testsuite/std/ranges/concat/1.cc
index 1672191..f78ed08 100644
--- a/libstdc++-v3/testsuite/std/ranges/concat/1.cc
+++ b/libstdc++-v3/testsuite/std/ranges/concat/1.cc
@@ -99,6 +99,18 @@ test04()
using type = decltype(v);
}
+void
+test05()
+{
+ // PR libstdc++/120934 - views::concat is ill-formed depending on argument order
+ auto v1 = views::single(1);
+ std::vector<int> vec = {2, 3};
+ auto v2 = views::join(views::transform(vec, views::single));
+
+ static_assert( ranges::range<decltype(views::concat(v1, v2))> );
+ static_assert( ranges::range<decltype(views::concat(v2, v1))> );
+}
+
int
main()
{
@@ -107,4 +119,5 @@ main()
test02();
test03();
test04();
+ test05();
}
diff --git a/libstdc++-v3/testsuite/std/ranges/iota/max_size_type.cc b/libstdc++-v3/testsuite/std/ranges/iota/max_size_type.cc
index 3e6f954..4739d9e 100644
--- a/libstdc++-v3/testsuite/std/ranges/iota/max_size_type.cc
+++ b/libstdc++-v3/testsuite/std/ranges/iota/max_size_type.cc
@@ -400,6 +400,13 @@ static_assert(max_diff_t(max_size_t(1)
<< (numeric_limits<max_size_t>::digits-1))
== numeric_limits<max_diff_t>::min());
+// Verify that the types are structural types and can therefore be used
+// as NTTP types.
+template<max_size_t V> struct Su { static_assert(V*V == V+132); };
+template<max_diff_t V> struct Ss { static_assert(V*V == V+132); };
+template struct Su<12>;
+template struct Ss<12>;
+
int
main()
{
diff --git a/libstdc++-v3/testsuite/std/time/clock/local/io.cc b/libstdc++-v3/testsuite/std/time/clock/local/io.cc
index b4d562f..67818e8 100644
--- a/libstdc++-v3/testsuite/std/time/clock/local/io.cc
+++ b/libstdc++-v3/testsuite/std/time/clock/local/io.cc
@@ -89,6 +89,9 @@ test_format()
s = std::format("{}", local_seconds{});
VERIFY( s == "1970-01-01 00:00:00" );
+
+ s = std::format("{}", local_days{}); // PR libstdc++/120293
+ VERIFY( s == "1970-01-01" );
}
void
diff --git a/libstdc++-v3/testsuite/std/time/format/data_not_present_neg.cc b/libstdc++-v3/testsuite/std/time/format/data_not_present_neg.cc
new file mode 100644
index 0000000..bb09451
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/time/format/data_not_present_neg.cc
@@ -0,0 +1,164 @@
+// { dg-do compile { target c++20 } }
+
+#include <chrono>
+#include <format>
+
+using namespace std::chrono;
+
+auto d1 = std::format("{:%w}", 10d); // { dg-error "call to consteval function" }
+auto d2 = std::format("{:%m}", 10d); // { dg-error "call to consteval function" }
+auto d3 = std::format("{:%y}", 10d); // { dg-error "call to consteval function" }
+auto d4 = std::format("{:%F}", 10d); // { dg-error "call to consteval function" }
+auto d5 = std::format("{:%T}", 10d); // { dg-error "call to consteval function" }
+auto d6 = std::format("{:%Q}", 10d); // { dg-error "call to consteval function" }
+auto d7 = std::format("{:%Z}", 10d); // { dg-error "call to consteval function" }
+
+auto w1 = std::format("{:%d}", Thursday); // { dg-error "call to consteval function" }
+auto w2 = std::format("{:%m}", Thursday); // { dg-error "call to consteval function" }
+auto w3 = std::format("{:%y}", Thursday); // { dg-error "call to consteval function" }
+auto w4 = std::format("{:%F}", Thursday); // { dg-error "call to consteval function" }
+auto w5 = std::format("{:%T}", Thursday); // { dg-error "call to consteval function" }
+auto w6 = std::format("{:%Q}", Thursday); // { dg-error "call to consteval function" }
+auto w7 = std::format("{:%Z}", Thursday); // { dg-error "call to consteval function" }
+
+auto wi1 = std::format("{:%d}", Thursday[2]); // { dg-error "call to consteval function" }
+auto wi2 = std::format("{:%m}", Thursday[2]); // { dg-error "call to consteval function" }
+auto wi3 = std::format("{:%y}", Thursday[2]); // { dg-error "call to consteval function" }
+auto wi4 = std::format("{:%F}", Thursday[2]); // { dg-error "call to consteval function" }
+auto wi5 = std::format("{:%T}", Thursday[2]); // { dg-error "call to consteval function" }
+auto wi6 = std::format("{:%Q}", Thursday[2]); // { dg-error "call to consteval function" }
+auto wi7 = std::format("{:%Z}", Thursday[2]); // { dg-error "call to consteval function" }
+
+auto wl1 = std::format("{:%d}", Thursday[last]); // { dg-error "call to consteval function" }
+auto wl2 = std::format("{:%m}", Thursday[last]); // { dg-error "call to consteval function" }
+auto wl3 = std::format("{:%y}", Thursday[last]); // { dg-error "call to consteval function" }
+auto wl4 = std::format("{:%F}", Thursday[last]); // { dg-error "call to consteval function" }
+auto wl5 = std::format("{:%T}", Thursday[last]); // { dg-error "call to consteval function" }
+auto wl6 = std::format("{:%Q}", Thursday[last]); // { dg-error "call to consteval function" }
+auto wl7 = std::format("{:%Z}", Thursday[last]); // { dg-error "call to consteval function" }
+
+auto m1 = std::format("{:%d}", January); // { dg-error "call to consteval function" }
+auto m2 = std::format("{:%w}", January); // { dg-error "call to consteval function" }
+auto m3 = std::format("{:%y}", January); // { dg-error "call to consteval function" }
+auto m4 = std::format("{:%F}", January); // { dg-error "call to consteval function" }
+auto m5 = std::format("{:%T}", January); // { dg-error "call to consteval function" }
+auto m6 = std::format("{:%Q}", January); // { dg-error "call to consteval function" }
+auto m7 = std::format("{:%Z}", January); // { dg-error "call to consteval function" }
+
+auto yr1 = std::format("{:%d}", 2025y); // { dg-error "call to consteval function" }
+auto yr2 = std::format("{:%w}", 2025y); // { dg-error "call to consteval function" }
+auto yr3 = std::format("{:%m}", 2025y); // { dg-error "call to consteval function" }
+auto yr4 = std::format("{:%F}", 2025y); // { dg-error "call to consteval function" }
+auto yr5 = std::format("{:%T}", 2025y); // { dg-error "call to consteval function" }
+auto yr6 = std::format("{:%Q}", 2025y); // { dg-error "call to consteval function" }
+auto yr7 = std::format("{:%Z}", 2025y); // { dg-error "call to consteval function" }
+
+auto md1 = std::format("{:%w}", January/10d); // { dg-error "call to consteval function" }
+auto md2 = std::format("{:%y}", January/10d); // { dg-error "call to consteval function" }
+auto md3 = std::format("{:%F}", January/10d); // { dg-error "call to consteval function" }
+auto md4 = std::format("{:%T}", January/10d); // { dg-error "call to consteval function" }
+auto md5 = std::format("{:%Q}", January/10d); // { dg-error "call to consteval function" }
+auto md6 = std::format("{:%Z}", January/10d); // { dg-error "call to consteval function" }
+
+auto mwi1 = std::format("{:%d}", January/Thursday[2]); // { dg-error "call to consteval function" }
+auto mwi2 = std::format("{:%y}", January/Thursday[2]); // { dg-error "call to consteval function" }
+auto mwi3 = std::format("{:%F}", January/Thursday[2]); // { dg-error "call to consteval function" }
+auto mwi4 = std::format("{:%T}", January/Thursday[2]); // { dg-error "call to consteval function" }
+auto mwi5 = std::format("{:%Q}", January/Thursday[2]); // { dg-error "call to consteval function" }
+auto mwi6 = std::format("{:%Z}", January/Thursday[2]); // { dg-error "call to consteval function" }
+
+auto mwl1 = std::format("{:%d}", January/Thursday[last]); // { dg-error "call to consteval function" }
+auto mwl2 = std::format("{:%y}", January/Thursday[last]); // { dg-error "call to consteval function" }
+auto mwl3 = std::format("{:%F}", January/Thursday[last]); // { dg-error "call to consteval function" }
+auto mwl4 = std::format("{:%T}", January/Thursday[last]); // { dg-error "call to consteval function" }
+auto mwl5 = std::format("{:%Q}", January/Thursday[last]); // { dg-error "call to consteval function" }
+auto mwl6 = std::format("{:%Z}", January/Thursday[last]); // { dg-error "call to consteval function" }
+
+auto ml1 = std::format("{:%d}", January/last); // { dg-error "call to consteval function" }
+auto ml2 = std::format("{:%w}", January/last); // { dg-error "call to consteval function" }
+auto ml3 = std::format("{:%y}", January/last); // { dg-error "call to consteval function" }
+auto ml4 = std::format("{:%F}", January/last); // { dg-error "call to consteval function" }
+auto ml5 = std::format("{:%T}", January/last); // { dg-error "call to consteval function" }
+auto ml6 = std::format("{:%Q}", January/last); // { dg-error "call to consteval function" }
+auto ml7 = std::format("{:%Z}", January/last); // { dg-error "call to consteval function" }
+
+auto ym1 = std::format("{:%d}", 2024y/March); // { dg-error "call to consteval function" }
+auto ym2 = std::format("{:%w}", 2024y/March); // { dg-error "call to consteval function" }
+auto ym3 = std::format("{:%F}", 2024y/March); // { dg-error "call to consteval function" }
+auto ym4 = std::format("{:%T}", 2024y/March); // { dg-error "call to consteval function" }
+auto ym5 = std::format("{:%Q}", 2024y/March); // { dg-error "call to consteval function" }
+auto ym6 = std::format("{:%Z}", 2024y/March); // { dg-error "call to consteval function" }
+
+auto ymd1 = std::format("{:%T}", 2021y/January/10d); // { dg-error "call to consteval function" }
+auto ymd2 = std::format("{:%Q}", 2021y/January/10d); // { dg-error "call to consteval function" }
+auto ymd3 = std::format("{:%Z}", 2021y/January/10d); // { dg-error "call to consteval function" }
+
+auto ymwi1 = std::format("{:%T}", 2021y/January/Thursday[2]); // { dg-error "call to consteval function" }
+auto ymwi2 = std::format("{:%Q}", 2021y/January/Thursday[2]); // { dg-error "call to consteval function" }
+auto ymwi3 = std::format("{:%Z}", 2021y/January/Thursday[2]); // { dg-error "call to consteval function" }
+
+auto ymwl1 = std::format("{:%T}", 2021y/January/Thursday[last]); // { dg-error "call to consteval function" }
+auto ymwl2 = std::format("{:%Q}", 2021y/January/Thursday[last]); // { dg-error "call to consteval function" }
+auto ymwl3 = std::format("{:%Z}", 2021y/January/Thursday[last]); // { dg-error "call to consteval function" }
+
+auto yml1 = std::format("{:%T}", 2021y/January/last); // { dg-error "call to consteval function" }
+auto yml2 = std::format("{:%Q}", 2021y/January/last); // { dg-error "call to consteval function" }
+auto yml3 = std::format("{:%Z}", 2021y/January/last); // { dg-error "call to consteval function" }
+
+auto ls1 = std::format("{:%Q}", local_seconds(20s)); // { dg-error "call to consteval function" }
+auto ls2 = std::format("{:%Z}", local_seconds(10s)); // { dg-error "call to consteval function" }
+auto ld1 = std::format("{:%Q}", local_days(days(20))); // { dg-error "call to consteval function" }
+auto ld2 = std::format("{:%Z}", local_days(days(10))); // { dg-error "call to consteval function" }
+
+auto ss1 = std::format("{:%Q}", sys_seconds(20s)); // { dg-error "call to consteval function" }
+auto sd1 = std::format("{:%Q}", sys_days(days(20))); // { dg-error "call to consteval function" }
+
+auto utc = std::format("{:%Q}", utc_clock::now()); // { dg-error "call to consteval function" }
+auto gps = std::format("{:%Q}", gps_clock::now()); // { dg-error "call to consteval function" }
+auto tai = std::format("{:%Q}", tai_clock::now()); // { dg-error "call to consteval function" }
+auto file = std::format("{:%Q}", file_clock::now()); // { dg-error "call to consteval function" }
+
+const auto ltc = local_seconds(10s);
+#if _GLIBCXX_USE_CXX11_ABI || !_GLIBCXX_USE_DUAL_ABI
+const auto zt = zoned_time<seconds>("Europe/Sofia", local_seconds(10s));
+auto zt1 = std::format("{:%Q}", zt); // { dg-error "call to consteval function" "" { target cxx11_abi } }
+#endif
+auto lf1 = std::format("{:%Q}", local_time_format(ltc)); // { dg-error "call to consteval function" }
+
+auto dur1 = std::format("{:%d}", 123s); // { dg-error "call to consteval function" }
+auto dur2 = std::format("{:%w}", 123s); // { dg-error "call to consteval function" }
+auto dur3 = std::format("{:%m}", 123s); // { dg-error "call to consteval function" }
+auto dur4 = std::format("{:%y}", 123s); // { dg-error "call to consteval function" }
+auto dur5 = std::format("{:%F}", 123s); // { dg-error "call to consteval function" }
+auto dur6 = std::format("{:%Z}", 123s); // { dg-error "call to consteval function" }
+
+using HMS = hh_mm_ss<seconds>;
+auto hms1 = std::format("{:%d}", HMS(1255s)); // { dg-error "call to consteval function" }
+auto hms2 = std::format("{:%w}", HMS(1255s)); // { dg-error "call to consteval function" }
+auto hms3 = std::format("{:%m}", HMS(1255s)); // { dg-error "call to consteval function" }
+auto hms4 = std::format("{:%y}", HMS(1255s)); // { dg-error "call to consteval function" }
+auto hms5 = std::format("{:%F}", HMS(1255s)); // { dg-error "call to consteval function" }
+auto hms6 = std::format("{:%Q}", HMS(1255s)); // { dg-error "call to consteval function" }
+auto hms7 = std::format("{:%Z}", HMS(1255s)); // { dg-error "call to consteval function" }
+
+#if _GLIBCXX_USE_CXX11_ABI || !_GLIBCXX_USE_DUAL_ABI
+auto li1 = std::format("{:%d}", local_info()); // { dg-error "call to consteval function" "" { target cxx11_abi } }
+auto li2 = std::format("{:%w}", local_info()); // { dg-error "call to consteval function" "" { target cxx11_abi } }
+auto li3 = std::format("{:%m}", local_info()); // { dg-error "call to consteval function" "" { target cxx11_abi } }
+auto li4 = std::format("{:%y}", local_info()); // { dg-error "call to consteval function" "" { target cxx11_abi } }
+auto li5 = std::format("{:%F}", local_info()); // { dg-error "call to consteval function" "" { target cxx11_abi } }
+auto li6 = std::format("{:%T}", local_info()); // { dg-error "call to consteval function" "" { target cxx11_abi } }
+auto li7 = std::format("{:%Q}", local_info()); // { dg-error "call to consteval function" "" { target cxx11_abi } }
+auto li8 = std::format("{:%Z}", local_info()); // { dg-error "call to consteval function" "" { target cxx11_abi } }
+
+auto si1 = std::format("{:%d}", sys_info()); // { dg-error "call to consteval function" "" { target cxx11_abi } }
+auto si2 = std::format("{:%w}", sys_info()); // { dg-error "call to consteval function" "" { target cxx11_abi } }
+auto si3 = std::format("{:%m}", sys_info()); // { dg-error "call to consteval function" "" { target cxx11_abi } }
+auto si4 = std::format("{:%y}", sys_info()); // { dg-error "call to consteval function" "" { target cxx11_abi } }
+auto si5 = std::format("{:%F}", sys_info()); // { dg-error "call to consteval function" "" { target cxx11_abi } }
+auto si6 = std::format("{:%T}", sys_info()); // { dg-error "call to consteval function" "" { target cxx11_abi } }
+auto si7 = std::format("{:%Q}", sys_info()); // { dg-error "call to consteval function" "" { target cxx11_abi } }
+auto si8 = std::format("{:%Z}", sys_info()); // { dg-error "call to consteval function" "" { target cxx11_abi } }
+#endif
+
+// { dg-error "call to non-'constexpr' function" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/std/time/format/empty_spec.cc b/libstdc++-v3/testsuite/std/time/format/empty_spec.cc
new file mode 100644
index 0000000..ef1b19d
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/time/format/empty_spec.cc
@@ -0,0 +1,917 @@
+// { dg-do run { target c++20 } }
+// { dg-require-effective-target hosted }
+// { dg-timeout-factor 5 }
+
+#include <chrono>
+#include <ranges>
+#include <sstream>
+#include <testsuite_hooks.h>
+
+using namespace std::chrono;
+
+#define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S)
+#define WIDEN(S) WIDEN_(CharT, S)
+
+template<typename CharT, typename T>
+void
+test_no_empty_spec()
+{
+ try
+ {
+ T t{};
+
+ if constexpr (std::is_same_v<CharT, char>)
+ (void)std::vformat("{}", std::make_format_args(t));
+#ifdef _GLIBCXX_USE_WCHAR_T
+ else
+ (void)std::vformat(L"{}", std::make_wformat_args(t));
+#endif // _GLIBCXX_USE_WCHAR_T
+ VERIFY(false);
+ }
+ catch (const std::format_error&)
+ {
+ VERIFY(true);
+ }
+}
+
+template<typename T, typename CharT>
+void verify(const T& t, std::basic_string_view<CharT> str)
+{
+ std::basic_string<CharT> res;
+
+ res = std::format(WIDEN("{}"), t);
+ VERIFY( res == str );
+
+ std::basic_stringstream<CharT> os;
+ os << t;
+ res = std::move(os).str();
+ VERIFY( res == str );
+}
+
+template<typename T, typename CharT>
+void verify(const T& t, const CharT* str)
+{ verify(t, std::basic_string_view<CharT>(str)); }
+
+template<typename CharT>
+void
+test_padding()
+{
+ std::basic_string<CharT> res;
+
+ res = std::format(WIDEN("{:5}"), day(2));
+ VERIFY( res == WIDEN("02 ") );
+
+ res = std::format(WIDEN("{:>6}"), weekday(4));
+ VERIFY( res == WIDEN(" Thu") );
+
+ res = std::format(WIDEN("{:^7}"), month(3));
+ VERIFY( res == WIDEN(" Mar ") );
+
+ res = std::format(WIDEN("{:-<4}"), day(30));
+ VERIFY( res == WIDEN("30--") );
+
+ res = std::format(WIDEN("{:+>30}"), weekday(9));
+ VERIFY( res == WIDEN("++++++9 is not a valid weekday") );
+
+ res = std::format(WIDEN("{:=^27}"), month(16));
+ VERIFY( res == WIDEN("==16 is not a valid month==") );
+}
+
+template<typename Ret = void, typename Under = long>
+struct Rep
+{
+ using Return
+ = std::conditional_t<std::is_void_v<Ret>, Rep, Ret>;
+
+ Rep(Under v = 0) : val(v) {}
+
+ template<typename ORet, typename OUnder>
+ Rep(Rep<ORet, OUnder> o) : val(o.val) {}
+
+ operator Under() const
+ { return val; }
+
+ Return
+ operator+() const
+ { return val; }
+
+ Rep
+ operator-() const
+ { return -val; }
+
+ friend Rep
+ operator+(Rep lhs, Rep rhs)
+ { return lhs.val + rhs.val; }
+
+ friend Rep
+ operator-(Rep lhs, Rep rhs)
+ { return lhs.val - rhs.val; }
+
+ friend Rep
+ operator*(Rep lhs, Rep rhs)
+ { return lhs.val * rhs.val; }
+
+ friend Rep
+ operator/(Rep lhs, Rep rhs)
+ { return lhs.val / rhs.val; }
+
+ friend auto operator<=>(Rep, Rep) = default;
+
+ template<typename CharT>
+ friend std::basic_ostream<CharT>&
+ operator<<(std::basic_ostream<CharT>& os, const Rep& t)
+ { return os << t.val << WIDEN("[via <<]"); }
+
+ Under val;
+};
+
+template<typename Ret, typename Under1, typename Under2>
+struct std::common_type<Rep<Ret, Under1>, Rep<Ret, Under2>>
+{
+ using type = Rep<Ret, std::common_type_t<Under1, Under2>>;
+};
+
+template<typename Ret, typename Under, typename Other>
+ requires std::is_integral_v<Other>
+struct std::common_type<Rep<Ret, Under>, Other>
+{
+ using type = Rep<Ret, std::common_type_t<Under, Other>>;
+};
+
+template<typename Ret, typename Under, typename Other>
+ requires std::is_integral_v<Other>
+struct std::common_type<Other, Rep<Ret, Under>>
+ : std::common_type<Rep<Ret, Under>, Other>
+{ };
+
+template<typename Ret, typename Under>
+struct std::numeric_limits<Rep<Ret, Under>>
+ : std::numeric_limits<Under>
+{ };
+
+template<typename Ret, typename Under, typename CharT>
+struct std::formatter<Rep<Ret, Under>, CharT>
+ : std::formatter<Under, CharT>
+{
+ template<typename Out>
+ typename std::basic_format_context<Out, CharT>::iterator
+ format(const Rep<Ret>& t, std::basic_format_context<Out, CharT>& ctx) const
+ {
+ constexpr std::basic_string_view<CharT> suffix = WIDEN("[via format]");
+ auto out = std::formatter<Under, CharT>::format(t.val, ctx);
+ return std::ranges::copy(suffix, out).out;
+ }
+};
+
+using deciseconds = duration<seconds::rep, std::deci>;
+
+template<typename CharT>
+void
+test_duration()
+{
+ std::basic_string<CharT> res;
+
+ const milliseconds di(40);
+ verify( di, WIDEN("40ms") );
+ res = std::format(WIDEN("{:>6}"), di);
+ VERIFY( res == WIDEN(" 40ms") );
+
+ verify( -di, WIDEN("-40ms") );
+ res = std::format(WIDEN("{:>6}"), -di);
+ VERIFY( res == WIDEN(" -40ms") );
+}
+
+template<typename CharT>
+void
+test_duration_fp()
+{
+ std::basic_string<CharT> res;
+
+ const duration<double> df(11.22);
+ verify( df, WIDEN("11.22s") );
+ res = std::format(WIDEN("{:=^12}"), df);
+ VERIFY( res == WIDEN("===11.22s===") );
+
+ verify( -df, WIDEN("-11.22s") );
+ res = std::format(WIDEN("{:=^12}"), -df);
+ VERIFY( res == WIDEN("==-11.22s===") );
+
+ // precision accepted but ignored
+ res = std::format(WIDEN("{:.6}"), df);
+ VERIFY( res == WIDEN("11.22s") );
+}
+
+template<typename CharT>
+void
+test_duration_cust()
+{
+ std::basic_string<CharT> res;
+ const duration<char, std::ratio<1, 10>> charRep(123);
+ verify( charRep, WIDEN("123ds") );
+
+ // +asLong returns long, so formatted as long
+ const duration<Rep<long>> asLong(20);
+ verify( asLong, WIDEN("20s") );
+ res = std::format(WIDEN("{:>6}"), asLong);
+ VERIFY( res == WIDEN(" 20s") );
+
+ verify( -asLong, WIDEN("-20s") );
+ res = std::format(WIDEN("{:>6}"), -asLong);
+ VERIFY( res == WIDEN(" -20s") );
+
+ res = std::format(WIDEN("{:%Q}"), asLong);
+ VERIFY( res == WIDEN("20") );
+ res = std::format(WIDEN("{:+<7%Q}"), asLong);
+ VERIFY( res == WIDEN("20+++++") );
+
+ // +asRep returns Rep<>, so formatted as Rep<>
+ const duration<Rep<>> asRep(10);
+ verify( asRep, WIDEN("10[via <<]s") );
+ res = std::format(WIDEN("{:=^15}"), asRep);
+ VERIFY( res == WIDEN("==10[via <<]s==") );
+
+ verify( -asRep, WIDEN("-10[via <<]s") );
+ res = std::format(WIDEN("{:=^15}"), -asRep);
+ VERIFY( res == WIDEN("=-10[via <<]s==") );
+
+ res = std::format(WIDEN("{:%Q}"), asRep);
+ VERIFY( res == WIDEN("10[via format]") );
+ res = std::format(WIDEN("{:=^18%Q}"), asRep);
+ VERIFY( res == WIDEN("==10[via format]==") );
+
+ const duration<Rep<>, std::milli> milliRep(10);
+ verify( milliRep, WIDEN("10[via <<]ms") );
+ res = std::format(WIDEN("{:=^15}"), milliRep);
+ VERIFY( res == WIDEN("=10[via <<]ms==") );
+
+ verify( -milliRep, WIDEN("-10[via <<]ms") );
+ res = std::format(WIDEN("{:=^15}"), -milliRep);
+ VERIFY( res == WIDEN("=-10[via <<]ms=") );
+
+ res = std::format(WIDEN("{:%Q}"), milliRep);
+ VERIFY( res == WIDEN("10[via format]") );
+ res = std::format(WIDEN("{:=^18%Q}"), milliRep);
+ VERIFY( res == WIDEN("==10[via format]==") );
+}
+
+template<typename Ratio, typename Rep, typename Period>
+constexpr auto
+hms(const duration<Rep, Period>& d)
+{
+ using Dur = duration<Rep, typename Ratio::period>;
+ return hh_mm_ss<Dur>(duration_cast<Dur>(d));
+}
+
+template<typename CharT>
+void
+test_hh_mm_ss()
+{
+ auto dt = 22h + 24min + 54s + 111222333ns;
+ verify( hms<nanoseconds>(dt),
+ WIDEN("22:24:54.111222333") );
+ verify( hms<microseconds>(dt),
+ WIDEN("22:24:54.111222") );
+ verify( hms<milliseconds>(dt),
+ WIDEN("22:24:54.111") );
+ verify( hms<deciseconds>(dt),
+ WIDEN("22:24:54.1") );
+ verify( hms<seconds>(dt),
+ WIDEN("22:24:54") );
+ verify( hms<minutes>(dt),
+ WIDEN("22:24:00") );
+ verify( hms<hours>(dt),
+ WIDEN("22:00:00") );
+ verify( hms<nanoseconds>(-dt),
+ WIDEN("-22:24:54.111222333") );
+ verify( hms<microseconds>(-dt),
+ WIDEN("-22:24:54.111222") );
+ verify( hms<milliseconds>(-dt),
+ WIDEN("-22:24:54.111") );
+ verify( hms<deciseconds>(-dt),
+ WIDEN("-22:24:54.1") );
+ verify( hms<seconds>(-dt),
+ WIDEN("-22:24:54") );
+ verify( hms<minutes>(-dt),
+ WIDEN("-22:24:00") );
+ verify( hms<hours>(-dt),
+ WIDEN("-22:00:00") );
+
+ verify( hms<nanoseconds>(-dt),
+ WIDEN("-22:24:54.111222333") );
+
+ dt += 300h;
+ verify( hms<nanoseconds>(dt),
+ WIDEN("322:24:54.111222333") );
+ verify( hms<nanoseconds>(-dt),
+ WIDEN("-322:24:54.111222333") );
+
+ dt += 14000h;
+ verify( hms<nanoseconds>(dt),
+ WIDEN("14322:24:54.111222333") );
+ verify( hms<nanoseconds>(-dt),
+ WIDEN("-14322:24:54.111222333") );
+}
+
+template<typename CharT>
+void
+test_hh_mm_ss_fp()
+{
+ duration<double> dt = 22h + 24min + 54s + 111222333ns;
+ // period controls number of subseconds
+ verify( hms<nanoseconds>(dt),
+ WIDEN("22:24:54.111222333") );
+ verify( hms<microseconds>(dt),
+ WIDEN("22:24:54.111222") );
+ verify( hms<milliseconds>(dt),
+ WIDEN("22:24:54.111") );
+ verify( hms<deciseconds>(dt),
+ WIDEN("22:24:54.1") );
+ verify( hms<seconds>(dt),
+ WIDEN("22:24:54") );
+ verify( hms<nanoseconds>(-dt),
+ WIDEN("-22:24:54.111222333") );
+ verify( hms<microseconds>(-dt),
+ WIDEN("-22:24:54.111222") );
+ verify( hms<milliseconds>(-dt),
+ WIDEN("-22:24:54.111") );
+ verify( hms<deciseconds>(-dt),
+ WIDEN("-22:24:54.1") );
+ verify( hms<seconds>(-dt),
+ WIDEN("-22:24:54") );
+
+ // but hour and minutes are preserved
+ verify( hms<minutes>(dt),
+ WIDEN("22:24:54") );
+ verify( hms<hours>(dt),
+ WIDEN("22:24:54") );
+ verify( hms<minutes>(-dt),
+ WIDEN("-22:24:54") );
+ verify( hms<hours>(-dt),
+ WIDEN("-22:24:54") );
+}
+
+template<typename CharT>
+void
+test_hh_mm_ss_cust()
+{
+ const duration<char, deciseconds::period> charRep(123);
+ verify( hms<deciseconds>(charRep),
+ WIDEN("00:00:12.3") );
+ verify( hms<seconds>(charRep),
+ WIDEN("00:00:12") );
+
+ auto dt = 22h + 24min + 54s + 123ms;
+ // +plus returns long, so formatted as long
+ const duration<Rep<long>, std::milli> asLong(dt.count());
+ verify( hms<milliseconds>(asLong),
+ WIDEN("22:24:54.123") );
+ verify( hms<deciseconds>(asLong),
+ WIDEN("22:24:54.1") );
+ verify( hms<seconds>(asLong),
+ WIDEN("22:24:54") );
+ verify( hms<milliseconds>(-asLong),
+ WIDEN("-22:24:54.123") );
+ verify( hms<deciseconds>(-asLong),
+ WIDEN("-22:24:54.1") );
+ verify( hms<seconds>(-asLong),
+ WIDEN("-22:24:54") );
+
+ // +asRep returns Rep<>, so formatted as Rep<>
+ const duration<Rep<>, std::milli> asRep(dt.count());
+ verify( hms<milliseconds>(asRep),
+ WIDEN("22:24:54.123") );
+ verify( hms<deciseconds>(asRep),
+ WIDEN("22:24:54.1") );
+ verify( hms<seconds>(asLong),
+ WIDEN("22:24:54") );
+ verify( hms<milliseconds>(-asLong),
+ WIDEN("-22:24:54.123") );
+ verify( hms<deciseconds>(-asLong),
+ WIDEN("-22:24:54.1") );
+ verify( hms<seconds>(-asLong),
+ WIDEN("-22:24:54") );
+}
+
+template<typename CharT>
+void
+test_durations()
+{
+ test_duration<CharT>();
+ test_duration_fp<CharT>();
+ test_duration_cust<CharT>();
+
+ test_hh_mm_ss<CharT>();
+ test_hh_mm_ss_fp<CharT>();
+ test_hh_mm_ss_cust<CharT>();
+}
+
+template<typename CharT>
+void
+test_day()
+{
+ verify( day(0), WIDEN("00 is not a valid day") );
+ verify( day(1), WIDEN("01") );
+ verify( day(10), WIDEN("10") );
+ verify( day(32), WIDEN("32 is not a valid day") );
+ verify( day(110), WIDEN("110 is not a valid day") );
+ verify( day(255), WIDEN("255 is not a valid day") );
+}
+
+template<typename CharT>
+void
+test_month()
+{
+ verify( month(0), WIDEN("0 is not a valid month") );
+ verify( month(1), WIDEN("Jan") );
+ verify( month(10), WIDEN("Oct") );
+ verify( month(32), WIDEN("32 is not a valid month") );
+ verify( month(110), WIDEN("110 is not a valid month") );
+ verify( month(100), WIDEN("100 is not a valid month") );
+ verify( month(110), WIDEN("110 is not a valid month") );
+ verify( month(255), WIDEN("255 is not a valid month") );
+}
+
+template<typename CharT>
+void
+test_year()
+{
+ verify( year(-32768), WIDEN("-32768 is not a valid year") );
+ verify( year(-32767), WIDEN("-32767") );
+ verify( year(-67), WIDEN( "-0067") );
+ verify( year(-1), WIDEN( "-0001") );
+ verify( year(0), WIDEN( "0000") );
+ verify( year(1), WIDEN( "0001") );
+ verify( year(123), WIDEN( "0123") );
+ verify( year(2025), WIDEN( "2025") );
+ verify( year(32767), WIDEN( "32767") );
+}
+
+template<typename CharT>
+void
+test_weekday()
+{
+ verify( weekday(0), WIDEN("Sun") );
+ verify( weekday(2), WIDEN("Tue") );
+ verify( weekday(6), WIDEN("Sat") );
+ verify( weekday(7), WIDEN("Sun") );
+ verify( weekday(9), WIDEN("9 is not a valid weekday") );
+ verify( weekday(32), WIDEN("32 is not a valid weekday") );
+ verify( weekday(110), WIDEN("110 is not a valid weekday") );
+ verify( weekday(255), WIDEN("255 is not a valid weekday") );
+}
+
+template<typename CharT>
+void
+test_weekday_indexed()
+{
+ verify( weekday(0)[0], WIDEN("Sun[0 is not a valid index]") );
+ verify( weekday(2)[1], WIDEN("Tue[1]") );
+ verify( weekday(6)[5], WIDEN("Sat[5]") );
+ verify( weekday(7)[6], WIDEN("Sun[6 is not a valid index]") );
+ verify( weekday(7)[12], WIDEN("Sun[12 is not a valid index]") );
+ verify( weekday(5)[117], WIDEN("Fri[117 is not a valid index]") );
+ verify( weekday(7)[255], WIDEN("Sun[255 is not a valid index]") );
+ verify( weekday(9)[1], WIDEN("9 is not a valid weekday[1]") );
+ verify( weekday(32)[7], WIDEN("32 is not a valid weekday[7 is not a valid index]") );
+}
+
+template<typename CharT>
+void
+test_weekday_last()
+{
+ verify( weekday(0)[last], WIDEN("Sun[last]") );
+ verify( weekday(9)[last], WIDEN("9 is not a valid weekday[last]") );
+}
+
+template<typename CharT>
+void
+test_month_day()
+{
+ verify( month(1)/30, WIDEN("Jan/30") );
+ verify( month(3)/32, WIDEN("Mar/32 is not a valid day") );
+ verify( month(13)/30, WIDEN("13 is not a valid month/30") );
+ verify( month(13)/32, WIDEN("13 is not a valid month/32 is not a valid day") );
+}
+
+template<typename CharT>
+void
+test_month_day_last()
+{
+ verify( month(1)/last, WIDEN("Jan/last") );
+ verify( month(14)/last, WIDEN("14 is not a valid month/last") );
+}
+
+template<typename CharT>
+void
+test_month_weekday()
+{
+ verify( month(1)/weekday(2)[1],
+ WIDEN("Jan/Tue[1]") );
+ verify( month(3)/weekday(9)[2],
+ WIDEN("Mar/9 is not a valid weekday[2]") );
+ verify( month(13)/weekday(1)[7],
+ WIDEN("13 is not a valid month/Mon[7 is not a valid index]") );
+ verify( month(13)/weekday(10)[3],
+ WIDEN("13 is not a valid month/10 is not a valid weekday[3]") );
+ verify( month(13)/weekday(130)[0],
+ WIDEN("13 is not a valid month/130 is not a valid weekday[0 is not a valid index]") );
+}
+
+template<typename CharT>
+void
+test_month_weekday_last()
+{
+ verify( month(1)/weekday(2)[last],
+ WIDEN("Jan/Tue[last]") );
+ verify( month(3)/weekday(9)[last],
+ WIDEN("Mar/9 is not a valid weekday[last]") );
+ verify( month(13)/weekday(1)[last],
+ WIDEN("13 is not a valid month/Mon[last]") );
+ verify( month(13)/weekday(10)[last],
+ WIDEN("13 is not a valid month/10 is not a valid weekday[last]") );
+}
+
+template<typename CharT>
+void
+test_year_month()
+{
+ verify( year(2024)/month(1),
+ WIDEN("2024/Jan") );
+ verify( year(2025)/month(14),
+ WIDEN("2025/14 is not a valid month") );
+ verify( year(-32768)/month(2),
+ WIDEN("-32768 is not a valid year/Feb") );
+ verify( year(-32768)/month(0),
+ WIDEN("-32768 is not a valid year/0 is not a valid month") );
+}
+
+template<typename CharT>
+void
+test_year_month_day()
+{
+ verify( year(2024)/month(1)/30,
+ WIDEN("2024-01-30") );
+ verify( year(-100)/month(14)/1,
+ WIDEN("-0100-14-01 is not a valid date") );
+ verify( year(2025)/month(11)/100,
+ WIDEN("2025-11-100 is not a valid date") );
+ verify( year(-32768)/month(2)/10,
+ WIDEN("-32768-02-10 is not a valid date") );
+ verify( year(-32768)/month(212)/10,
+ WIDEN("-32768-212-10 is not a valid date") );
+ verify( year(-32768)/month(2)/105,
+ WIDEN("-32768-02-105 is not a valid date") );
+ verify( year(-32768)/month(14)/55,
+ WIDEN("-32768-14-55 is not a valid date") );
+}
+
+template<typename CharT>
+void
+test_year_month_last()
+{
+ verify( year(2024)/month(1)/last,
+ WIDEN("2024/Jan/last") );
+ verify( year(2025)/month(14)/last,
+ WIDEN("2025/14 is not a valid month/last") );
+ verify( year(-32768)/month(2)/last,
+ WIDEN("-32768 is not a valid year/Feb/last") );
+ verify( year(-32768)/month(0)/last,
+ WIDEN("-32768 is not a valid year/0 is not a valid month/last") );
+}
+
+template<typename CharT>
+void
+test_year_month_weekday()
+{
+ verify( year(2024)/month(1)/weekday(2)[1],
+ WIDEN("2024/Jan/Tue[1]") );
+ verify( year(-1)/month(3)/weekday(9)[2],
+ WIDEN("-0001/Mar/9 is not a valid weekday[2]") );
+ verify( year(-32768)/month(13)/weekday(1)[7],
+ WIDEN("-32768 is not a valid year/13 is not a valid month/Mon[7 is not a valid index]") );
+ verify( year(-100)/month(13)/weekday(10)[3],
+ WIDEN("-0100/13 is not a valid month/10 is not a valid weekday[3]") );
+ verify( year(-32768)/month(13)/weekday(130)[0],
+ WIDEN("-32768 is not a valid year/13 is not a valid month/130 is not a valid weekday[0 is not a valid index]") );
+}
+
+template<typename CharT>
+void
+test_year_month_weekday_last()
+{
+ verify( year(2024)/month(1)/weekday(2)[last],
+ WIDEN("2024/Jan/Tue[last]") );
+ verify( year(-1)/month(3)/weekday(9)[last],
+ WIDEN("-0001/Mar/9 is not a valid weekday[last]") );
+ verify( year(-32768)/month(13)/weekday(1)[last],
+ WIDEN("-32768 is not a valid year/13 is not a valid month/Mon[last]") );
+ verify( year(-100)/month(13)/weekday(10)[last],
+ WIDEN("-0100/13 is not a valid month/10 is not a valid weekday[last]") );
+ verify( year(-32768)/month(13)/weekday(130)[last],
+ WIDEN("-32768 is not a valid year/13 is not a valid month/130 is not a valid weekday[last]") );
+}
+
+template<typename CharT>
+void
+test_calendar()
+{
+ test_day<CharT>();
+ test_month<CharT>();
+ test_year<CharT>();
+
+ test_weekday<CharT>();
+ test_weekday_indexed<CharT>();
+ test_weekday_last<CharT>();
+
+ test_month_day<CharT>();
+ test_month_day_last<CharT>();
+ test_month_weekday<CharT>();
+ test_month_weekday_last<CharT>();
+
+ test_year_month<CharT>();
+ test_year_month_day<CharT>();
+ test_year_month_last<CharT>();
+ test_year_month_weekday<CharT>();
+ test_year_month_weekday_last<CharT>();
+}
+
+template<typename Clock, typename Dur, typename Dur2>
+constexpr auto
+wall_cast(const local_time<Dur2>& tp)
+{
+ using TP = time_point<Clock, std::common_type_t<Dur, days>>;
+ if constexpr (std::is_same_v<Clock, utc_clock> || std::is_same_v<Clock, file_clock>)
+ return clock_cast<Clock>(wall_cast<system_clock, Dur>(tp));
+ else if constexpr (std::is_same_v<Clock, tai_clock>)
+ return TP(floor<Dur>(tp.time_since_epoch()) + days(4383));
+ else if constexpr (std::is_same_v<Clock, gps_clock>)
+ return TP(floor<Dur>(tp.time_since_epoch()) - days(3657));
+ else // system_clock, local_t
+ return time_point<Clock, Dur>(floor<Dur>(tp.time_since_epoch()));
+}
+
+using decadays = duration<days::rep, std::ratio_multiply<std::deca, days::period>>;
+using kilodays = duration<days::rep, std::ratio_multiply<std::kilo, days::period>>;
+
+template<typename CharT, typename Clock>
+void
+test_time_point(bool daysAsTime)
+{
+ std::basic_string<CharT> res;
+
+ const auto lt = local_days(2024y/March/22) + 13h + 24min + 54s + 111222333ns;
+ auto strip_time = [daysAsTime](std::basic_string_view<CharT> sv)
+ { return daysAsTime ? sv : sv.substr(0, 10); };
+
+ verify( wall_cast<Clock, nanoseconds>(lt),
+ WIDEN("2024-03-22 13:24:54.111222333") );
+ verify( wall_cast<Clock, microseconds>(lt),
+ WIDEN("2024-03-22 13:24:54.111222") );
+ verify( wall_cast<Clock, milliseconds>(lt),
+ WIDEN("2024-03-22 13:24:54.111") );
+ verify( wall_cast<Clock, seconds>(lt),
+ WIDEN("2024-03-22 13:24:54") );
+ verify( wall_cast<Clock, minutes>(lt),
+ WIDEN("2024-03-22 13:24:00") );
+ verify( wall_cast<Clock, hours>(lt),
+ WIDEN("2024-03-22 13:00:00") );
+ verify( wall_cast<Clock, days>(lt),
+ strip_time(WIDEN("2024-03-22 00:00:00")) );
+ verify( wall_cast<Clock, decadays>(lt),
+ strip_time(WIDEN("2024-03-18 00:00:00")) );
+ verify( wall_cast<Clock, kilodays>(lt),
+ strip_time(WIDEN("2022-01-08 00:00:00")) );
+}
+
+template<typename CharT>
+void
+test_leap_second()
+{
+ std::basic_string<CharT> res;
+
+ const auto st = sys_days(2012y/June/30) + 23h + 59min + 59s + 111222333ns;
+ auto tp = clock_cast<utc_clock>(st);
+ tp += 1s;
+
+ verify( floor<nanoseconds>(tp),
+ WIDEN("2012-06-30 23:59:60.111222333") );
+ verify( floor<microseconds>(tp),
+ WIDEN("2012-06-30 23:59:60.111222") );
+ verify( floor<milliseconds>(tp),
+ WIDEN("2012-06-30 23:59:60.111") );
+ verify( floor<seconds>(tp),
+ WIDEN("2012-06-30 23:59:60") );
+}
+
+#if _GLIBCXX_USE_CXX11_ABI || !_GLIBCXX_USE_DUAL_ABI
+template<typename Dur, typename Dur2>
+auto
+make_zoned(const sys_time<Dur2>& st, const time_zone* tz)
+{ return zoned_time<Dur>(tz, floor<Dur>(st)); }
+
+template<typename CharT>
+void
+test_zoned_time()
+{
+ const auto st = sys_days(2024y/March/22) + 13h + 24min + 54s + 111222333ns;
+ const time_zone* tz = locate_zone("Europe/Sofia");
+ VERIFY( tz != nullptr );
+
+ verify( make_zoned<nanoseconds>(st, tz),
+ WIDEN("2024-03-22 15:24:54.111222333 EET") );
+ verify( make_zoned<microseconds>(st, tz),
+ WIDEN("2024-03-22 15:24:54.111222 EET") );
+ verify( make_zoned<milliseconds>(st, tz),
+ WIDEN("2024-03-22 15:24:54.111 EET") );
+ verify( make_zoned<seconds>(st, tz),
+ WIDEN("2024-03-22 15:24:54 EET") );
+ verify( make_zoned<minutes>(st, tz),
+ WIDEN("2024-03-22 15:24:00 EET") );
+ verify( make_zoned<hours>(st, tz),
+ WIDEN("2024-03-22 15:00:00 EET") );
+ verify( make_zoned<days>(st, tz),
+ WIDEN("2024-03-22 02:00:00 EET") );
+ verify( make_zoned<decadays>(st, tz),
+ WIDEN("2024-03-18 02:00:00 EET") );
+ verify( make_zoned<kilodays>(st, tz),
+ WIDEN("2022-01-08 02:00:00 EET") );
+}
+#endif
+
+template<typename Dur, typename Dur2>
+auto
+local_fmt(const local_time<Dur2>& lt, std::string* zone)
+{ return local_time_format(floor<Dur>(lt), zone); }
+
+template<typename CharT>
+void
+test_local_time_format()
+{
+ std::basic_string<CharT> res;
+
+ std::string abbrev = "Zone";
+ const auto lt = local_days(2024y/March/22) + 13h + 24min + 54s + 111222333ns;
+
+ res = std::format(WIDEN("{}"), local_fmt<nanoseconds>(lt, &abbrev));
+ VERIFY( res == WIDEN("2024-03-22 13:24:54.111222333 Zone") );
+ res = std::format(WIDEN("{}"), local_fmt<microseconds>(lt, &abbrev));
+ VERIFY( res == WIDEN("2024-03-22 13:24:54.111222 Zone") );
+ res = std::format(WIDEN("{}"), local_fmt<milliseconds>(lt, &abbrev));
+ VERIFY( res == WIDEN("2024-03-22 13:24:54.111 Zone") );
+ res = std::format(WIDEN("{}"), local_fmt<seconds>(lt, &abbrev));
+ VERIFY( res == WIDEN("2024-03-22 13:24:54 Zone") );
+ res = std::format(WIDEN("{}"), local_fmt<minutes>(lt, &abbrev));
+ VERIFY( res == WIDEN("2024-03-22 13:24:00 Zone") );
+ res = std::format(WIDEN("{}"), local_fmt<hours>(lt, &abbrev));
+ VERIFY( res == WIDEN("2024-03-22 13:00:00 Zone") );
+ res = std::format(WIDEN("{}"), local_fmt<days>(lt, &abbrev));
+ VERIFY( res == WIDEN("2024-03-22 00:00:00 Zone") );
+ res = std::format(WIDEN("{}"), local_fmt<decadays>(lt, &abbrev));
+ VERIFY( res == WIDEN("2024-03-18 00:00:00 Zone") );
+ res = std::format(WIDEN("{}"), local_fmt<kilodays>(lt, &abbrev));
+ VERIFY( res == WIDEN("2022-01-08 00:00:00 Zone") );
+}
+
+template<typename CharT>
+void
+test_time_points()
+{
+ test_time_point<CharT, local_t>(false);
+ test_time_point<CharT, system_clock>(false);
+ test_time_point<CharT, utc_clock>(true);
+ test_time_point<CharT, tai_clock>(true);
+ test_time_point<CharT, gps_clock>(true);
+ test_time_point<CharT, file_clock>(true);
+ test_leap_second<CharT>();
+#if _GLIBCXX_USE_CXX11_ABI || !_GLIBCXX_USE_DUAL_ABI
+ test_zoned_time<CharT>();
+#endif
+ test_local_time_format<CharT>();
+
+ test_no_empty_spec<CharT, sys_time<years>>();
+ test_no_empty_spec<CharT, sys_time<duration<float>>>();
+}
+
+#if _GLIBCXX_USE_CXX11_ABI || !_GLIBCXX_USE_DUAL_ABI
+template<typename CharT>
+void
+test_sys_info()
+{
+ const sys_info si
+ {
+ sys_days(2024y/March/22) + 2h,
+ sys_days(2025y/April/11) + 23h + 15min + 10s,
+ 2h + 13min + 4s,
+ 15min,
+ "Zone"
+ };
+ const std::basic_string_view<CharT> txt
+ = WIDEN("[2024-03-22 02:00:00,2025-04-11 23:15:10,02:13:04,15min,Zone]");
+
+ verify( si, txt );
+
+ std::basic_string<CharT> res;
+ std::basic_string_view<CharT> sv;
+
+ sv = res = std::format(WIDEN("{:65}"), si);
+ VERIFY( sv.ends_with(WIDEN(" ")) );
+ sv.remove_suffix(4);
+ VERIFY( sv == txt );
+
+ sv = res = std::format(WIDEN("{:=^67}"), si);
+ VERIFY( sv.starts_with(WIDEN("===")) );
+ VERIFY( sv.ends_with(WIDEN("===")) );
+ sv.remove_prefix(3);
+ sv.remove_suffix(3);
+ VERIFY( sv == txt );
+}
+
+template<typename CharT>
+void test_local_info()
+{
+ using String = std::basic_string<CharT>;
+ using StringView = std::basic_string_view<CharT>;
+
+ const sys_info s1
+ {
+ sys_days(2015y/September/11) + 2h,
+ sys_days(2016y/March/13) + 2h,
+ -5h,
+ 0h,
+ "EET"
+ };
+ const sys_info s2
+ {
+ sys_days(2016y/March/13) + 2h,
+ sys_days(2015y/September/15) + 2h,
+ -4h,
+ 1h,
+ "EDT"
+ };
+
+ const StringView single
+ = WIDEN("[2015-09-11 02:00:00,2016-03-13 02:00:00,-05:00:00,0min,EET]");
+ const StringView both
+ = WIDEN(" local time between "
+ "[2015-09-11 02:00:00,2016-03-13 02:00:00,-05:00:00,0min,EET]"
+ " and "
+ "[2016-03-13 02:00:00,2015-09-15 02:00:00,-04:00:00,60min,EDT]");
+
+ const local_info l1{local_info::nonexistent, s1, s2};
+ auto exp = WIDEN("[nonexistent") + String(both) + WIDEN("]");
+ verify( l1, StringView(exp) );
+
+ const local_info l2{local_info::ambiguous, s1, s2};
+ exp = WIDEN("[ambiguous") + String(both) + WIDEN("]");
+ verify( l2, StringView(exp) );
+
+ const local_info l3{local_info::unique, s1, s1};
+ exp = WIDEN("[") + String(single) + WIDEN("]");
+ verify( l3, StringView(exp) );
+
+ String res;
+ StringView sv;
+
+ sv = res = std::format(WIDEN("{:65}"), l3);
+ VERIFY( sv.ends_with(WIDEN(" ")) );
+ sv.remove_suffix(3);
+ VERIFY( sv == exp );
+
+ sv = res = std::format(WIDEN("{:=^67}"), l3);
+ VERIFY( sv.starts_with(WIDEN("==")) );
+ VERIFY( sv.ends_with(WIDEN("===")) );
+ sv.remove_prefix(2);
+ sv.remove_suffix(3);
+ VERIFY( sv == exp );
+}
+
+template<typename CharT>
+void
+test_infos()
+{
+ test_sys_info<CharT>();
+ test_local_info<CharT>();
+}
+#endif
+
+template<typename CharT>
+void
+test_all()
+{
+ test_padding<CharT>();
+ test_durations<CharT>();
+ test_calendar<CharT>();
+ test_time_points<CharT>();
+#if _GLIBCXX_USE_CXX11_ABI || !_GLIBCXX_USE_DUAL_ABI
+ test_infos<CharT>();
+#endif
+}
+
+int main()
+{
+ test_all<char>();
+
+#ifdef _GLIBCXX_USE_WCHAR_T
+ test_all<wchar_t>();
+#endif // _GLIBCXX_USE_WCHAR_T
+}
diff --git a/libstdc++-v3/testsuite/std/time/format/pr117214.cc b/libstdc++-v3/testsuite/std/time/format/pr117214.cc
index 87c703d..79109c3 100644
--- a/libstdc++-v3/testsuite/std/time/format/pr117214.cc
+++ b/libstdc++-v3/testsuite/std/time/format/pr117214.cc
@@ -7,10 +7,14 @@
#include <chrono>
#include <locale>
+#include <span>
#include <testsuite_hooks.h>
+
+template<typename ChronoType>
void
-test_c()
+test_locale_formats(const ChronoType& t,
+ std::span<const char* const> test_specifiers)
{
const char *test_locales[] = {
"aa_DJ.UTF-8",
@@ -19,15 +23,44 @@ test_c()
"az_IR.UTF-8",
"my_MM.UTF-8",
};
- std::chrono::sys_seconds t{std::chrono::seconds{1}};
+ auto format_args = std::make_format_args(t);
for (auto locale_name : test_locales)
{
- auto s = std::format(std::locale(locale_name), "{:L%c}", t);
- VERIFY( !s.empty() );
+ std::locale loc(locale_name);
+ for (auto specifier : test_specifiers)
+ {
+ auto s = std::vformat(loc, specifier, format_args);
+ VERIFY( !s.empty() );
+ }
}
}
+void
+test_locale_formats()
+{
+ using namespace std::chrono;
+
+ const char* test_specifiers[] = {
+ "{:L%x}", "{:L%Ex}",
+ "{:L%c}", "{:L%Ec}",
+ "{:L%X}", "{:L%EX}",
+ "{:L%r}",
+ };
+ auto date_time_specifiers = std::span(test_specifiers);
+ auto date_specifiers = date_time_specifiers.subspan(0, 2);
+ auto time_specifiers = date_time_specifiers.subspan(4);
+
+ auto ymd = 2020y/November/12d;
+ test_locale_formats(ymd, date_specifiers);
+
+ auto tod = 25h + 10min + 12s;
+ test_locale_formats(tod, time_specifiers);
+
+ auto tp = sys_days(ymd) + tod;
+ test_locale_formats(tp, date_time_specifiers);
+}
+
#include <stdlib.h>
#include <time.h>
@@ -93,7 +126,7 @@ test_c_local()
int main()
{
- test_c();
+ test_locale_formats();
test_c_zoned();
test_c_local();
}
diff --git a/libstdc++-v3/testsuite/std/time/format/pr120114.cc b/libstdc++-v3/testsuite/std/time/format/pr120114.cc
new file mode 100644
index 0000000..cdde468
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/time/format/pr120114.cc
@@ -0,0 +1,125 @@
+// { dg-do run { target c++23 } }
+// { dg-options "-fexec-charset=UTF-8" }
+// { dg-timeout-factor 2 }
+
+#include <algorithm>
+#include <chrono>
+#include <testsuite_hooks.h>
+
+#define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S)
+#define WIDEN(S) WIDEN_(CharT, S)
+
+template<typename CharT>
+void
+test_from_format_string()
+{
+ std::basic_string<CharT> res;
+ using namespace std::chrono_literals;
+ auto date = 2025y/std::chrono::May/05d;
+
+ res = std::format(WIDEN("{:+<13%F\U0001f921}"), date);
+ VERIFY( res == WIDEN("2025-05-05\U0001f921+") );
+
+ res = std::format(WIDEN("{:->15%F\U0001f921}"), date);
+ VERIFY( res == WIDEN("---2025-05-05\U0001f921") );
+
+ res = std::format(WIDEN("{:=^20%F\U0001f921}"), date);
+ VERIFY( res == WIDEN("====2025-05-05\U0001f921====") );
+}
+
+template<typename CharT>
+void
+test_formatted_value()
+{
+ // Custom time_put facet which returns Ideographic Telegraph Symbol
+ // for given month for Om.
+ struct TimePut : std::time_put<CharT>
+ {
+ using iter_type = std::time_put<CharT>::iter_type;
+ using char_type = std::time_put<CharT>::char_type;
+
+ iter_type
+ do_put(iter_type out, std::ios_base& io, char_type fill, const tm* t,
+ char format, char modifier) const override
+ {
+ if (format != 'm' && modifier != 'm')
+ return std::time_put<CharT>::do_put(out, io, fill, t, format, modifier);
+ std::basic_string_view<CharT> str;
+ switch (t->tm_mon)
+ {
+ case 0:
+ str = WIDEN("\u32C0");
+ break;
+ case 1:
+ str = WIDEN("\u32C1");
+ break;
+ case 2:
+ str = WIDEN("\u32C2");
+ break;
+ case 3:
+ str = WIDEN("\u32C3");
+ break;
+ case 4:
+ str = WIDEN("\u32C4");
+ break;
+ case 5:
+ str = WIDEN("\u32C5");
+ break;
+ case 6:
+ str = WIDEN("\u32C6");
+ break;
+ case 7:
+ str = WIDEN("\u32C7");
+ break;
+ case 8:
+ str = WIDEN("\u32C8");
+ break;
+ case 9:
+ str = WIDEN("\u32C9");
+ break;
+ case 10:
+ str = WIDEN("\u32CA");
+ break;
+ case 11:
+ str = WIDEN("\u32CB");
+ break;
+ };
+ return std::copy(str.begin(), str.end(), out);
+ }
+ };
+ const std::locale loc(std::locale::classic(), new TimePut);
+
+ std::basic_string<CharT> res;
+
+ res = std::format(loc, WIDEN("{:<1L%Om}"), std::chrono::January);
+ VERIFY( res == WIDEN("\u32C0") );
+
+ res = std::format(loc, WIDEN("{:>2L%Om}"), std::chrono::February);
+ VERIFY( res == WIDEN("\u32C1") );
+
+ res = std::format(loc, WIDEN("{:<3L%Om}"), std::chrono::March);
+ VERIFY( res == WIDEN("\u32C2 ") );
+
+ res = std::format(loc, WIDEN("{:^4L%Om}"), std::chrono::April);
+ VERIFY( res == WIDEN(" \u32C3 ") );
+
+ res = std::format(loc, WIDEN("{:>5L%Om}"), std::chrono::May);
+ VERIFY( res == WIDEN(" \u32C4") );
+
+ res = std::format(loc, WIDEN("{:+<6L%Om}"), std::chrono::June);
+ VERIFY( res == WIDEN("\u32C5++++") );
+
+ res = std::format(loc, WIDEN("{:=^7L%Om}"), std::chrono::July);
+ VERIFY( res == WIDEN("==\u32C6===") );
+
+ res = std::format(loc, WIDEN("{:->8L%Om}"), std::chrono::August);
+ VERIFY( res == WIDEN("------\u32C7") );
+}
+
+int main()
+{
+ test_from_format_string<char>();
+ test_from_format_string<wchar_t>();
+ test_formatted_value<char>();
+ test_formatted_value<wchar_t>();
+}
diff --git a/libstdc++-v3/testsuite/std/time/format/pr120481.cc b/libstdc++-v3/testsuite/std/time/format/pr120481.cc
new file mode 100644
index 0000000..a748acb
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/time/format/pr120481.cc
@@ -0,0 +1,324 @@
+// { dg-do run { target c++23 } }
+// { dg-options "-fexec-charset=UTF-8" }
+// { dg-timeout-factor 2 }
+
+#include <algorithm>
+#include <chrono>
+#include <testsuite_hooks.h>
+
+#define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S)
+#define WIDEN(S) WIDEN_(CharT, S)
+
+using namespace std::chrono;
+
+template<typename CharT>
+void
+test_year()
+{
+ std::basic_string<CharT> res;
+
+ res = std::format(WIDEN("{:%Y}"), year(0));
+ VERIFY( res == WIDEN("0000") );
+ res = std::format(WIDEN("{:%C}"), year(0));
+ VERIFY( res == WIDEN("00") );
+ res = std::format(WIDEN("{:%y}"), year(0));
+ VERIFY( res == WIDEN("00") );
+
+ res = std::format(WIDEN("{:%Y}"), year(5));
+ VERIFY( res == WIDEN("0005") );
+ res = std::format(WIDEN("{:%C}"), year(5));
+ VERIFY( res == WIDEN("00") );
+ res = std::format(WIDEN("{:%y}"), year(5));
+ VERIFY( res == WIDEN("05") );
+ res = std::format(WIDEN("{:%Y}"), year(-5));
+ VERIFY( res == WIDEN("-0005") );
+ res = std::format(WIDEN("{:%C}"), year(-5));
+ VERIFY( res == WIDEN("-01") );
+ res = std::format(WIDEN("{:%y}"), year(-5));
+ VERIFY( res == WIDEN("05") );
+
+ res = std::format(WIDEN("{:%Y}"), year(213));
+ VERIFY( res == WIDEN("0213") );
+ res = std::format(WIDEN("{:%C}"), year(213));
+ VERIFY( res == WIDEN("02") );
+ res = std::format(WIDEN("{:%y}"), year(213));
+ VERIFY( res == WIDEN("13") );
+ res = std::format(WIDEN("{:%Y}"), year(-213));
+ VERIFY( res == WIDEN("-0213") );
+ res = std::format(WIDEN("{:%C}"), year(-213));
+ VERIFY( res == WIDEN("-03") );
+ res = std::format(WIDEN("{:%y}"), year(-213));
+ VERIFY( res == WIDEN("13") );
+
+ res = std::format(WIDEN("{:%Y}"), year(7100));
+ VERIFY( res == WIDEN("7100") );
+ res = std::format(WIDEN("{:%C}"), year(7100));
+ VERIFY( res == WIDEN("71") );
+ res = std::format(WIDEN("{:%y}"), year(7100));
+ VERIFY( res == WIDEN("00") );
+ res = std::format(WIDEN("{:%Y}"), year(-7100));
+ VERIFY( res == WIDEN("-7100") );
+ res = std::format(WIDEN("{:%C}"), year(-7100));
+ VERIFY( res == WIDEN("-71") );
+ res = std::format(WIDEN("{:%y}"), year(-7100));
+ VERIFY( res == WIDEN("00") );
+
+ res = std::format(WIDEN("{:%Y}"), year(12101));
+ VERIFY( res == WIDEN("12101") );
+ res = std::format(WIDEN("{:%C}"), year(12101));
+ VERIFY( res == WIDEN("121") );
+ res = std::format(WIDEN("{:%y}"), year(12101));
+ VERIFY( res == WIDEN("01") );
+ res = std::format(WIDEN("{:%Y}"), year(-12101));
+ VERIFY( res == WIDEN("-12101") );
+ res = std::format(WIDEN("{:%C}"), year(-12101));
+ VERIFY( res == WIDEN("-122") );
+ res = std::format(WIDEN("{:%y}"), year(-12101));
+ VERIFY( res == WIDEN("01") );
+}
+
+template<typename CharT>
+void
+test_month()
+{
+ std::basic_string<CharT> res;
+
+ res = std::format(WIDEN("{:%m}"), month(5));
+ VERIFY( res == WIDEN("05") );
+ res = std::format(WIDEN("{:%m}"), month(50));
+ VERIFY( res == WIDEN("50") );
+ res = std::format(WIDEN("{:%m}"), month(127));
+ VERIFY( res == WIDEN("127") );
+ res = std::format(WIDEN("{:%m}"), month(254));
+ VERIFY( res == WIDEN("254") );
+}
+
+template<typename CharT>
+void
+test_day()
+{
+ std::basic_string<CharT> res;
+
+ res = std::format(WIDEN("{:%d}"), day(3));
+ VERIFY( res == WIDEN("03") );
+ res = std::format(WIDEN("{:%d}"), day(22));
+ VERIFY( res == WIDEN("22") );
+ res = std::format(WIDEN("{:%d}"), day(100));
+ VERIFY( res == WIDEN("100") );
+ res = std::format(WIDEN("{:%d}"), day(207));
+ VERIFY( res == WIDEN("207") );
+
+ res = std::format(WIDEN("{:%e}"), day(5));
+ VERIFY( res == WIDEN(" 5") );
+ res = std::format(WIDEN("{:%e}"), day(99));
+ VERIFY( res == WIDEN("99") );
+ res = std::format(WIDEN("{:%e}"), day(183));
+ VERIFY( res == WIDEN("183") );
+ res = std::format(WIDEN("{:%e}"), day(214));
+ VERIFY( res == WIDEN("214") );
+}
+
+template<typename CharT>
+void
+test_date()
+{
+ std::basic_string<CharT> res;
+
+ res = std::format(WIDEN("{:%F}"), year(-22)/month(10)/day(20));
+ VERIFY( res == WIDEN("-0022-10-20") );
+ res = std::format(WIDEN("{:%D}"), year(-22)/month(10)/day(20));
+ VERIFY( res == WIDEN("10/20/22") );
+
+ res = std::format(WIDEN("{:%F}"), year(-2020)/month(123)/day(44));
+ VERIFY( res == WIDEN("-2020-123-44") );
+ res = std::format(WIDEN("{:%D}"), year(-2020)/month(123)/day(44));
+ VERIFY( res == WIDEN("123/44/20") );
+
+ res = std::format(WIDEN("{:%F}"), year(-23404)/month(99)/day(223));
+ VERIFY( res == WIDEN("-23404-99-223") );
+ res = std::format(WIDEN("{:%D}"), year(-23404)/month(99)/day(223));
+ VERIFY( res == WIDEN("99/223/04") );
+
+ res = std::format(WIDEN("{:%F}"), year(10000)/month(220)/day(100));
+ VERIFY( res == WIDEN("10000-220-100") );
+ res = std::format(WIDEN("{:%D}"), year(10000)/month(220)/day(100));
+ VERIFY( res == WIDEN("220/100/00") );
+}
+
+template<typename CharT>
+void
+test_weekday()
+{
+ std::basic_string<CharT> res;
+
+ res = std::format(WIDEN("{:%w}"), weekday(0));
+ VERIFY( res == WIDEN("0") );
+ res = std::format(WIDEN("{:%u}"), weekday(0));
+ VERIFY( res == WIDEN("7") );
+
+ res = std::format(WIDEN("{:%w}"), weekday(7));
+ VERIFY( res == WIDEN("0") );
+ res = std::format(WIDEN("{:%u}"), weekday(7));
+ VERIFY( res == WIDEN("7") );
+
+ res = std::format(WIDEN("{:%w}"), weekday(8));
+ VERIFY( res == WIDEN("8") );
+ res = std::format(WIDEN("{:%u}"), weekday(8));
+ VERIFY( res == WIDEN("8") );
+
+ res = std::format(WIDEN("{:%w}"), weekday(10));
+ VERIFY( res == WIDEN("10") );
+ res = std::format(WIDEN("{:%u}"), weekday(10));
+ VERIFY( res == WIDEN("10") );
+
+ res = std::format(WIDEN("{:%w}"), weekday(76));
+ VERIFY( res == WIDEN("76") );
+ res = std::format(WIDEN("{:%u}"), weekday(76));
+ VERIFY( res == WIDEN("76") );
+
+ res = std::format(WIDEN("{:%w}"), weekday(100));
+ VERIFY( res == WIDEN("100") );
+ res = std::format(WIDEN("{:%u}"), weekday(100));
+ VERIFY( res == WIDEN("100") );
+
+ res = std::format(WIDEN("{:%w}"), weekday(202));
+ VERIFY( res == WIDEN("202") );
+ res = std::format(WIDEN("{:%u}"), weekday(202));
+ VERIFY( res == WIDEN("202") );
+}
+
+template<typename CharT>
+void
+test_hour()
+{
+ std::basic_string<CharT> res;
+
+ res = std::format(WIDEN("{:%H}"), 0h + 5min + 6s);
+ VERIFY( res == WIDEN("00") );
+ res = std::format(WIDEN("{:%R}"), 0h + 5min + 6s);
+ VERIFY( res == WIDEN("00:05") );
+ res = std::format(WIDEN("{:%T}"), 0h + 5min + 6s);
+ VERIFY( res == WIDEN("00:05:06") );
+ res = std::format(WIDEN("{:%I}"), 0h + 5min + 6s);
+ VERIFY( res == WIDEN("12") );
+ res = std::format(WIDEN("{:%p}"), 0h + 5min + 6s);
+ VERIFY( res == WIDEN("AM") );
+
+ res = std::format(WIDEN("{:%H}"), 7h + 15min + 6s);
+ VERIFY( res == WIDEN("07") );
+ res = std::format(WIDEN("{:%R}"), 7h + 15min + 6s);
+ VERIFY( res == WIDEN("07:15") );
+ res = std::format(WIDEN("{:%T}"), 7h + 15min + 6s);
+ VERIFY( res == WIDEN("07:15:06") );
+ res = std::format(WIDEN("{:%I}"), 7h + 15min + 6s);
+ VERIFY( res == WIDEN("07") );
+ res = std::format(WIDEN("{:%p}"), 7h + 15min + 6s);
+ VERIFY( res == WIDEN("AM") );
+
+ res = std::format(WIDEN("{:%H}"), 15h + 55min + 26s);
+ VERIFY( res == WIDEN("15") );
+ res = std::format(WIDEN("{:%R}"), 15h + 55min + 26s);
+ VERIFY( res == WIDEN("15:55") );
+ res = std::format(WIDEN("{:%T}"), 15h + 55min + 26s);
+ VERIFY( res == WIDEN("15:55:26") );
+ res = std::format(WIDEN("{:%I}"), 15h + 55min + 26s);
+ VERIFY( res == WIDEN("03") );
+ res = std::format(WIDEN("{:%p}"), 15h + 55min + 26s);
+ VERIFY( res == WIDEN("PM") );
+
+ res = std::format(WIDEN("{:%H}"), 50h + 33min + 37s);
+ VERIFY( res == WIDEN("50") );
+ res = std::format(WIDEN("{:%R}"), 50h + 33min + 37s);
+ VERIFY( res == WIDEN("50:33") );
+ res = std::format(WIDEN("{:%T}"), 50h + 33min + 37s);
+ VERIFY( res == WIDEN("50:33:37") );
+ res = std::format(WIDEN("{:%I}"), 50h + 33min + 37s);
+ VERIFY( res == WIDEN("02") );
+ res = std::format(WIDEN("{:%p}"), 50h + 33min + 37s);
+ VERIFY( res == WIDEN("AM") );
+
+ res = std::format(WIDEN("{:%H}"), 100h + 21min + 48s);
+ VERIFY( res == WIDEN("100") );
+ res = std::format(WIDEN("{:%R}"), 100h + 21min + 48s);
+ VERIFY( res == WIDEN("100:21") );
+ res = std::format(WIDEN("{:%T}"), 100h + 21min + 48s);
+ VERIFY( res == WIDEN("100:21:48") );
+ res = std::format(WIDEN("{:%I}"), 100h + 21min + 48s);
+ VERIFY( res == WIDEN("04") );
+ res = std::format(WIDEN("{:%p}"), 100h + 21min + 48s);
+ VERIFY( res == WIDEN("AM") );
+
+ res = std::format(WIDEN("{:%H}"), 228h + 45min + 33s);
+ VERIFY( res == WIDEN("228") );
+ res = std::format(WIDEN("{:%R}"), 228h + 45min + 33s);
+ VERIFY( res == WIDEN("228:45") );
+ res = std::format(WIDEN("{:%T}"), 228h + 45min + 33s);
+ VERIFY( res == WIDEN("228:45:33") );
+ res = std::format(WIDEN("{:%I}"), 228h + 4min + 33s);
+ VERIFY( res == WIDEN("12") );
+ res = std::format(WIDEN("{:%p}"), 228h + 4min + 33s);
+ VERIFY( res == WIDEN("PM") );
+
+ res = std::format(WIDEN("{:%H}"), 1024h + 3min);
+ VERIFY( res == WIDEN("1024") );
+ res = std::format(WIDEN("{:%R}"), 1024h + 3min);
+ VERIFY( res == WIDEN("1024:03") );
+ res = std::format(WIDEN("{:%T}"), 1024h + 3min);
+ VERIFY( res == WIDEN("1024:03:00") );
+ res = std::format(WIDEN("{:%I}"), 1024h + 3min);
+ VERIFY( res == WIDEN("04") );
+ res = std::format(WIDEN("{:%p}"), 1024h + 3min);
+ VERIFY( res == WIDEN("PM") );
+
+ res = std::format(WIDEN("{:%H}"), 2039h);
+ VERIFY( res == WIDEN("2039") );
+ res = std::format(WIDEN("{:%R}"), 2039h);
+ VERIFY( res == WIDEN("2039:00") );
+ res = std::format(WIDEN("{:%T}"), 2039h);
+ VERIFY( res == WIDEN("2039:00:00") );
+ res = std::format(WIDEN("{:%I}"), 2039h);
+ VERIFY( res == WIDEN("11") );
+ res = std::format(WIDEN("{:%p}"), 2039h);
+ VERIFY( res == WIDEN("PM") );
+
+ res = std::format(WIDEN("{:%H}"), 22111h + 59min + 59s);
+ VERIFY( res == WIDEN("22111") );
+ res = std::format(WIDEN("{:%R}"), 22111h + 59min + 59s);
+ VERIFY( res == WIDEN("22111:59") );
+ res = std::format(WIDEN("{:%T}"), 22111h + 59min + 59s);
+ VERIFY( res == WIDEN("22111:59:59") );
+ res = std::format(WIDEN("{:%I}"), 22111h + 59min + 59s);
+ VERIFY( res == WIDEN("07") );
+ res = std::format(WIDEN("{:%p}"), 22111h + 59min + 59s);
+ VERIFY( res == WIDEN("AM") );
+
+ res = std::format(WIDEN("{:%H}"), -22111h - 59min - 59s);
+ VERIFY( res == WIDEN("-22111") );
+ res = std::format(WIDEN("{:%R}"), -22111h - 59min - 59s);
+ VERIFY( res == WIDEN("-22111:59") );
+ res = std::format(WIDEN("{:%T}"), -22111h - 59min - 59s);
+ VERIFY( res == WIDEN("-22111:59:59") );
+ res = std::format(WIDEN("{:%I}"), -22111h - 59min - 59s);
+ VERIFY( res == WIDEN("-07") );
+ res = std::format(WIDEN("{:%p}"), -22111h - 59min - 59s);
+ VERIFY( res == WIDEN("AM") );
+}
+
+int main()
+{
+ test_year<char>();
+ test_month<char>();
+ test_day<char>();
+ test_date<char>();
+ test_weekday<char>();
+ test_hour<char>();
+
+#ifdef _GLIBCXX_USE_WCHAR_T
+ test_year<wchar_t>();
+ test_month<wchar_t>();
+ test_day<wchar_t>();
+ test_date<wchar_t>();
+ test_weekday<wchar_t>();
+ test_hour<wchar_t>();
+#endif // _GLIBCXX_USE_WCHAR_T
+}
diff --git a/libstdc++-v3/testsuite/std/time/format/precision.cc b/libstdc++-v3/testsuite/std/time/format/precision.cc
new file mode 100644
index 0000000..aa26615
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/time/format/precision.cc
@@ -0,0 +1,201 @@
+// { dg-do run { target c++20 } }
+
+#include <chrono>
+#include <ranges>
+#include <testsuite_hooks.h>
+
+using namespace std::chrono;
+
+#define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S)
+#define WIDEN(S) WIDEN_(CharT, S)
+
+template<typename CharT>
+void
+test_empty()
+{
+ std::basic_string<CharT> res;
+
+ const duration<double> d(33.111222);
+ res = std::format(WIDEN("{:}"), d);
+ VERIFY( res == WIDEN("33.1112s") );
+ res = std::format(WIDEN("{:.0}"), d);
+ VERIFY( res == WIDEN("33.1112s") );
+ res = std::format(WIDEN("{:.3}"), d);
+ VERIFY( res == WIDEN("33.1112s") );
+ res = std::format(WIDEN("{:.6}"), d);
+ VERIFY( res == WIDEN("33.1112s") );
+ res = std::format(WIDEN("{:.9}"), d);
+ VERIFY( res == WIDEN("33.1112s") );
+
+ // Uses ostream operator<<
+ const duration<double, std::nano> nd = d;
+ res = std::format(WIDEN("{:}"), nd);
+ VERIFY( res == WIDEN("3.31112e+10ns") );
+ res = std::format(WIDEN("{:.0}"), nd);
+ VERIFY( res == WIDEN("3.31112e+10ns") );
+ res = std::format(WIDEN("{:.3}"), nd);
+ VERIFY( res == WIDEN("3.31112e+10ns") );
+ res = std::format(WIDEN("{:.6}"), nd);
+ VERIFY( res == WIDEN("3.31112e+10ns") );
+ res = std::format(WIDEN("{:.9}"), nd);
+ VERIFY( res == WIDEN("3.31112e+10ns") );
+}
+
+template<typename CharT>
+void
+test_Q()
+{
+ std::basic_string<CharT> res;
+
+ const duration<double> d(7.111222);
+ res = std::format(WIDEN("{:%Q}"), d);
+ VERIFY( res == WIDEN("7.111222") );
+ res = std::format(WIDEN("{:.0%Q}"), d);
+ VERIFY( res == WIDEN("7.111222") );
+ res = std::format(WIDEN("{:.3%Q}"), d);
+ VERIFY( res == WIDEN("7.111222") );
+ res = std::format(WIDEN("{:.6%Q}"), d);
+ VERIFY( res == WIDEN("7.111222") );
+ res = std::format(WIDEN("{:.9%Q}"), d);
+ VERIFY( res == WIDEN("7.111222") );
+
+ duration<double, std::milli> md = d;
+ res = std::format(WIDEN("{:%Q}"), md);
+ VERIFY( res == WIDEN("7111.222") );
+ res = std::format(WIDEN("{:.0%Q}"), md);
+ VERIFY( res == WIDEN("7111.222") );
+ res = std::format(WIDEN("{:.3%Q}"), md);
+ VERIFY( res == WIDEN("7111.222") );
+ res = std::format(WIDEN("{:.6%Q}"), md);
+ VERIFY( res == WIDEN("7111.222") );
+ res = std::format(WIDEN("{:.9%Q}"), md);
+ VERIFY( res == WIDEN("7111.222") );
+
+ const duration<double, std::nano> nd = d;
+ res = std::format(WIDEN("{:%Q}"), nd);
+ VERIFY( res == WIDEN("7111222000") );
+ res = std::format(WIDEN("{:.0%Q}"), nd);
+ VERIFY( res == WIDEN("7111222000") );
+ res = std::format(WIDEN("{:.3%Q}"), nd);
+ VERIFY( res == WIDEN("7111222000") );
+ res = std::format(WIDEN("{:.6%Q}"), nd);
+ VERIFY( res == WIDEN("7111222000") );
+ res = std::format(WIDEN("{:.9%Q}"), nd);
+ VERIFY( res == WIDEN("7111222000") );
+}
+
+template<typename CharT>
+void
+test_S_fp()
+{
+ std::basic_string<CharT> res;
+
+ // Precision is ignored, but period affects output
+ duration<double> d(5.111222);
+ res = std::format(WIDEN("{:%S}"), d);
+ VERIFY( res == WIDEN("05") );
+ res = std::format(WIDEN("{:.0%S}"), d);
+ VERIFY( res == WIDEN("05") );
+ res = std::format(WIDEN("{:.3%S}"), d);
+ VERIFY( res == WIDEN("05") );
+ res = std::format(WIDEN("{:.6%S}"), d);
+ VERIFY( res == WIDEN("05") );
+ res = std::format(WIDEN("{:.9%S}"), d);
+ VERIFY( res == WIDEN("05") );
+
+ duration<double, std::milli> md = d;
+ res = std::format(WIDEN("{:%S}"), md);
+ VERIFY( res == WIDEN("05.111") );
+ res = std::format(WIDEN("{:.0%S}"), md);
+ VERIFY( res == WIDEN("05.111") );
+ res = std::format(WIDEN("{:.3%S}"), md);
+ VERIFY( res == WIDEN("05.111") );
+ res = std::format(WIDEN("{:.6%S}"), md);
+ VERIFY( res == WIDEN("05.111") );
+ res = std::format(WIDEN("{:.9%S}"), md);
+ VERIFY( res == WIDEN("05.111") );
+
+ duration<double, std::micro> ud = d;
+ res = std::format(WIDEN("{:%S}"), ud);
+ VERIFY( res == WIDEN("05.111222") );
+ res = std::format(WIDEN("{:.0%S}"), ud);
+ VERIFY( res == WIDEN("05.111222") );
+ res = std::format(WIDEN("{:.3%S}"), ud);
+ VERIFY( res == WIDEN("05.111222") );
+ res = std::format(WIDEN("{:.6%S}"), ud);
+ VERIFY( res == WIDEN("05.111222") );
+ res = std::format(WIDEN("{:.9%S}"), ud);
+ VERIFY( res == WIDEN("05.111222") );
+
+ duration<double, std::nano> nd = d;
+ res = std::format(WIDEN("{:%S}"), nd);
+ VERIFY( res == WIDEN("05.111222000") );
+ res = std::format(WIDEN("{:.0%S}"), nd);
+ VERIFY( res == WIDEN("05.111222000") );
+ res = std::format(WIDEN("{:.3%S}"), nd);
+ VERIFY( res == WIDEN("05.111222000") );
+ res = std::format(WIDEN("{:.6%S}"), nd);
+ VERIFY( res == WIDEN("05.111222000") );
+ res = std::format(WIDEN("{:.9%S}"), nd);
+ VERIFY( res == WIDEN("05.111222000") );
+
+ duration<double, std::pico> pd = d;
+ res = std::format(WIDEN("{:%S}"), pd);
+ VERIFY( res == WIDEN("05.111222000000") );
+ res = std::format(WIDEN("{:.0%S}"), pd);
+ VERIFY( res == WIDEN("05.111222000000") );
+ res = std::format(WIDEN("{:.3%S}"), pd);
+ VERIFY( res == WIDEN("05.111222000000") );
+ res = std::format(WIDEN("{:.6%S}"), pd);
+ VERIFY( res == WIDEN("05.111222000000") );
+ res = std::format(WIDEN("{:.9%S}"), pd);
+ VERIFY( res == WIDEN("05.111222000000") );
+}
+
+template<typename CharT>
+void
+test_S_int()
+{
+ std::basic_string<CharT> res;
+ const nanoseconds src(7'000'012'345);
+
+ auto d = floor<seconds>(src);
+ res = std::format(WIDEN("{:%S}"), d);
+ VERIFY( res == WIDEN("07") );
+
+ auto md = floor<milliseconds>(src);
+ res = std::format(WIDEN("{:%S}"), md);
+ VERIFY( res == WIDEN("07.000") );
+
+ auto ud = floor<microseconds>(src);
+ res = std::format(WIDEN("{:%S}"), ud);
+ VERIFY( res == WIDEN("07.000012") );
+
+ auto nd = floor<nanoseconds>(src);
+ res = std::format(WIDEN("{:%S}"), nd);
+ VERIFY( res == WIDEN("07.000012345") );
+
+ using picoseconds = duration<unsigned long long, std::pico>;
+ auto pd = floor<picoseconds>(src);
+ res = std::format(WIDEN("{:%S}"), pd);
+ VERIFY( res == WIDEN("07.000012345000") );
+}
+
+template<typename CharT>
+void
+test_all()
+{
+ test_empty<CharT>();
+ test_Q<CharT>();
+ test_S_int<CharT>();
+ test_S_fp<CharT>();
+}
+
+int main()
+{
+ test_all<char>();
+
+#ifdef _GLIBCXX_USE_WCHAR_T
+ test_all<wchar_t>();
+#endif // _GLIBCXX_USE_WCHAR_T
+}
diff --git a/libstdc++-v3/testsuite/std/time/format/whitespace.cc b/libstdc++-v3/testsuite/std/time/format/whitespace.cc
new file mode 100644
index 0000000..debda08
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/time/format/whitespace.cc
@@ -0,0 +1,56 @@
+// { dg-do run { target c++20 } }
+
+#include <chrono>
+#include <testsuite_hooks.h>
+
+using namespace std::chrono;
+
+#define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S)
+#define WIDEN(S) WIDEN_(_CharT, S)
+
+template<typename _CharT, typename ChronoType>
+void
+test(const ChronoType& ct)
+{
+ std::basic_string<_CharT> res;
+
+ res = std::format(WIDEN("{:%% %t %n more text}"), ct);
+ VERIFY( res == WIDEN("% \t \n more text") );
+
+ res = std::format(WIDEN("{:7%% %t %n}"), ct);
+ VERIFY( res == WIDEN("% \t \n ") );
+
+ res = std::format(WIDEN("{:>6%% %t %n}"), ct);
+ VERIFY( res == WIDEN(" % \t \n") );
+
+ res = std::format(WIDEN("{:+>7%% %t %n}"), ct);
+ VERIFY( res == WIDEN("++% \t \n") );
+
+ res = std::format(WIDEN("{:=^7%% %t %n}"), ct);
+ VERIFY( res == WIDEN("=% \t \n=") );
+}
+
+template<typename CharT>
+void
+test_all()
+{
+ test<CharT>(20s);
+ test<CharT>(10d);
+ test<CharT>(Monday);
+ test<CharT>(2020y/January/8);
+ test<CharT>(local_days(2020y/January/8));
+ test<CharT>(sys_days(2020y/January/8) + 13h + 10min + 5s);
+#if _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI
+ test<CharT>(sys_info());
+ test<CharT>(local_info());
+#endif
+}
+
+int main()
+{
+ test_all<char>();
+
+#ifdef _GLIBCXX_USE_WCHAR_T
+ test_all<wchar_t>();
+#endif // _GLIBCXX_USE_WCHAR_T
+}
diff --git a/libstdc++-v3/testsuite/tr1/2_general_utilities/shared_ptr/cons/43820_neg.cc b/libstdc++-v3/testsuite/tr1/2_general_utilities/shared_ptr/cons/43820_neg.cc
index 7b5ede4..03fad14 100644
--- a/libstdc++-v3/testsuite/tr1/2_general_utilities/shared_ptr/cons/43820_neg.cc
+++ b/libstdc++-v3/testsuite/tr1/2_general_utilities/shared_ptr/cons/43820_neg.cc
@@ -39,9 +39,6 @@ void test01()
// { dg-error "incomplete" "" { target *-*-* } 600 }
}
-// { dg-error "-Wdelete-incomplete" "" { target c++26 } 283 }
-// { dg-error "-Wdelete-incomplete" "" { target c++26 } 305 }
-
// Ignore additional diagnostic given with -Wsystem-headers:
// { dg-prune-output "has incomplete type" }
// { dg-prune-output "possible problem detected" }
diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/01_assoc_laguerre/check_value.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/01_assoc_laguerre/check_value.cc
index 1ae8371..77e7648 100644
--- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/01_assoc_laguerre/check_value.cc
+++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/01_assoc_laguerre/check_value.cc
@@ -2217,7 +2217,6 @@ template<typename Ret, unsigned int Num>
void
test(const testcase_assoc_laguerre<Ret> (&data)[Num], Ret toler)
{
- bool test __attribute__((unused)) = true;
const Ret eps = std::numeric_limits<Ret>::epsilon();
Ret max_abs_diff = -Ret(1);
Ret max_abs_frac = -Ret(1);
diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/02_assoc_legendre/check_value.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/02_assoc_legendre/check_value.cc
index 023f09d..a30700b 100644
--- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/02_assoc_legendre/check_value.cc
+++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/02_assoc_legendre/check_value.cc
@@ -1985,7 +1985,6 @@ template<typename Ret, unsigned int Num>
void
test(const testcase_assoc_legendre<Ret> (&data)[Num], Ret toler)
{
- bool test __attribute__((unused)) = true;
const Ret eps = std::numeric_limits<Ret>::epsilon();
Ret max_abs_diff = -Ret(1);
Ret max_abs_frac = -Ret(1);
diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/02_assoc_legendre/pr86655.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/02_assoc_legendre/pr86655.cc
index 7f7e3a4..ec99b60 100644
--- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/02_assoc_legendre/pr86655.cc
+++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/02_assoc_legendre/pr86655.cc
@@ -36,7 +36,6 @@ template<typename _Tp>
void
test_m_gt_l()
{
- bool test __attribute__((unused)) = true;
unsigned int larr[4] = {0u, 1u, 2u, 5u};
for (unsigned int l = 0; l < 4; ++l)
for (unsigned int m = larr[l] + 1u; m <= larr[l] + 2u; ++m)
diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/03_beta/check_value.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/03_beta/check_value.cc
index f61438d..2dcdcbc 100644
--- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/03_beta/check_value.cc
+++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/03_beta/check_value.cc
@@ -261,7 +261,6 @@ template<typename Ret, unsigned int Num>
void
test(const testcase_beta<Ret> (&data)[Num], Ret toler)
{
- bool test __attribute__((unused)) = true;
const Ret eps = std::numeric_limits<Ret>::epsilon();
Ret max_abs_diff = -Ret(1);
Ret max_abs_frac = -Ret(1);
diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/04_comp_ellint_1/check_value.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/04_comp_ellint_1/check_value.cc
index 76240db..7faffe8 100644
--- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/04_comp_ellint_1/check_value.cc
+++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/04_comp_ellint_1/check_value.cc
@@ -73,7 +73,6 @@ template<typename Ret, unsigned int Num>
void
test(const testcase_comp_ellint_1<Ret> (&data)[Num], Ret toler)
{
- bool test __attribute__((unused)) = true;
const Ret eps = std::numeric_limits<Ret>::epsilon();
Ret max_abs_diff = -Ret(1);
Ret max_abs_frac = -Ret(1);
diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/05_comp_ellint_2/check_value.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/05_comp_ellint_2/check_value.cc
index b46a140..60adcb1 100644
--- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/05_comp_ellint_2/check_value.cc
+++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/05_comp_ellint_2/check_value.cc
@@ -73,7 +73,6 @@ template<typename Ret, unsigned int Num>
void
test(const testcase_comp_ellint_2<Ret> (&data)[Num], Ret toler)
{
- bool test __attribute__((unused)) = true;
const Ret eps = std::numeric_limits<Ret>::epsilon();
Ret max_abs_diff = -Ret(1);
Ret max_abs_frac = -Ret(1);
diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/06_comp_ellint_3/check_value.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/06_comp_ellint_3/check_value.cc
index aba5284..34f5956 100644
--- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/06_comp_ellint_3/check_value.cc
+++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/06_comp_ellint_3/check_value.cc
@@ -459,7 +459,6 @@ template<typename Ret, unsigned int Num>
void
test(const testcase_comp_ellint_3<Ret> (&data)[Num], Ret toler)
{
- bool test __attribute__((unused)) = true;
const Ret eps = std::numeric_limits<Ret>::epsilon();
Ret max_abs_diff = -Ret(1);
Ret max_abs_frac = -Ret(1);
diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/07_conf_hyperg/check_value.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/07_conf_hyperg/check_value.cc
index 5b10ea4..1cd2733 100644
--- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/07_conf_hyperg/check_value.cc
+++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/07_conf_hyperg/check_value.cc
@@ -3819,7 +3819,6 @@ template<typename Ret, unsigned int Num>
void
test(const testcase_conf_hyperg<Ret> (&data)[Num], Ret toler)
{
- bool test __attribute__((unused)) = true;
const Ret eps = std::numeric_limits<Ret>::epsilon();
Ret max_abs_diff = -Ret(1);
Ret max_abs_frac = -Ret(1);
diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/08_cyl_bessel_i/check_value.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/08_cyl_bessel_i/check_value.cc
index cb4b3960..02df6ba 100644
--- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/08_cyl_bessel_i/check_value.cc
+++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/08_cyl_bessel_i/check_value.cc
@@ -702,7 +702,6 @@ template<typename Ret, unsigned int Num>
void
test(const testcase_cyl_bessel_i<Ret> (&data)[Num], Ret toler)
{
- bool test __attribute__((unused)) = true;
const Ret eps = std::numeric_limits<Ret>::epsilon();
Ret max_abs_diff = -Ret(1);
Ret max_abs_frac = -Ret(1);
diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/09_cyl_bessel_j/check_value.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/09_cyl_bessel_j/check_value.cc
index 689880d..f3b7fa6 100644
--- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/09_cyl_bessel_j/check_value.cc
+++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/09_cyl_bessel_j/check_value.cc
@@ -735,7 +735,6 @@ template<typename Ret, unsigned int Num>
void
test(const testcase_cyl_bessel_j<Ret> (&data)[Num], Ret toler)
{
- bool test __attribute__((unused)) = true;
const Ret eps = std::numeric_limits<Ret>::epsilon();
Ret max_abs_diff = -Ret(1);
Ret max_abs_frac = -Ret(1);
diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/10_cyl_bessel_k/check_value.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/10_cyl_bessel_k/check_value.cc
index a408c3f..10b8092 100644
--- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/10_cyl_bessel_k/check_value.cc
+++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/10_cyl_bessel_k/check_value.cc
@@ -746,7 +746,6 @@ template<typename Ret, unsigned int Num>
void
test(const testcase_cyl_bessel_k<Ret> (&data)[Num], Ret toler)
{
- bool test __attribute__((unused)) = true;
const Ret eps = std::numeric_limits<Ret>::epsilon();
Ret max_abs_diff = -Ret(1);
Ret max_abs_frac = -Ret(1);
diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/11_cyl_neumann/check_value.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/11_cyl_neumann/check_value.cc
index 868d278..c365bb5 100644
--- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/11_cyl_neumann/check_value.cc
+++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/11_cyl_neumann/check_value.cc
@@ -779,7 +779,6 @@ template<typename Ret, unsigned int Num>
void
test(const testcase_cyl_neumann<Ret> (&data)[Num], Ret toler)
{
- bool test __attribute__((unused)) = true;
const Ret eps = std::numeric_limits<Ret>::epsilon();
Ret max_abs_diff = -Ret(1);
Ret max_abs_frac = -Ret(1);
diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/12_ellint_1/check_value.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/12_ellint_1/check_value.cc
index 2ca367f..acb217d 100644
--- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/12_ellint_1/check_value.cc
+++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/12_ellint_1/check_value.cc
@@ -459,7 +459,6 @@ template<typename Ret, unsigned int Num>
void
test(const testcase_ellint_1<Ret> (&data)[Num], Ret toler)
{
- bool test __attribute__((unused)) = true;
const Ret eps = std::numeric_limits<Ret>::epsilon();
Ret max_abs_diff = -Ret(1);
Ret max_abs_frac = -Ret(1);
diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/13_ellint_2/check_value.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/13_ellint_2/check_value.cc
index d9e0f7f..7bb33b5 100644
--- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/13_ellint_2/check_value.cc
+++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/13_ellint_2/check_value.cc
@@ -459,7 +459,6 @@ template<typename Ret, unsigned int Num>
void
test(const testcase_ellint_2<Ret> (&data)[Num], Ret toler)
{
- bool test __attribute__((unused)) = true;
const Ret eps = std::numeric_limits<Ret>::epsilon();
Ret max_abs_diff = -Ret(1);
Ret max_abs_frac = -Ret(1);
diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/14_ellint_3/check_value.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/14_ellint_3/check_value.cc
index 2da68ab..df624a0 100644
--- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/14_ellint_3/check_value.cc
+++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/14_ellint_3/check_value.cc
@@ -6121,7 +6121,6 @@ template<typename Ret, unsigned int Num>
void
test(const testcase_ellint_3<Ret> (&data)[Num], Ret toler)
{
- bool test __attribute__((unused)) = true;
const Ret eps = std::numeric_limits<Ret>::epsilon();
Ret max_abs_diff = -Ret(1);
Ret max_abs_frac = -Ret(1);
diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/15_expint/check_value_neg.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/15_expint/check_value_neg.cc
index 33d95c9..64f7685 100644
--- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/15_expint/check_value_neg.cc
+++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/15_expint/check_value_neg.cc
@@ -168,7 +168,6 @@ template<typename Ret, unsigned int Num>
void
test(const testcase_expint<Ret> (&data)[Num], Ret toler)
{
- bool test __attribute__((unused)) = true;
const Ret eps = std::numeric_limits<Ret>::epsilon();
Ret max_abs_diff = -Ret(1);
Ret max_abs_frac = -Ret(1);
diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/16_hermite/check_value.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/16_hermite/check_value.cc
index 8afbcdd..0676f62 100644
--- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/16_hermite/check_value.cc
+++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/16_hermite/check_value.cc
@@ -1904,7 +1904,6 @@ template<typename Ret, unsigned int Num>
void
test(const testcase_hermite<Ret> (&data)[Num], Ret toler)
{
- bool test __attribute__((unused)) = true;
const Ret eps = std::numeric_limits<Ret>::epsilon();
Ret max_abs_diff = -Ret(1);
Ret max_abs_frac = -Ret(1);
diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/17_hyperg/check_value.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/17_hyperg/check_value.cc
index c77dc3d..b83994e 100644
--- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/17_hyperg/check_value.cc
+++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/17_hyperg/check_value.cc
@@ -12292,7 +12292,6 @@ template<typename Ret, unsigned int Num>
void
test(const testcase_hyperg<Ret> (&data)[Num], Ret toler)
{
- bool test __attribute__((unused)) = true;
const Ret eps = std::numeric_limits<Ret>::epsilon();
Ret max_abs_diff = -Ret(1);
Ret max_abs_frac = -Ret(1);
diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/18_laguerre/check_value.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/18_laguerre/check_value.cc
index 60d6af0..2fee8e4 100644
--- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/18_laguerre/check_value.cc
+++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/18_laguerre/check_value.cc
@@ -305,7 +305,6 @@ template<typename Ret, unsigned int Num>
void
test(const testcase_laguerre<Ret> (&data)[Num], Ret toler)
{
- bool test __attribute__((unused)) = true;
const Ret eps = std::numeric_limits<Ret>::epsilon();
Ret max_abs_diff = -Ret(1);
Ret max_abs_frac = -Ret(1);
diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/19_legendre/check_value.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/19_legendre/check_value.cc
index 19f096d..325ae0d 100644
--- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/19_legendre/check_value.cc
+++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/19_legendre/check_value.cc
@@ -305,7 +305,6 @@ template<typename Ret, unsigned int Num>
void
test(const testcase_legendre<Ret> (&data)[Num], Ret toler)
{
- bool test __attribute__((unused)) = true;
const Ret eps = std::numeric_limits<Ret>::epsilon();
Ret max_abs_diff = -Ret(1);
Ret max_abs_frac = -Ret(1);
diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/20_riemann_zeta/check_value_neg.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/20_riemann_zeta/check_value_neg.cc
index 658faa7..cbbccdf 100644
--- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/20_riemann_zeta/check_value_neg.cc
+++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/20_riemann_zeta/check_value_neg.cc
@@ -273,7 +273,6 @@ template<typename Ret, unsigned int Num>
void
test(const testcase_riemann_zeta<Ret> (&data)[Num], Ret toler)
{
- bool test __attribute__((unused)) = true;
const Ret eps = std::numeric_limits<Ret>::epsilon();
Ret max_abs_diff = -Ret(1);
Ret max_abs_frac = -Ret(1);
diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/21_sph_bessel/check_value.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/21_sph_bessel/check_value.cc
index 5863f9a..f2ef94b 100644
--- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/21_sph_bessel/check_value.cc
+++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/21_sph_bessel/check_value.cc
@@ -504,7 +504,6 @@ template<typename Ret, unsigned int Num>
void
test(const testcase_sph_bessel<Ret> (&data)[Num], Ret toler)
{
- bool test __attribute__((unused)) = true;
const Ret eps = std::numeric_limits<Ret>::epsilon();
Ret max_abs_diff = -Ret(1);
Ret max_abs_frac = -Ret(1);
diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/22_sph_legendre/check_value.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/22_sph_legendre/check_value.cc
index 910485f..1e178a6 100644
--- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/22_sph_legendre/check_value.cc
+++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/22_sph_legendre/check_value.cc
@@ -1985,7 +1985,6 @@ template<typename Ret, unsigned int Num>
void
test(const testcase_sph_legendre<Ret> (&data)[Num], Ret toler)
{
- bool test __attribute__((unused)) = true;
const Ret eps = std::numeric_limits<Ret>::epsilon();
Ret max_abs_diff = -Ret(1);
Ret max_abs_frac = -Ret(1);
diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/22_sph_legendre/pr86655.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/22_sph_legendre/pr86655.cc
index 11c9935..87f63ce 100644
--- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/22_sph_legendre/pr86655.cc
+++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/22_sph_legendre/pr86655.cc
@@ -36,7 +36,6 @@ template<typename _Tp>
void
test_m_gt_l()
{
- bool test __attribute__((unused)) = true;
unsigned int larr[4] = {0u, 1u, 2u, 5u};
for (unsigned int l = 0; l < 4; ++l)
for (unsigned int m = larr[l] + 1u; m <= larr[l] + 2u; ++m)
diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/23_sph_neumann/check_value.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/23_sph_neumann/check_value.cc
index 8134e7f..64cfce9 100644
--- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/23_sph_neumann/check_value.cc
+++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/special_functions/23_sph_neumann/check_value.cc
@@ -554,7 +554,6 @@ template<typename Ret, unsigned int Num>
void
test(const testcase_sph_neumann<Ret> (&data)[Num], Ret toler)
{
- bool test __attribute__((unused)) = true;
const Ret eps = std::numeric_limits<Ret>::epsilon();
Ret max_abs_diff = -Ret(1);
Ret max_abs_frac = -Ret(1);
diff --git a/libstdc++-v3/testsuite/util/debug/unordered_checks.h b/libstdc++-v3/testsuite/util/debug/unordered_checks.h
index d01ee82..785aeb4 100644
--- a/libstdc++-v3/testsuite/util/debug/unordered_checks.h
+++ b/libstdc++-v3/testsuite/util/debug/unordered_checks.h
@@ -65,28 +65,36 @@ namespace __gnu_test
template<typename _Tp>
struct KeyExtractor
{
- static _Tp get_key(const _Tp& val)
+ static const _Tp& get_key(const _Tp& val)
{ return val; }
};
template<typename _Tp1, typename _Tp2>
- struct KeyExtractor<std::pair<const _Tp1, _Tp2>>
+ struct KeyExtractor<std::pair<_Tp1, _Tp2>>
{
- static _Tp1 get_key(const std::pair<const _Tp1, _Tp2>& val)
+ static const _Tp1& get_key(const std::pair<_Tp1, _Tp2>& val)
{ return val.first; }
};
template<typename _Tp>
- void use_erased_local_iterator()
+ void fill_container(_Tp& c)
{
typedef _Tp cont_type;
typedef typename cont_type::value_type cont_val_type;
typedef typename CopyableValueType<cont_val_type>::value_type val_type;
generate_unique<val_type> gu;
- cont_type c;
for (size_t i = 0; i != 5; ++i)
c.insert(gu.build());
+ }
+
+ template<typename _Tp>
+ void use_erased_local_iterator()
+ {
+ typedef _Tp cont_type;
+ typedef typename cont_type::value_type cont_val_type;
+ cont_type c;
+ fill_container(c);
typename cont_type::local_iterator it, end;
for (size_t i = 0; i != c.bucket_count(); ++i)
@@ -96,22 +104,18 @@ namespace __gnu_test
if (it != end)
break;
}
- typename cont_type::key_type key = KeyExtractor<cont_val_type>::get_key(*it);
+
+ const auto& key = KeyExtractor<cont_val_type>::get_key(*it);
c.erase(key);
VERIFY( it != end );
}
template<typename _Tp>
- void use_invalid_local_iterator()
+ typename _Tp::local_iterator
+ fill_and_get_local_iterator(_Tp& c)
{
typedef _Tp cont_type;
- typedef typename cont_type::value_type cont_val_type;
- typedef typename CopyableValueType<cont_val_type>::value_type val_type;
- generate_unique<val_type> gu;
-
- cont_type c;
- for (size_t i = 0; i != 5; ++i)
- c.insert(gu.build());
+ fill_container(c);
typename cont_type::local_iterator it;
for (size_t i = 0; i != c.bucket_count(); ++i)
@@ -120,22 +124,107 @@ namespace __gnu_test
if (it != c.end(i))
break;
}
- cont_val_type val = *it;
+
+ return it;
+ }
+
+ template<typename _Tp>
+ void use_invalid_local_iterator()
+ {
+ typedef _Tp cont_type;
+ cont_type c;
+ auto it = fill_and_get_local_iterator(c);
+
+ const auto& val = *it;
c.clear();
VERIFY( *it == val );
}
template<typename _Tp>
- void invalid_local_iterator_pre_increment()
+ void invalid_local_iterator_arrow_operator()
{
typedef _Tp cont_type;
- typedef typename cont_type::value_type cont_val_type;
- typedef typename CopyableValueType<cont_val_type>::value_type val_type;
- generate_unique<val_type> gu;
+ cont_type c;
+ auto it = fill_and_get_local_iterator(c);
+
+ const auto& val = *it;
+ c.clear();
+ VERIFY( *it.operator->() == val );
+ }
+ template<typename _Tp>
+ void invalid_local_iterator_copy_construction()
+ {
+ typedef _Tp cont_type;
cont_type c;
- for (size_t i = 0; i != 5; ++i)
- c.insert(gu.build());
+ auto it = fill_and_get_local_iterator(c);
+
+ const auto& val = *it;
+ c.clear();
+ typename cont_type::local_iterator lit(it);
+ VERIFY( *lit == val );
+ }
+
+ template<typename _Tp>
+ void invalid_local_iterator_move_construction()
+ {
+ typedef _Tp cont_type;
+ cont_type c;
+ auto it = fill_and_get_local_iterator(c);
+
+ const auto& val = *it;
+ c.clear();
+ typename cont_type::local_iterator lit(std::move(it));
+ VERIFY( *lit == val );
+ }
+
+ template<typename _Tp>
+ void invalid_local_iterator_copy_assignment()
+ {
+ typedef _Tp cont_type;
+ cont_type c;
+ auto it = fill_and_get_local_iterator(c);
+
+ const auto& val = *it;
+ c.clear();
+ typename cont_type::local_iterator lit;
+ lit = it;
+ VERIFY( *lit == val );
+ }
+
+ template<typename _Tp>
+ void invalid_local_iterator_move_assignment()
+ {
+ typedef _Tp cont_type;
+ cont_type c;
+ auto it = fill_and_get_local_iterator(c);
+
+ const auto& val = *it;
+ c.clear();
+ typename cont_type::local_iterator lit;
+ lit = std::move(it);
+ VERIFY( *lit == val );
+ }
+
+ template<typename _Tp>
+ void invalid_local_iterator_const_conversion()
+ {
+ typedef _Tp cont_type;
+ cont_type c;
+ auto it = fill_and_get_local_iterator(c);
+
+ const auto& val = *it;
+ c.clear();
+ typename cont_type::const_local_iterator clit(it);
+ VERIFY( *clit == val );
+ }
+
+ template<typename _Tp>
+ void invalid_local_iterator_pre_increment()
+ {
+ typedef _Tp cont_type;
+ cont_type c;
+ fill_container(c);
auto lit = c.begin(0);
for (size_t i = 0; i != 6; ++i)
@@ -146,13 +235,8 @@ namespace __gnu_test
void invalid_local_iterator_post_increment()
{
typedef _Tp cont_type;
- typedef typename cont_type::value_type cont_val_type;
- typedef typename CopyableValueType<cont_val_type>::value_type val_type;
- generate_unique<val_type> gu;
-
cont_type c;
- for (size_t i = 0; i != 5; ++i)
- c.insert(gu.build());
+ fill_container(c);
auto lit = c.begin(0);
for (size_t i = 0; i != 6; ++i)
@@ -163,13 +247,8 @@ namespace __gnu_test
void invalid_local_iterator_compare()
{
typedef _Tp cont_type;
- typedef typename cont_type::value_type cont_val_type;
- typedef typename CopyableValueType<cont_val_type>::value_type val_type;
- generate_unique<val_type> gu;
-
cont_type c;
- for (size_t i = 0; i != 5; ++i)
- c.insert(gu.build());
+ fill_container(c);
typename cont_type::local_iterator it1, it2;
size_t i;
@@ -194,13 +273,8 @@ namespace __gnu_test
void invalid_local_iterator_range()
{
typedef _Tp cont_type;
- typedef typename cont_type::value_type cont_val_type;
- typedef typename CopyableValueType<cont_val_type>::value_type val_type;
- generate_unique<val_type> gu;
-
cont_type c;
- for (size_t i = 0; i != 5; ++i)
- c.insert(gu.build());
+ fill_container(c);
typename cont_type::local_iterator it, end;
for (size_t i = 0; i != c.bucket_count(); ++i)
diff --git a/libstdc++-v3/testsuite/util/pstl/test_utils.h b/libstdc++-v3/testsuite/util/pstl/test_utils.h
index 55b5100..9c61a714 100644
--- a/libstdc++-v3/testsuite/util/pstl/test_utils.h
+++ b/libstdc++-v3/testsuite/util/pstl/test_utils.h
@@ -154,7 +154,7 @@ class ForwardIterator
explicit ForwardIterator(Iterator i) : my_iterator(i) {}
reference operator*() const { return *my_iterator; }
Iterator operator->() const { return my_iterator; }
- ForwardIterator
+ ForwardIterator&
operator++()
{
++my_iterator;
@@ -194,13 +194,13 @@ class BidirectionalIterator : public ForwardIterator<Iterator, IteratorTag>
explicit BidirectionalIterator(Iterator i) : base_type(i) {}
BidirectionalIterator(const base_type& i) : base_type(i.iterator()) {}
- BidirectionalIterator
+ BidirectionalIterator&
operator++()
{
++base_type::my_iterator;
return *this;
}
- BidirectionalIterator
+ BidirectionalIterator&
operator--()
{
--base_type::my_iterator;
diff --git a/libstdc++-v3/testsuite/util/replacement_memory_operators.h b/libstdc++-v3/testsuite/util/replacement_memory_operators.h
index 2516cd2..69afa77 100644
--- a/libstdc++-v3/testsuite/util/replacement_memory_operators.h
+++ b/libstdc++-v3/testsuite/util/replacement_memory_operators.h
@@ -36,8 +36,12 @@ namespace __gnu_test
~counter() THROW (counter_error)
{
+#if __cpp_exceptions
if (_M_throw && _M_count != 0)
throw counter_error();
+#else
+ VERIFY( !_M_throw || _M_count == 0 );
+#endif
}
static void
@@ -133,8 +137,12 @@ void* operator new(std::size_t size) THROW(std::bad_alloc)
{
std::printf("operator new is called \n");
void* p = std::malloc(size);
+#if __cpp_exceptions
if (!p)
throw std::bad_alloc();
+#else
+ VERIFY( p );
+#endif
__gnu_test::counter::increment();
return p;
}
diff --git a/libstdc++-v3/testsuite/util/testsuite_abi.cc b/libstdc++-v3/testsuite/util/testsuite_abi.cc
index 1b4044c..4b01023 100644
--- a/libstdc++-v3/testsuite/util/testsuite_abi.cc
+++ b/libstdc++-v3/testsuite/util/testsuite_abi.cc
@@ -216,6 +216,7 @@ check_version(symbol& test, bool added)
known_versions.push_back("GLIBCXX_3.4.32");
known_versions.push_back("GLIBCXX_3.4.33");
known_versions.push_back("GLIBCXX_3.4.34");
+ known_versions.push_back("GLIBCXX_3.4.35");
known_versions.push_back("GLIBCXX_LDBL_3.4.31");
known_versions.push_back("GLIBCXX_IEEE128_3.4.29");
known_versions.push_back("GLIBCXX_IEEE128_3.4.30");
@@ -240,6 +241,7 @@ check_version(symbol& test, bool added)
#ifdef __riscv
known_versions.push_back("CXXABI_1.3.16");
#endif
+ known_versions.push_back("CXXABI_1.3.17");
known_versions.push_back("CXXABI_IEEE128_1.3.13");
known_versions.push_back("CXXABI_TM_1");
known_versions.push_back("CXXABI_FLOAT128");
@@ -258,8 +260,8 @@ check_version(symbol& test, bool added)
test.version_status = symbol::incompatible;
// Check that added symbols are added in the latest pre-release version.
- bool latestp = (test.version_name == "GLIBCXX_3.4.34"
- || test.version_name == "CXXABI_1.3.16"
+ bool latestp = (test.version_name == "GLIBCXX_3.4.35"
+ || test.version_name == "CXXABI_1.3.17"
|| test.version_name == "CXXABI_FLOAT128"
|| test.version_name == "CXXABI_TM_1");
if (added && !latestp)
diff --git a/libstdc++-v3/testsuite/util/testsuite_allocator.h b/libstdc++-v3/testsuite/util/testsuite_allocator.h
index be596bf..e5ffad2 100644
--- a/libstdc++-v3/testsuite/util/testsuite_allocator.h
+++ b/libstdc++-v3/testsuite/util/testsuite_allocator.h
@@ -541,15 +541,16 @@ namespace __gnu_test
default_init_allocator() = default;
template<typename U>
+ constexpr
default_init_allocator(const default_init_allocator<U>& a)
: state(a.state)
{ }
- T*
+ constexpr T*
allocate(std::size_t n)
{ return std::allocator<T>().allocate(n); }
- void
+ constexpr void
deallocate(T* p, std::size_t n)
{ std::allocator<T>().deallocate(p, n); }
@@ -557,15 +558,17 @@ namespace __gnu_test
};
template<typename T, typename U>
- bool operator==(const default_init_allocator<T>& t,
- const default_init_allocator<U>& u)
+ constexpr bool
+ operator==(const default_init_allocator<T>& t,
+ const default_init_allocator<U>& u)
{ return t.state == u.state; }
template<typename T, typename U>
- bool operator!=(const default_init_allocator<T>& t,
- const default_init_allocator<U>& u)
+ constexpr bool
+ operator!=(const default_init_allocator<T>& t,
+ const default_init_allocator<U>& u)
{ return !(t == u); }
-#endif
+#endif // C++11
template<typename Tp>
struct ExplicitConsAlloc : std::allocator<Tp>
diff --git a/libstdc++-v3/testsuite/util/testsuite_iterators.h b/libstdc++-v3/testsuite/util/testsuite_iterators.h
index 0df6dcc..74a8739 100644
--- a/libstdc++-v3/testsuite/util/testsuite_iterators.h
+++ b/libstdc++-v3/testsuite/util/testsuite_iterators.h
@@ -610,12 +610,10 @@ namespace __gnu_test
test_container(T* _first, T* _last) : bounds(_first, _last)
{ }
-#if __cplusplus >= 201103L
template<std::size_t N>
explicit
- test_container(T (&arr)[N]) : test_container(arr, arr+N)
+ test_container(T (&arr)[N]) : bounds(arr, arr+N)
{ }
-#endif
ItType<T>
it(int pos)
@@ -894,6 +892,9 @@ namespace __gnu_test
using test_input_range
= test_range<T, input_iterator_wrapper>;
template<typename T>
+ using test_input_range_nocopy
+ = test_range_nocopy<T, input_iterator_wrapper_nocopy>;
+ template<typename T>
using test_output_range
= test_range<T, output_iterator_wrapper>;