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/headers/c++1998/stdc++_assert_neg.cc3
-rw-r--r--libstdc++-v3/testsuite/17_intro/headers/c++2011/42319.cc4
-rw-r--r--libstdc++-v3/testsuite/17_intro/names.cc16
-rw-r--r--libstdc++-v3/testsuite/18_support/comparisons/categories/zero_neg.cc16
-rw-r--r--libstdc++-v3/testsuite/18_support/comparisons/type_order/1.cc95
-rw-r--r--libstdc++-v3/testsuite/18_support/exception/version.cc9
-rw-r--r--libstdc++-v3/testsuite/18_support/exception_ptr/62258.cc2
-rw-r--r--libstdc++-v3/testsuite/18_support/exception_ptr/exception_ptr_cast.cc92
-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/18_support/headers/climits/values.cc8
-rw-r--r--libstdc++-v3/testsuite/18_support/headers/csignal/macros.cc4
-rw-r--r--libstdc++-v3/testsuite/18_support/headers/new/synopsis.cc4
-rw-r--r--libstdc++-v3/testsuite/18_support/numeric_limits/128bit.cc5
-rw-r--r--libstdc++-v3/testsuite/18_support/uncaught_exception/14026.cc2
-rw-r--r--libstdc++-v3/testsuite/19_diagnostics/debugging/breakpoint.cc13
-rw-r--r--libstdc++-v3/testsuite/19_diagnostics/debugging/breakpoint_if_debugging.cc13
-rw-r--r--libstdc++-v3/testsuite/19_diagnostics/debugging/is_debugger_present-2.cc19
-rw-r--r--libstdc++-v3/testsuite/19_diagnostics/debugging/is_debugger_present.cc14
-rw-r--r--libstdc++-v3/testsuite/20_util/aligned_storage/value.cc6
-rw-r--r--libstdc++-v3/testsuite/20_util/allocator_traits/members/allocate_hint.cc2
-rw-r--r--libstdc++-v3/testsuite/20_util/allocator_traits/members/allocate_hint_nonpod.cc2
-rw-r--r--libstdc++-v3/testsuite/20_util/any/misc/any_cast_neg.cc3
-rw-r--r--libstdc++-v3/testsuite/20_util/bind/80564.cc50
-rw-r--r--libstdc++-v3/testsuite/20_util/bind/cv_quals_2.cc3
-rw-r--r--libstdc++-v3/testsuite/20_util/bind/dangling_ref.cc1
-rw-r--r--libstdc++-v3/testsuite/20_util/bind/ref_neg.cc1
-rw-r--r--libstdc++-v3/testsuite/20_util/bitset/121054.cc233
-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/constexpr_c++23.cc2
-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/common_reference/p2655r3.cc15
-rw-r--r--libstdc++-v3/testsuite/20_util/constant_wrapper/adl.cc86
-rw-r--r--libstdc++-v3/testsuite/20_util/constant_wrapper/ex.cc39
-rw-r--r--libstdc++-v3/testsuite/20_util/constant_wrapper/generic.cc391
-rw-r--r--libstdc++-v3/testsuite/20_util/constant_wrapper/instantiate.cc575
-rw-r--r--libstdc++-v3/testsuite/20_util/constant_wrapper/op_comma_neg.cc14
-rw-r--r--libstdc++-v3/testsuite/20_util/constant_wrapper/other_wrappers.cc75
-rw-r--r--libstdc++-v3/testsuite/20_util/constant_wrapper/version.cc11
-rw-r--r--libstdc++-v3/testsuite/20_util/copyable_function/call.cc248
-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/duration/114244.cc4
-rw-r--r--libstdc++-v3/testsuite/20_util/duration/io.cc8
-rw-r--r--libstdc++-v3/testsuite/20_util/expected/119714.cc9
-rw-r--r--libstdc++-v3/testsuite/20_util/expected/equality.cc26
-rw-r--r--libstdc++-v3/testsuite/20_util/expected/illformed_neg.cc1
-rw-r--r--libstdc++-v3/testsuite/20_util/expected/lwg4222.cc39
-rw-r--r--libstdc++-v3/testsuite/20_util/expected/lwg4366.cc33
-rw-r--r--libstdc++-v3/testsuite/20_util/function/cons/70692.cc2
-rw-r--r--libstdc++-v3/testsuite/20_util/function_objects/121782.cc30
-rw-r--r--libstdc++-v3/testsuite/20_util/function_objects/bind_back/1.cc196
-rw-r--r--libstdc++-v3/testsuite/20_util/function_objects/bind_back/111327.cc14
-rw-r--r--libstdc++-v3/testsuite/20_util/function_objects/bind_back/nttp.cc345
-rw-r--r--libstdc++-v3/testsuite/20_util/function_objects/bind_back/nttp_neg.cc38
-rw-r--r--libstdc++-v3/testsuite/20_util/function_objects/bind_front/1.cc195
-rw-r--r--libstdc++-v3/testsuite/20_util/function_objects/bind_front/111327.cc13
-rw-r--r--libstdc++-v3/testsuite/20_util/function_objects/bind_front/nttp.cc345
-rw-r--r--libstdc++-v3/testsuite/20_util/function_objects/bind_front/nttp_neg.cc38
-rw-r--r--libstdc++-v3/testsuite/20_util/function_objects/not_fn/111327.cc19
-rw-r--r--libstdc++-v3/testsuite/20_util/function_objects/not_fn/nttp.cc141
-rw-r--r--libstdc++-v3/testsuite/20_util/function_objects/not_fn/nttp_neg.cc28
-rw-r--r--libstdc++-v3/testsuite/20_util/function_objects/not_fn/version.cc12
-rw-r--r--libstdc++-v3/testsuite/20_util/function_ref/assign.cc108
-rw-r--r--libstdc++-v3/testsuite/20_util/function_ref/call.cc263
-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.cc131
-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/hash/int128.cc20
-rw-r--r--libstdc++-v3/testsuite/20_util/headers/functional/synopsis.cc27
-rw-r--r--libstdc++-v3/testsuite/20_util/headers/memory/version.cc8
-rw-r--r--libstdc++-v3/testsuite/20_util/integer_comparisons/extended.cc60
-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/is_implicit_lifetime/value.cc129
-rw-r--r--libstdc++-v3/testsuite/20_util/is_implicit_lifetime/version.cc27
-rw-r--r--libstdc++-v3/testsuite/20_util/is_literal_type/requirements/explicit_instantiation.cc2
-rw-r--r--libstdc++-v3/testsuite/20_util/is_literal_type/requirements/typedefs.cc2
-rw-r--r--libstdc++-v3/testsuite/20_util/is_literal_type/value.cc2
-rw-r--r--libstdc++-v3/testsuite/20_util/is_pod/requirements/explicit_instantiation.cc2
-rw-r--r--libstdc++-v3/testsuite/20_util/is_pod/requirements/typedefs.cc2
-rw-r--r--libstdc++-v3/testsuite/20_util/is_pod/value.cc2
-rw-r--r--libstdc++-v3/testsuite/20_util/is_sufficiently_aligned/1.cc31
-rw-r--r--libstdc++-v3/testsuite/20_util/make_unsigned/int128.cc14
-rw-r--r--libstdc++-v3/testsuite/20_util/move_only_function/call.cc44
-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/cons/value_neg.cc1
-rw-r--r--libstdc++-v3/testsuite/20_util/optional/make_optional-2.cc2
-rw-r--r--libstdc++-v3/testsuite/20_util/optional/make_optional_neg.cc20
-rw-r--r--libstdc++-v3/testsuite/20_util/optional/monadic/or_else_neg.cc1
-rw-r--r--libstdc++-v3/testsuite/20_util/optional/monadic/ref_neg.cc20
-rw-r--r--libstdc++-v3/testsuite/20_util/optional/range.cc350
-rw-r--r--libstdc++-v3/testsuite/20_util/optional/ref/access.cc119
-rw-r--r--libstdc++-v3/testsuite/20_util/optional/ref/assign.cc430
-rw-r--r--libstdc++-v3/testsuite/20_util/optional/ref/cons.cc356
-rw-r--r--libstdc++-v3/testsuite/20_util/optional/ref/internal_traits.cc11
-rw-r--r--libstdc++-v3/testsuite/20_util/optional/ref/make_optional/1.cc74
-rw-r--r--libstdc++-v3/testsuite/20_util/optional/ref/make_optional/from_args_neg.cc43
-rw-r--r--libstdc++-v3/testsuite/20_util/optional/ref/make_optional/from_lvalue_neg.cc40
-rw-r--r--libstdc++-v3/testsuite/20_util/optional/ref/make_optional/from_rvalue_neg.cc38
-rw-r--r--libstdc++-v3/testsuite/20_util/optional/ref/monadic.cc192
-rw-r--r--libstdc++-v3/testsuite/20_util/optional/ref/relops.cc229
-rw-r--r--libstdc++-v3/testsuite/20_util/optional/relops/constrained.cc86
-rw-r--r--libstdc++-v3/testsuite/20_util/optional/relops/lwg4370.cc55
-rw-r--r--libstdc++-v3/testsuite/20_util/optional/requirements.cc6
-rw-r--r--libstdc++-v3/testsuite/20_util/optional/requirements_neg.cc17
-rw-r--r--libstdc++-v3/testsuite/20_util/optional/version.cc22
-rw-r--r--libstdc++-v3/testsuite/20_util/owner_equal/cmp.cc105
-rw-r--r--libstdc++-v3/testsuite/20_util/owner_equal/noexcept.cc30
-rw-r--r--libstdc++-v3/testsuite/20_util/owner_equal/version.cc13
-rw-r--r--libstdc++-v3/testsuite/20_util/owner_hash/cmp.cc87
-rw-r--r--libstdc++-v3/testsuite/20_util/owner_hash/noexcept.cc16
-rw-r--r--libstdc++-v3/testsuite/20_util/pair/astuple/get_by_type.cc52
-rw-r--r--libstdc++-v3/testsuite/20_util/pair/cons/110853.cc10
-rw-r--r--libstdc++-v3/testsuite/20_util/ratio/operations/ops_overflow_neg.cc2
-rw-r--r--libstdc++-v3/testsuite/20_util/reference_wrapper/p2655r3.cc75
-rw-r--r--libstdc++-v3/testsuite/20_util/scoped_allocator/69293_neg.cc2
-rw-r--r--libstdc++-v3/testsuite/20_util/shared_ptr/assign/auto_ptr.cc2
-rw-r--r--libstdc++-v3/testsuite/20_util/shared_ptr/assign/auto_ptr_neg.cc2
-rw-r--r--libstdc++-v3/testsuite/20_util/shared_ptr/assign/auto_ptr_rvalue.cc2
-rw-r--r--libstdc++-v3/testsuite/20_util/shared_ptr/atomic/1.cc2
-rw-r--r--libstdc++-v3/testsuite/20_util/shared_ptr/atomic/2.cc2
-rw-r--r--libstdc++-v3/testsuite/20_util/shared_ptr/atomic/3.cc2
-rw-r--r--libstdc++-v3/testsuite/20_util/shared_ptr/atomic/pr118757.cc30
-rw-r--r--libstdc++-v3/testsuite/20_util/shared_ptr/cons/43820_neg.cc2
-rw-r--r--libstdc++-v3/testsuite/20_util/shared_ptr/cons/auto_ptr.cc2
-rw-r--r--libstdc++-v3/testsuite/20_util/shared_ptr/cons/auto_ptr_neg.cc2
-rw-r--r--libstdc++-v3/testsuite/20_util/shared_ptr/cons/move.cc2
-rw-r--r--libstdc++-v3/testsuite/20_util/shared_ptr/creation/dr925.cc2
-rw-r--r--libstdc++-v3/testsuite/20_util/shared_ptr/observers/owner_equal.cc74
-rw-r--r--libstdc++-v3/testsuite/20_util/shared_ptr/observers/owner_hash.cc71
-rw-r--r--libstdc++-v3/testsuite/20_util/shared_ptr/requirements/1.cc111
-rw-r--r--libstdc++-v3/testsuite/20_util/specialized_algorithms/destroy/121024.cc77
-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_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_value_construct/120397.cc19
-rw-r--r--libstdc++-v3/testsuite/20_util/synchronized_pool_resource/118681.cc6
-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/requirements/empty_trivial.cc17
-rw-r--r--libstdc++-v3/testsuite/20_util/unique_ptr/cons/auto_ptr.cc2
-rw-r--r--libstdc++-v3/testsuite/20_util/unique_ptr/cons/auto_ptr_neg.cc2
-rw-r--r--libstdc++-v3/testsuite/20_util/unique_ptr/lwg4148.cc1
-rw-r--r--libstdc++-v3/testsuite/20_util/unique_ptr/modifiers/93562.cc25
-rw-r--r--libstdc++-v3/testsuite/20_util/unsynchronized_pool_resource/118681.cc58
-rw-r--r--libstdc++-v3/testsuite/20_util/variable_templates_for_traits.cc2
-rw-r--r--libstdc++-v3/testsuite/20_util/variant/112591.cc32
-rw-r--r--libstdc++-v3/testsuite/20_util/variant/87619.cc2
-rw-r--r--libstdc++-v3/testsuite/20_util/weak_ptr/cons/virtual_bases.cc80
-rw-r--r--libstdc++-v3/testsuite/20_util/weak_ptr/observers/owner_equal.cc52
-rw-r--r--libstdc++-v3/testsuite/20_util/weak_ptr/observers/owner_hash.cc50
-rw-r--r--libstdc++-v3/testsuite/20_util/weak_ptr/pr118757.cc31
-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/from_range.cc31
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/modifiers/append/append_range.cc24
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/modifiers/assign/assign_range.cc24
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/modifiers/insert/insert_range.cc24
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/modifiers/replace/replace_with_range.cc24
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/stoi.cc2
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/stol.cc2
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/stold.cc6
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/stoll.cc2
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/stoul.cc2
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/stoull.cc2
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/stoi.cc2
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/stol.cc2
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/stoll.cc2
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/stoul.cc2
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/stoull.cc2
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/operations/subview/char.cc46
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/operations/subview/wchar_t.cc46
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string_view/operations/subview/char.cc51
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string_view/operations/subview/wchar_t.cc51
-rw-r--r--libstdc++-v3/testsuite/22_locale/codecvt/codecvt_unicode.h4
-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/22_locale/time_get/get/char/3.cc2
-rw-r--r--libstdc++-v3/testsuite/22_locale/time_get/get/wchar_t/3.cc2
-rw-r--r--libstdc++-v3/testsuite/23_containers/array/creation/3_neg.cc2
-rw-r--r--libstdc++-v3/testsuite/23_containers/array/tuple_interface/get_neg.cc6
-rw-r--r--libstdc++-v3/testsuite/23_containers/bitset/lwg4294.cc11
-rw-r--r--libstdc++-v3/testsuite/23_containers/deque/capacity/shrink_to_fit.cc37
-rw-r--r--libstdc++-v3/testsuite/23_containers/deque/debug/erase.cc27
-rw-r--r--libstdc++-v3/testsuite/23_containers/deque/debug/invalidation/erase.cc28
-rw-r--r--libstdc++-v3/testsuite/23_containers/deque/modifiers/emplace/118087.cc43
-rw-r--r--libstdc++-v3/testsuite/23_containers/flat_map/1.cc54
-rw-r--r--libstdc++-v3/testsuite/23_containers/flat_multimap/1.cc44
-rw-r--r--libstdc++-v3/testsuite/23_containers/flat_multiset/1.cc11
-rw-r--r--libstdc++-v3/testsuite/23_containers/flat_set/1.cc11
-rw-r--r--libstdc++-v3/testsuite/23_containers/forward_list/48101_neg.cc1
-rw-r--r--libstdc++-v3/testsuite/23_containers/forward_list/modifiers/122661.cc20
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/access/capacity.cc51
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/access/elem.cc115
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/access/elem_neg.cc65
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/cons/1.cc387
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/cons/from_range.cc177
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/cons/throws.cc129
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/copy.cc251
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/debug/assign1_neg.cc16
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/debug/assign2_neg.cc16
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/debug/assign3_neg.cc16
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/debug/assign4_backtrace_neg.cc17
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/debug/assign4_neg.cc15
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/debug/construct1_neg.cc16
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/debug/construct2_neg.cc16
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/debug/construct3_neg.cc16
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/debug/construct4_neg.cc15
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/debug/debug_functions.cc34
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/debug/erase.cc35
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/debug/insert1_neg.cc16
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/debug/insert2_neg.cc16
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/debug/insert3_neg.cc16
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/debug/insert4_neg.cc15
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/debug/insert5_neg.cc16
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/debug/insert7_neg.cc24
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/1.cc33
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/2.cc34
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/3.cc43
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/4.cc40
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/append_range.cc45
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/erase.cc36
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/pop_back.cc27
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/push_back.cc53
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/swap.cc53
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/try_append_range.cc45
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/try_emplace_back.cc27
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/try_push_back.cc45
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/unchecked_emplace_back.cc27
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/erasure.cc69
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/assign.cc379
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/erase.cc117
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/erase_neg.cc43
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/multi_insert.cc606
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/single_insert.cc215
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/single_insert_neg.cc42
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/move.cc362
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/relops.cc60
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/version.cc20
-rw-r--r--libstdc++-v3/testsuite/23_containers/list/48101_neg.cc1
-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.cc14
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/accessors/aligned_neg.cc33
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/accessors/debug/aligned_access_neg.cc23
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/accessors/debug/aligned_offset_neg.cc23
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/accessors/default_neg.cc23
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/accessors/generic.cc171
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/class_mandate_neg.cc41
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/extents/class_mandates_neg.cc17
-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.cc69
-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.cc96
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/extents/extents_mismatch_neg.cc35
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/extents/misc.cc261
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/int_like.h81
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/layout_like.h87
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/layout_traits.h196
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/layouts/class_mandate_neg.cc49
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/layouts/ctors.cc532
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/layouts/debug/out_of_bounds_neg.cc30
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/layouts/empty.cc148
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/layouts/mapping.cc717
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded.cc674
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded_neg.cc352
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/layouts/stride.cc513
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc779
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/out_of_bounds_neg.cc24
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/submdspan/generic.cc71
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/left.cc9
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/left_padded.cc12
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/right.cc9
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/right_padded.cc12
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/stride.cc9
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/testcases.h360
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/submdspan/strided_slice.cc49
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/submdspan/strided_slice_neg.cc19
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_canonicalize_slices.cc220
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_canonicalize_slices_neg.cc208
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_extents.cc169
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_extents_neg.cc48
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_mapping.cc301
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_neg.cc122
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/version.cc20
-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.cc14
-rw-r--r--libstdc++-v3/testsuite/23_containers/multiset/48101_neg.cc1
-rw-r--r--libstdc++-v3/testsuite/23_containers/multiset/cons/from_range.cc6
-rw-r--r--libstdc++-v3/testsuite/23_containers/set/48101_neg.cc1
-rw-r--r--libstdc++-v3/testsuite/23_containers/set/cons/from_range.cc6
-rw-r--r--libstdc++-v3/testsuite/23_containers/span/120997.cc46
-rw-r--r--libstdc++-v3/testsuite/23_containers/span/contiguous_range_neg.cc1
-rw-r--r--libstdc++-v3/testsuite/23_containers/span/deduction.cc21
-rw-r--r--libstdc++-v3/testsuite/23_containers/tuple/comparison_operators/119721.cc65
-rw-r--r--libstdc++-v3/testsuite/23_containers/tuple/cons/119721.cc121
-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.cc14
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_map/const_container.cc19
-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.cc14
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_multimap/const_container.cc22
-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.cc4
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_multiset/const_container.cc15
-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.cc4
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_set/const_container.cc14
-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.cc24
-rw-r--r--libstdc++-v3/testsuite/23_containers/vector/bool/format.cc7
-rw-r--r--libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/assign/assign_range.cc20
-rw-r--r--libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/insert/append_range.cc13
-rw-r--r--libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/insert/insert_range.cc20
-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.cc40
-rw-r--r--libstdc++-v3/testsuite/23_containers/vector/debug/erase.cc27
-rw-r--r--libstdc++-v3/testsuite/23_containers/vector/debug/invalidation/erase.cc28
-rw-r--r--libstdc++-v3/testsuite/23_containers/vector/debug/mutex_association.cc2
-rw-r--r--libstdc++-v3/testsuite/23_containers/vector/modifiers/append_range.cc76
-rw-r--r--libstdc++-v3/testsuite/23_containers/vector/modifiers/assign/assign_range.cc20
-rw-r--r--libstdc++-v3/testsuite/23_containers/vector/modifiers/insert/insert_range.cc64
-rw-r--r--libstdc++-v3/testsuite/23_containers/vector/modifiers/moveable.cc6
-rw-r--r--libstdc++-v3/testsuite/23_containers/vector/modifiers/resize.cc69
-rw-r--r--libstdc++-v3/testsuite/24_iterators/const_iterator/1.cc29
-rw-r--r--libstdc++-v3/testsuite/24_iterators/indirect_callable/projected.cc5
-rw-r--r--libstdc++-v3/testsuite/24_iterators/operations/cxx20_iterators.cc60
-rw-r--r--libstdc++-v3/testsuite/24_iterators/operations/prev_neg.cc2
-rw-r--r--libstdc++-v3/testsuite/24_iterators/random_access/string_vector_iterators.cc526
-rw-r--r--libstdc++-v3/testsuite/24_iterators/range_generators/lwg3899.cc57
-rw-r--r--libstdc++-v3/testsuite/24_iterators/range_generators/lwg3900.cc3
-rw-r--r--libstdc++-v3/testsuite/24_iterators/range_operations/122224.cc100
-rw-r--r--libstdc++-v3/testsuite/24_iterators/range_operations/advance.cc2
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/copy/debug/constexpr_neg.cc2
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/copy_backward/debug/constexpr_neg.cc2
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/ends_with/1.cc165
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/equal/debug/constexpr_neg.cc2
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/fill_n/diff_type.cc13
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/heap/constrained.cc66
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/inplace_merge/constrained.cc36
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/lexicographical_compare/diff_type.cc57
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/lower_bound/debug/constexpr_partitioned_neg.cc2
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/lower_bound/debug/constexpr_partitioned_pred_neg.cc2
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/lower_bound/debug/constexpr_valid_range_neg.cc2
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/max/constrained.cc4
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/min/constrained.cc4
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/minmax/constrained.cc16
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/minmax_element/constrained.cc16
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/nth_element/58800.cc2
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/nth_element/constrained.cc33
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/nth_element/random_test.cc4
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/partial_sort/check_compare_by_value.cc4
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/partial_sort/constrained.cc3
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/partial_sort/random_test.cc4
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/partial_sort_copy/constrained.cc4
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/partial_sort_copy/random_test.cc4
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/remove_if/120789.cc36
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/rotate/121913.cc45
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/sample/constrained.cc26
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/shift_left/constrained.cc105
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/shift_right/constrained.cc104
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/shuffle/constrained.cc43
-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/25_algorithms/upper_bound/debug/constexpr_partitioned_neg.cc2
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/upper_bound/debug/constexpr_partitioned_pred_neg.cc2
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/upper_bound/debug/constexpr_valid_range_neg.cc2
-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/philox4x32.cc26
-rw-r--r--libstdc++-v3/testsuite/26_numerics/random/philox4x64.cc26
-rw-r--r--libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/copy.cc27
-rw-r--r--libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/default.cc49
-rw-r--r--libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/seed.cc51
-rw-r--r--libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/equal.cc33
-rw-r--r--libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/serialize.cc46
-rw-r--r--libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constants.cc48
-rw-r--r--libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/typedefs.cc30
-rw-r--r--libstdc++-v3/testsuite/26_numerics/random/piecewise_linear_distribution/cons/122062.cc16
-rw-r--r--libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc4
-rw-r--r--libstdc++-v3/testsuite/26_numerics/saturation/extended.cc55
-rw-r--r--libstdc++-v3/testsuite/26_numerics/stdckdint/extended.cc65
-rw-r--r--libstdc++-v3/testsuite/26_numerics/valarray/108951.cc22
-rw-r--r--libstdc++-v3/testsuite/27_io/basic_filebuf/seekoff/wchar_t/9875_seekoff.cc2
-rw-r--r--libstdc++-v3/testsuite/27_io/basic_filebuf/seekpos/wchar_t/9875_seekpos.cc2
-rw-r--r--libstdc++-v3/testsuite/27_io/basic_filebuf/underflow/char/1.cc2
-rw-r--r--libstdc++-v3/testsuite/27_io/basic_filebuf/underflow/wchar_t/11603.cc2
-rw-r--r--libstdc++-v3/testsuite/27_io/basic_istream/ignore/char/4.cc22
-rw-r--r--libstdc++-v3/testsuite/27_io/basic_istream/ignore/char/93672.cc8
-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/operations/rename.cc10
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/path/concat/120029.cc72
-rw-r--r--libstdc++-v3/testsuite/27_io/ios_base/types/fmtflags/case_label.cc6
-rw-r--r--libstdc++-v3/testsuite/27_io/ios_base/types/iostate/case_label.cc6
-rw-r--r--libstdc++-v3/testsuite/27_io/ios_base/types/openmode/case_label.cc6
-rw-r--r--libstdc++-v3/testsuite/27_io/ios_base/types/seekdir/case_label.cc2
-rw-r--r--libstdc++-v3/testsuite/27_io/manipulators/extended/get_time/wchar_t/1.cc4
-rw-r--r--libstdc++-v3/testsuite/27_io/print/1.cc56
-rw-r--r--libstdc++-v3/testsuite/28_regex/algorithms/regex_match/multiline.cc4
-rw-r--r--libstdc++-v3/testsuite/28_regex/basic_regex/assign/wchar_t/pstring.cc3
-rw-r--r--libstdc++-v3/testsuite/29_atomics/atomic/lwg3220.cc2
-rw-r--r--libstdc++-v3/testsuite/29_atomics/atomic/operators/pointer_partial_void.cc1
-rw-r--r--libstdc++-v3/testsuite/29_atomics/atomic/requirements/types_neg.cc6
-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/29_atomics/atomic_ref/address.cc42
-rw-r--r--libstdc++-v3/testsuite/29_atomics/atomic_ref/bool.cc98
-rw-r--r--libstdc++-v3/testsuite/29_atomics/atomic_ref/cv_qual.cc94
-rw-r--r--libstdc++-v3/testsuite/29_atomics/atomic_ref/deduction.cc36
-rw-r--r--libstdc++-v3/testsuite/29_atomics/atomic_ref/float.cc29
-rw-r--r--libstdc++-v3/testsuite/29_atomics/atomic_ref/generic.cc11
-rw-r--r--libstdc++-v3/testsuite/29_atomics/atomic_ref/integral.cc11
-rw-r--r--libstdc++-v3/testsuite/29_atomics/atomic_ref/op_support.cc127
-rw-r--r--libstdc++-v3/testsuite/29_atomics/atomic_ref/pointer.cc11
-rw-r--r--libstdc++-v3/testsuite/29_atomics/atomic_ref/requirements.cc127
-rw-r--r--libstdc++-v3/testsuite/29_atomics/atomic_ref/requirements_neg.cc34
-rw-r--r--libstdc++-v3/testsuite/29_atomics/atomic_ref/wait_notify.cc10
-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/condition_variable/members/116586.cc63
-rw-r--r--libstdc++-v3/testsuite/30_threads/future/members/116586.cc58
-rw-r--r--libstdc++-v3/testsuite/30_threads/packaged_task/cons/dangling_ref.cc4
-rw-r--r--libstdc++-v3/testsuite/30_threads/packaged_task/cons/lwg4154_neg.cc10
-rw-r--r--libstdc++-v3/testsuite/30_threads/recursive_timed_mutex/try_lock_until/116586.cc75
-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.cc9
-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_for.cc22
-rw-r--r--libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_posix.cc153
-rw-r--r--libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc24
-rw-r--r--libstdc++-v3/testsuite/30_threads/shared_timed_mutex/try_lock_until/116586.cc125
-rw-r--r--libstdc++-v3/testsuite/30_threads/stop_token/stop_callback/destructible_neg.cc1
-rw-r--r--libstdc++-v3/testsuite/30_threads/stop_token/stop_callback/invocable_neg.cc1
-rw-r--r--libstdc++-v3/testsuite/30_threads/this_thread/113327.cc29
-rw-r--r--libstdc++-v3/testsuite/30_threads/this_thread/sleep_for.cc13
-rw-r--r--libstdc++-v3/testsuite/30_threads/this_thread/sleep_until.cc26
-rw-r--r--libstdc++-v3/testsuite/30_threads/thread/id/output.cc35
-rw-r--r--libstdc++-v3/testsuite/30_threads/thread/swap/1.cc2
-rw-r--r--libstdc++-v3/testsuite/30_threads/timed_mutex/121496.cc14
-rw-r--r--libstdc++-v3/testsuite/30_threads/timed_mutex/try_lock_until/116586.cc60
-rw-r--r--libstdc++-v3/testsuite/Makefile.am2
-rw-r--r--libstdc++-v3/testsuite/Makefile.in5
-rw-r--r--libstdc++-v3/testsuite/backward/hash_set/check_construct_destroy.cc25
-rw-r--r--libstdc++-v3/testsuite/experimental/filesystem/path/concat/120029.cc74
-rw-r--r--libstdc++-v3/testsuite/experimental/memory/observer_ptr/make_observer.cc11
-rw-r--r--libstdc++-v3/testsuite/experimental/memory/observer_ptr/relops/relops.cc28
-rw-r--r--libstdc++-v3/testsuite/experimental/memory/observer_ptr/swap/swap.cc20
-rw-r--r--libstdc++-v3/testsuite/experimental/memory/shared_ptr/cons/move_ctor.cc2
-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/experimental/type_traits/value.cc2
-rw-r--r--libstdc++-v3/testsuite/ext/iotaarray.cc20
-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/ext/unicode/properties.cc2
-rw-r--r--libstdc++-v3/testsuite/ext/unicode/view.cc84
-rw-r--r--libstdc++-v3/testsuite/ext/verify_neg.cc28
-rw-r--r--libstdc++-v3/testsuite/lib/libstdc++.exp25
-rw-r--r--libstdc++-v3/testsuite/lib/prune.exp11
-rw-r--r--libstdc++-v3/testsuite/performance/23_containers/sort_search/list.cc2
-rw-r--r--libstdc++-v3/testsuite/performance/25_algorithms/equal_deque_iterators.cc10
-rw-r--r--libstdc++-v3/testsuite/performance/25_algorithms/search_n.cc4
-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/concepts/concepts.compare/move_only.cc28
-rw-r--r--libstdc++-v3/testsuite/std/format/arguments/args.cc45
-rw-r--r--libstdc++-v3/testsuite/std/format/arguments/args_neg.cc1
-rw-r--r--libstdc++-v3/testsuite/std/format/debug.cc472
-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/nonlocking.cc59
-rw-r--r--libstdc++-v3/testsuite/std/format/functions/format.cc13
-rw-r--r--libstdc++-v3/testsuite/std/format/parse_ctx.cc74
-rw-r--r--libstdc++-v3/testsuite/std/format/pr121765.cc53
-rw-r--r--libstdc++-v3/testsuite/std/format/ranges/adaptors.cc165
-rw-r--r--libstdc++-v3/testsuite/std/format/ranges/feature_test.cc9
-rw-r--r--libstdc++-v3/testsuite/std/format/ranges/format_kind.cc4
-rw-r--r--libstdc++-v3/testsuite/std/format/ranges/format_kind_neg.cc15
-rw-r--r--libstdc++-v3/testsuite/std/format/ranges/formatter.cc27
-rw-r--r--libstdc++-v3/testsuite/std/format/ranges/map.cc9
-rw-r--r--libstdc++-v3/testsuite/std/format/ranges/pr119861_neg.cc52
-rw-r--r--libstdc++-v3/testsuite/std/format/ranges/sequence.cc134
-rw-r--r--libstdc++-v3/testsuite/std/format/ranges/string.cc165
-rw-r--r--libstdc++-v3/testsuite/std/format/string.cc2
-rw-r--r--libstdc++-v3/testsuite/std/format/string_neg.cc2
-rw-r--r--libstdc++-v3/testsuite/std/format/tuple.cc154
-rw-r--r--libstdc++-v3/testsuite/std/memory/indirect/access.cc58
-rw-r--r--libstdc++-v3/testsuite/std/memory/indirect/copy.cc156
-rw-r--r--libstdc++-v3/testsuite/std/memory/indirect/copy_alloc.cc222
-rw-r--r--libstdc++-v3/testsuite/std/memory/indirect/ctor.cc213
-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.cc201
-rw-r--r--libstdc++-v3/testsuite/std/memory/indirect/move_alloc.cc290
-rw-r--r--libstdc++-v3/testsuite/std/memory/indirect/relops.cc82
-rw-r--r--libstdc++-v3/testsuite/std/memory/polymorphic/access.cc53
-rw-r--r--libstdc++-v3/testsuite/std/memory/polymorphic/copy.cc192
-rw-r--r--libstdc++-v3/testsuite/std/memory/polymorphic/copy_alloc.cc264
-rw-r--r--libstdc++-v3/testsuite/std/memory/polymorphic/ctor.cc199
-rw-r--r--libstdc++-v3/testsuite/std/memory/polymorphic/ctor_poly.cc226
-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.cc232
-rw-r--r--libstdc++-v3/testsuite/std/memory/polymorphic/move_alloc.cc333
-rw-r--r--libstdc++-v3/testsuite/std/memory/start_lifetime_as/start_lifetime_as.cc94
-rw-r--r--libstdc++-v3/testsuite/std/ranges/adaptors/adjacent/1.cc13
-rw-r--r--libstdc++-v3/testsuite/std/ranges/adaptors/adjacent_transform/1.cc41
-rw-r--r--libstdc++-v3/testsuite/std/ranges/adaptors/drop.cc2
-rw-r--r--libstdc++-v3/testsuite/std/ranges/adaptors/join.cc20
-rw-r--r--libstdc++-v3/testsuite/std/ranges/adaptors/join_with/1.cc8
-rw-r--r--libstdc++-v3/testsuite/std/ranges/adaptors/lazy_split.cc8
-rw-r--r--libstdc++-v3/testsuite/std/ranges/adaptors/take.cc15
-rw-r--r--libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc178
-rw-r--r--libstdc++-v3/testsuite/std/ranges/concat/1.cc13
-rw-r--r--libstdc++-v3/testsuite/std/ranges/indices/1.cc45
-rw-r--r--libstdc++-v3/testsuite/std/ranges/iota/max_size_type.cc38
-rw-r--r--libstdc++-v3/testsuite/std/ranges/zip_transform/1.cc97
-rw-r--r--libstdc++-v3/testsuite/std/time/clock/local/io.cc11
-rw-r--r--libstdc++-v3/testsuite/std/time/format/custom_rep.h92
-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.cc841
-rw-r--r--libstdc++-v3/testsuite/std/time/format/format.cc8
-rw-r--r--libstdc++-v3/testsuite/std/time/format/nonlocking.cc164
-rw-r--r--libstdc++-v3/testsuite/std/time/format/pr117214.cc43
-rw-r--r--libstdc++-v3/testsuite/std/time/format/pr117214_custom_timeput.cc37
-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/std/time/hash.cc280
-rw-r--r--libstdc++-v3/testsuite/std/time/month/io.cc7
-rw-r--r--libstdc++-v3/testsuite/std/time/month_day/io.cc41
-rw-r--r--libstdc++-v3/testsuite/std/time/month_day_last/io.cc42
-rw-r--r--libstdc++-v3/testsuite/std/time/month_weekday/io.cc42
-rw-r--r--libstdc++-v3/testsuite/std/time/month_weekday_last/io.cc42
-rw-r--r--libstdc++-v3/testsuite/std/time/parse/parse.cc2
-rw-r--r--libstdc++-v3/testsuite/std/time/weekday/io.cc2
-rw-r--r--libstdc++-v3/testsuite/std/time/weekday_indexed/io.cc42
-rw-r--r--libstdc++-v3/testsuite/std/time/weekday_last/io.cc42
-rw-r--r--libstdc++-v3/testsuite/std/time/year_month/io.cc41
-rw-r--r--libstdc++-v3/testsuite/std/time/year_month_day/io.cc91
-rw-r--r--libstdc++-v3/testsuite/std/time/year_month_day_last/io.cc82
-rw-r--r--libstdc++-v3/testsuite/std/time/year_month_weekday/io.cc148
-rw-r--r--libstdc++-v3/testsuite/std/time/year_month_weekday_last/io.cc98
-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/checks.h37
-rw-r--r--libstdc++-v3/testsuite/util/exception/safety.h1
-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.h115
-rw-r--r--libstdc++-v3/testsuite/util/testsuite_common_types.h16
-rw-r--r--libstdc++-v3/testsuite/util/testsuite_containers.h10
-rw-r--r--libstdc++-v3/testsuite/util/testsuite_error.h7
-rw-r--r--libstdc++-v3/testsuite/util/testsuite_greedy_ops.h2
-rw-r--r--libstdc++-v3/testsuite/util/testsuite_hooks.h17
-rw-r--r--libstdc++-v3/testsuite/util/testsuite_iterators.h198
-rw-r--r--libstdc++-v3/testsuite/util/testsuite_new_operators.h1
-rw-r--r--libstdc++-v3/testsuite/util/testsuite_random.h1
669 files changed, 35011 insertions, 1749 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/headers/c++1998/stdc++_assert_neg.cc b/libstdc++-v3/testsuite/17_intro/headers/c++1998/stdc++_assert_neg.cc
index eb380c4..7ce90a2 100644
--- a/libstdc++-v3/testsuite/17_intro/headers/c++1998/stdc++_assert_neg.cc
+++ b/libstdc++-v3/testsuite/17_intro/headers/c++1998/stdc++_assert_neg.cc
@@ -1,8 +1,5 @@
// { dg-do compile }
-// { dg-options "-D_GLIBCXX_NO_ASSERT" }
// { dg-require-effective-target hosted }
-// NB: This is done to force any generated and possibly included PCH
-// to be invalid, and also to remove cassert from the include set.
// 2005-05-24 bkoz
diff --git a/libstdc++-v3/testsuite/17_intro/headers/c++2011/42319.cc b/libstdc++-v3/testsuite/17_intro/headers/c++2011/42319.cc
index cd576ca..350a548 100644
--- a/libstdc++-v3/testsuite/17_intro/headers/c++2011/42319.cc
+++ b/libstdc++-v3/testsuite/17_intro/headers/c++2011/42319.cc
@@ -1,5 +1,5 @@
// { dg-do compile }
-// { dg-options "-std=gnu++11" }
+// { dg-add-options no_pch }
// Copyright (C) 2009-2025 Free Software Foundation, Inc.
//
@@ -19,4 +19,4 @@
// <http://www.gnu.org/licenses/>.
// libstdc++/42319
-#include <bits/char_traits.h>
+#include <ios>
diff --git a/libstdc++-v3/testsuite/17_intro/names.cc b/libstdc++-v3/testsuite/17_intro/names.cc
index f67818d..befb5aa 100644
--- a/libstdc++-v3/testsuite/17_intro/names.cc
+++ b/libstdc++-v3/testsuite/17_intro/names.cc
@@ -248,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
@@ -282,6 +286,8 @@
// <sys/ucontext.h> defines fpreg_t::d and fpreg_t::f
#undef d
#undef f
+// <asm/types.h> defines __vector128::u
+#undef u
#endif
#if defined (__linux__) && defined (__sparc__)
@@ -323,6 +329,7 @@
#ifdef __sun__
// <fenv.h> defines these as members of fex_numeric_t
+#undef i
#undef l
#undef f
#undef d
@@ -332,8 +339,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__
@@ -396,4 +406,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/categories/zero_neg.cc b/libstdc++-v3/testsuite/18_support/comparisons/categories/zero_neg.cc
index 2e6b9c1..ce0ca8e 100644
--- a/libstdc++-v3/testsuite/18_support/comparisons/categories/zero_neg.cc
+++ b/libstdc++-v3/testsuite/18_support/comparisons/categories/zero_neg.cc
@@ -23,6 +23,16 @@
// C++20 [cmp.categories.pre]
// "an argument other than a literal 0 is undefined"
+struct PtrConv
+{
+ template<typename T>
+ consteval operator T*()
+ { return nullptr; }
+
+ consteval operator std::nullptr_t()
+ { return nullptr; }
+};
+
void
test01()
{
@@ -48,6 +58,12 @@ test01()
std::partial_ordering::equivalent == nullptr;
std::weak_ordering::equivalent == nullptr;
std::strong_ordering::equivalent == nullptr;
+
+ constexpr PtrConv c;
+ // requires two user-defined conversion
+ std::partial_ordering::equivalent == c; // { dg-error "no match for 'operator=='" }
+ std::weak_ordering::equivalent == c; // { dg-error "no match for 'operator=='" }
+ std::strong_ordering::equivalent == c; // { dg-error "no match for 'operator=='" }
}
// { dg-prune-output "reinterpret_cast.* is not a constant expression" }
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/version.cc b/libstdc++-v3/testsuite/18_support/exception/version.cc
new file mode 100644
index 0000000..5707abd
--- /dev/null
+++ b/libstdc++-v3/testsuite/18_support/exception/version.cc
@@ -0,0 +1,9 @@
+// { dg-do preprocess { target c++26 } }
+// { dg-add-options no_pch }
+
+#include <exception>
+
+#ifdef __cpp_lib_constexpr_exceptions
+# error "Feature test macro for constexpr_exceptions should not be provided by <exception>"
+#endif
+
diff --git a/libstdc++-v3/testsuite/18_support/exception_ptr/62258.cc b/libstdc++-v3/testsuite/18_support/exception_ptr/62258.cc
index 0a4d092..a49f347 100644
--- a/libstdc++-v3/testsuite/18_support/exception_ptr/62258.cc
+++ b/libstdc++-v3/testsuite/18_support/exception_ptr/62258.cc
@@ -1,4 +1,4 @@
-// { dg-options "-Wno-deprecated" }
+// { dg-options "-Wno-deprecated-declarations" }
// { dg-do run { target c++11 } }
// Copyright (C) 2015-2025 Free Software Foundation, Inc.
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..de371d1
--- /dev/null
+++ b/libstdc++-v3/testsuite/18_support/exception_ptr/exception_ptr_cast.cc
@@ -0,0 +1,92 @@
+// { 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; constexpr virtual ~E () {} };
+struct F : virtual E, virtual C { int f; };
+struct G : virtual F, virtual C, virtual E {
+ constexpr G () : g (4) { a = 1; e = 2; f = 3; } int g;
+};
+
+constexpr bool test01(bool x)
+{
+ 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 );
+ }
+ if (x)
+ throw 1;
+ return true;
+}
+
+static_assert(test01(false));
+
+int main()
+{
+ try
+ {
+ test01(true);
+ }
+ catch (...)
+ {
+ }
+}
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/18_support/headers/climits/values.cc b/libstdc++-v3/testsuite/18_support/headers/climits/values.cc
index ac13f9f..bf38369 100644
--- a/libstdc++-v3/testsuite/18_support/headers/climits/values.cc
+++ b/libstdc++-v3/testsuite/18_support/headers/climits/values.cc
@@ -49,4 +49,12 @@ namespace gnu
unsigned short us = USHRT_MAX;
unsigned long ul = ULONG_MAX;
+#if __cplusplus >= 201103L
+ // long long
+ long long ll1 = LLONG_MIN;
+ long long ll2 = LLONG_MAX;
+
+ // unsigned long long
+ unsigned long long ull1 = ULLONG_MAX;
+#endif
}
diff --git a/libstdc++-v3/testsuite/18_support/headers/csignal/macros.cc b/libstdc++-v3/testsuite/18_support/headers/csignal/macros.cc
index 6d6c821..1076cbc 100644
--- a/libstdc++-v3/testsuite/18_support/headers/csignal/macros.cc
+++ b/libstdc++-v3/testsuite/18_support/headers/csignal/macros.cc
@@ -37,6 +37,10 @@ namespace gnu
#error "SIG_DFL_must_be_a_macro"
#endif
+#ifndef SIG_IGN
+ #error "SIG_IGN_must_be_a_macro"
+#endif
+
#ifndef SIGFPE
#error "SIGFPE_must_be_a_macro"
#endif
diff --git a/libstdc++-v3/testsuite/18_support/headers/new/synopsis.cc b/libstdc++-v3/testsuite/18_support/headers/new/synopsis.cc
index ee61f91..6d8f4cd 100644
--- a/libstdc++-v3/testsuite/18_support/headers/new/synopsis.cc
+++ b/libstdc++-v3/testsuite/18_support/headers/new/synopsis.cc
@@ -53,8 +53,8 @@ void operator delete[](void* ptr, const std::nothrow_t&) throw();
#endif
CXX26_CONSTEXPR void* operator new (std::size_t size, void* ptr) throw();
CXX26_CONSTEXPR void* operator new[](std::size_t size, void* ptr) throw();
-void operator delete (void* ptr, void*) throw();
-void operator delete[](void* ptr, void*) throw();
+CXX26_CONSTEXPR void operator delete (void* ptr, void*) throw();
+CXX26_CONSTEXPR void operator delete[](void* ptr, void*) throw();
#if __cplusplus >= 201402L
// C++14 sized deallocation functions
diff --git a/libstdc++-v3/testsuite/18_support/numeric_limits/128bit.cc b/libstdc++-v3/testsuite/18_support/numeric_limits/128bit.cc
index b13d837..bf12b65 100644
--- a/libstdc++-v3/testsuite/18_support/numeric_limits/128bit.cc
+++ b/libstdc++-v3/testsuite/18_support/numeric_limits/128bit.cc
@@ -4,6 +4,11 @@
#if __SIZEOF_FLOAT128__
__extension__ template class std::numeric_limits<__float128>;
+
+# if __cplusplus >= 201103L
+static_assert( std::numeric_limits<__float128>::max_digits10 == 36,
+ "PR libstdc++/121374" );
+# endif
#endif
#if __SIZEOF_INT128__
diff --git a/libstdc++-v3/testsuite/18_support/uncaught_exception/14026.cc b/libstdc++-v3/testsuite/18_support/uncaught_exception/14026.cc
index 58f241b..7f41c80 100644
--- a/libstdc++-v3/testsuite/18_support/uncaught_exception/14026.cc
+++ b/libstdc++-v3/testsuite/18_support/uncaught_exception/14026.cc
@@ -18,7 +18,7 @@
// PR 14026
// 18.6.4 uncaught_exception
-// { dg-options "-Wno-deprecated" }
+// { dg-options "-Wno-deprecated-declarations" }
#include <cstdlib>
#include <exception>
diff --git a/libstdc++-v3/testsuite/19_diagnostics/debugging/breakpoint.cc b/libstdc++-v3/testsuite/19_diagnostics/debugging/breakpoint.cc
new file mode 100644
index 0000000..ad24177
--- /dev/null
+++ b/libstdc++-v3/testsuite/19_diagnostics/debugging/breakpoint.cc
@@ -0,0 +1,13 @@
+// { dg-do run { target c++26 xfail c++26 } }
+// { dg-options "-lstdc++exp" }
+// { dg-require-cpp-feature-test __cpp_lib_debugging }
+#include <debugging>
+#include <type_traits>
+
+static_assert( noexcept(std::breakpoint()) );
+static_assert( std::is_void_v<decltype(std::breakpoint())> );
+
+int main()
+{
+ std::breakpoint();
+}
diff --git a/libstdc++-v3/testsuite/19_diagnostics/debugging/breakpoint_if_debugging.cc b/libstdc++-v3/testsuite/19_diagnostics/debugging/breakpoint_if_debugging.cc
new file mode 100644
index 0000000..2646183
--- /dev/null
+++ b/libstdc++-v3/testsuite/19_diagnostics/debugging/breakpoint_if_debugging.cc
@@ -0,0 +1,13 @@
+// { dg-do run { target c++26 } }
+// { dg-options "-lstdc++exp" }
+// { dg-require-cpp-feature-test __cpp_lib_debugging }
+#include <debugging>
+#include <type_traits>
+
+static_assert( noexcept(std::breakpoint_if_debugging()) );
+static_assert( std::is_void_v<decltype(std::breakpoint_if_debugging())> );
+
+int main()
+{
+ std::breakpoint_if_debugging();
+}
diff --git a/libstdc++-v3/testsuite/19_diagnostics/debugging/is_debugger_present-2.cc b/libstdc++-v3/testsuite/19_diagnostics/debugging/is_debugger_present-2.cc
new file mode 100644
index 0000000..aa4690c
--- /dev/null
+++ b/libstdc++-v3/testsuite/19_diagnostics/debugging/is_debugger_present-2.cc
@@ -0,0 +1,19 @@
+// { dg-do run { target c++26 } }
+// { dg-options "-lstdc++exp" }
+// { dg-require-cpp-feature-test __cpp_lib_debugging }
+// { dg-xfail-run-if "no replaceable functions on AIX" { powerpc-ibm-aix* } }
+
+// P2810R4 is_debugger_present is_replaceable
+
+#include <debugging>
+#include <testsuite_hooks.h>
+
+bool called = false;
+
+bool std::is_debugger_present() noexcept { called = true; return true; }
+
+int main()
+{
+ VERIFY( std::is_debugger_present() );
+ VERIFY( called );
+}
diff --git a/libstdc++-v3/testsuite/19_diagnostics/debugging/is_debugger_present.cc b/libstdc++-v3/testsuite/19_diagnostics/debugging/is_debugger_present.cc
new file mode 100644
index 0000000..8dbfa69
--- /dev/null
+++ b/libstdc++-v3/testsuite/19_diagnostics/debugging/is_debugger_present.cc
@@ -0,0 +1,14 @@
+// { dg-do run { target c++26 } }
+// { dg-options "-lstdc++exp" }
+// { dg-require-cpp-feature-test __cpp_lib_debugging }
+#include <debugging>
+#include <type_traits>
+#include <testsuite_hooks.h>
+
+static_assert( noexcept(std::is_debugger_present()) );
+static_assert( std::is_same_v<decltype(std::is_debugger_present()), bool> );
+
+int main()
+{
+ VERIFY( ! std::is_debugger_present() );
+}
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/allocator_traits/members/allocate_hint.cc b/libstdc++-v3/testsuite/20_util/allocator_traits/members/allocate_hint.cc
index 214be6a..94c3fbd 100644
--- a/libstdc++-v3/testsuite/20_util/allocator_traits/members/allocate_hint.cc
+++ b/libstdc++-v3/testsuite/20_util/allocator_traits/members/allocate_hint.cc
@@ -74,7 +74,7 @@ void test02()
{
typedef std::allocator_traits<unhintable_allocator<X>> traits_type;
traits_type::allocator_type a;
- traits_type::const_void_pointer v;
+ traits_type::const_void_pointer v = nullptr;
X* p __attribute__((unused)) = traits_type::allocate(a, 1, v);
VERIFY( a.called );
}
diff --git a/libstdc++-v3/testsuite/20_util/allocator_traits/members/allocate_hint_nonpod.cc b/libstdc++-v3/testsuite/20_util/allocator_traits/members/allocate_hint_nonpod.cc
index 32bbf2b..c305b67 100644
--- a/libstdc++-v3/testsuite/20_util/allocator_traits/members/allocate_hint_nonpod.cc
+++ b/libstdc++-v3/testsuite/20_util/allocator_traits/members/allocate_hint_nonpod.cc
@@ -58,7 +58,7 @@ void test01()
{
typedef std::allocator_traits<Alloc<int>> traits_type;
traits_type::allocator_type a;
- traits_type::const_void_pointer v;
+ traits_type::const_void_pointer v = nullptr;
traits_type::pointer p = traits_type::allocate(a, 1, v);
traits_type::deallocate(a, p, 1);
}
diff --git a/libstdc++-v3/testsuite/20_util/any/misc/any_cast_neg.cc b/libstdc++-v3/testsuite/20_util/any/misc/any_cast_neg.cc
index 9740e09..9e5c64c 100644
--- a/libstdc++-v3/testsuite/20_util/any/misc/any_cast_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/any/misc/any_cast_neg.cc
@@ -27,6 +27,7 @@ void test01()
const any y(1);
any_cast<int&>(y); // { dg-error "here" }
// { dg-error "Template argument must be constructible from a const value" "" { target { *-*-* } } 0 }
+ // { dg-error "binding reference of type 'int&' to 'const int' discards qualifiers" "" { target { *-*-* } } 0 }
}
void test02()
@@ -34,6 +35,7 @@ void test02()
any y(1);
any_cast<int&&>(y); // { dg-error "here" }
// { dg-error "Template argument must be constructible from an lvalue" "" { target { *-*-* } } 0 }
+ // { dg-error "cannot bind rvalue reference of type 'int&&' to lvalue of type 'int'" "" { target { *-*-* } } 0 }
}
void test03()
@@ -41,6 +43,7 @@ void test03()
any y(1);
any_cast<int&>(std::move(y)); // { dg-error "here" }
// { dg-error "Template argument must be constructible from an rvalue" "" { target { *-*-* } } 0 }
+ // { dg-error "cannot bind non-const lvalue reference of type 'int&' to an rvalue of type 'int'" "" { target { *-*-* } } 0 }
}
// { dg-prune-output "invalid 'static_cast'" }
diff --git a/libstdc++-v3/testsuite/20_util/bind/80564.cc b/libstdc++-v3/testsuite/20_util/bind/80564.cc
new file mode 100644
index 0000000..f6e1a1e
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/bind/80564.cc
@@ -0,0 +1,50 @@
+// PR libstdc++/80564 - bind on SFINAE unfriendly generic lambda
+// { dg-do compile { target c++14 } }
+
+#include <functional>
+
+struct A
+{
+ template<typename T>
+ auto operator()(T&)
+ { }
+
+ template<typename T>
+ auto operator()(T&) const
+ { T::fail; }
+};
+
+void
+test01()
+{
+ A a;
+ std::bind(a, 0)(); // doesn't consider the const overload
+ std::bind<void>(a, 0)();
+}
+
+void
+test02()
+{
+ auto f = [] (auto& x) { x = 1; };
+ int i;
+ std::bind(f, i)(); // doesn't try const-invoking the lambda
+ std::bind<void>(f, i)();
+}
+
+#if __cpp_variadic_using
+template<typename... Ts>
+struct overloaded : private Ts...
+{
+ overloaded(Ts... ts) : Ts(ts)... { }
+ using Ts::operator()...;
+};
+
+void
+test03()
+{
+ A a;
+ auto f = std::bind(a, 0);
+ overloaded<decltype(f)> g(f);
+ g();
+}
+#endif
diff --git a/libstdc++-v3/testsuite/20_util/bind/cv_quals_2.cc b/libstdc++-v3/testsuite/20_util/bind/cv_quals_2.cc
index e4c348f..6d37cc4 100644
--- a/libstdc++-v3/testsuite/20_util/bind/cv_quals_2.cc
+++ b/libstdc++-v3/testsuite/20_util/bind/cv_quals_2.cc
@@ -44,6 +44,9 @@ void test01()
// { dg-error "no match" "" { target c++20 } 43 }
}
+// Ignore the reasons for deduction/substitution failure in the headers.
+// { dg-prune-output "no type named 'type' in 'struct std::enable_if<false" }
+
int main()
{
test01();
diff --git a/libstdc++-v3/testsuite/20_util/bind/dangling_ref.cc b/libstdc++-v3/testsuite/20_util/bind/dangling_ref.cc
index 17e7b21..32af0a2 100644
--- a/libstdc++-v3/testsuite/20_util/bind/dangling_ref.cc
+++ b/libstdc++-v3/testsuite/20_util/bind/dangling_ref.cc
@@ -1,4 +1,5 @@
// { dg-do compile { target c++11 } }
+// { dg-additional-options "-Wsystem-headers" }
#include <functional>
int f();
diff --git a/libstdc++-v3/testsuite/20_util/bind/ref_neg.cc b/libstdc++-v3/testsuite/20_util/bind/ref_neg.cc
index dd47c43..46cc4bb 100644
--- a/libstdc++-v3/testsuite/20_util/bind/ref_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/bind/ref_neg.cc
@@ -51,6 +51,7 @@ void test02()
// Ignore the reasons for deduction/substitution failure in the headers.
// Arrange for the match to work on installed trees as well as build trees.
// { dg-prune-output "no type named 'type' in 'struct std::__invoke_result" }
+// { dg-prune-output "no type named 'type' in 'struct std::enable_if<false" }
int main()
{
diff --git a/libstdc++-v3/testsuite/20_util/bitset/121054.cc b/libstdc++-v3/testsuite/20_util/bitset/121054.cc
new file mode 100644
index 0000000..0e8f32d
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/bitset/121054.cc
@@ -0,0 +1,233 @@
+// { dg-do run }
+
+// PR libstdc++/121054 std::bitset<0>("zero") should throw std::invalid_argument
+#include <bitset>
+#include <stdexcept>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+ try {
+ std::bitset<0>(std::string("x"));
+ VERIFY( false );
+ }
+ catch(std::invalid_argument& fail) {
+ VERIFY( true );
+ }
+ catch(...) {
+ VERIFY( false );
+ }
+
+ try {
+ std::bitset<1>(std::string("0x"));
+ VERIFY( false );
+ }
+ catch(std::invalid_argument& fail) {
+ VERIFY( true );
+ }
+ catch(...) {
+ VERIFY( false );
+ }
+
+ try {
+ std::bitset<0>(std::string("01"));
+ VERIFY( true );
+ }
+ catch(std::invalid_argument& fail) {
+ VERIFY( false );
+ }
+ catch(...) {
+ VERIFY( false );
+ }
+
+ try {
+ std::bitset<1>(std::string("x0"), 1);
+ VERIFY( true );
+ }
+ catch(std::invalid_argument& fail) {
+ VERIFY( false );
+ }
+ catch(...) {
+ VERIFY( false );
+ }
+
+#if _GLIBCXX_USE_C99_WCHAR
+ try {
+ std::bitset<1>(std::wstring(L"0x"));
+ VERIFY( false );
+ }
+ catch(std::invalid_argument& fail) {
+ VERIFY( true );
+ }
+ catch(...) {
+ VERIFY( false );
+ }
+
+ try {
+ std::bitset<1>(std::wstring(L"x0"), 1);
+ VERIFY( true );
+ }
+ catch(std::invalid_argument& fail) {
+ VERIFY( false );
+ }
+ catch(...) {
+ VERIFY( false );
+ }
+#endif
+}
+
+void
+test02()
+{
+#if __cplusplus >= 201103L
+ try {
+ std::bitset<0>("x");
+ VERIFY( false );
+ }
+ catch(std::invalid_argument& fail) {
+ VERIFY( true );
+ }
+ catch(...) {
+ VERIFY( false );
+ }
+
+ try {
+ std::bitset<1>("0x", 2);
+ VERIFY( false );
+ }
+ catch(std::invalid_argument& fail) {
+ VERIFY( true );
+ }
+ catch(...) {
+ VERIFY( false );
+ }
+
+ try {
+ std::bitset<1>("0x", 1);
+ VERIFY( true );
+ }
+ catch(std::invalid_argument& fail) {
+ VERIFY( false );
+ }
+ catch(...) {
+ VERIFY( false );
+ }
+
+ try {
+ std::bitset<0>("01");
+ VERIFY( true );
+ }
+ catch(std::invalid_argument& fail) {
+ VERIFY( false );
+ }
+ catch(...) {
+ VERIFY( false );
+ }
+
+#if _GLIBCXX_USE_C99_WCHAR
+ try {
+ std::bitset<1>(L"0x", 2);
+ VERIFY( false );
+ }
+ catch(std::invalid_argument& fail) {
+ VERIFY( true );
+ }
+ catch(...) {
+ VERIFY( false );
+ }
+
+ try {
+ std::bitset<1>(L"0x", 1);
+ VERIFY( true );
+ }
+ catch(std::invalid_argument& fail) {
+ VERIFY( false );
+ }
+ catch(...) {
+ VERIFY( false );
+ }
+#endif
+#endif
+}
+
+void
+test03()
+{
+#if __cpp_lib_bitset >= 202202L
+ try {
+ std::bitset<0>(std::string_view("x"));
+ VERIFY( false );
+ }
+ catch(std::invalid_argument& fail) {
+ VERIFY( true );
+ }
+ catch(...) {
+ VERIFY( false );
+ }
+
+ try {
+ std::bitset<1>(std::string_view("0x"));
+ VERIFY( false );
+ }
+ catch(std::invalid_argument& fail) {
+ VERIFY( true );
+ }
+ catch(...) {
+ VERIFY( false );
+ }
+
+ try {
+ std::bitset<0>(std::string_view("01"));
+ VERIFY( true );
+ }
+ catch(std::invalid_argument& fail) {
+ VERIFY( false );
+ }
+ catch(...) {
+ VERIFY( false );
+ }
+
+ try {
+ std::bitset<1>(std::string_view("x0"), 1);
+ VERIFY( true );
+ }
+ catch(std::invalid_argument& fail) {
+ VERIFY( false );
+ }
+ catch(...) {
+ VERIFY( false );
+ }
+
+#if _GLIBCXX_USE_C99_WCHAR
+ try {
+ std::bitset<1>(std::wstring_view(L"0x"));
+ VERIFY( false );
+ }
+ catch(std::invalid_argument& fail) {
+ VERIFY( true );
+ }
+ catch(...) {
+ VERIFY( false );
+ }
+
+ try {
+ std::bitset<1>(std::wstring_view(L"x0"), 1);
+ VERIFY( true );
+ }
+ catch(std::invalid_argument& fail) {
+ VERIFY( false );
+ }
+ catch(...) {
+ VERIFY( false );
+ }
+#endif
+#endif
+}
+
+int main()
+{
+ test01();
+ test02();
+ test03();
+}
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/constexpr_c++23.cc b/libstdc++-v3/testsuite/20_util/bitset/cons/constexpr_c++23.cc
index 7e2eba5..0a94094 100644
--- a/libstdc++-v3/testsuite/20_util/bitset/cons/constexpr_c++23.cc
+++ b/libstdc++-v3/testsuite/20_util/bitset/cons/constexpr_c++23.cc
@@ -18,8 +18,6 @@ constexpr bool test_ntbs()
VERIFY( std::bitset<0>("000").all() );
VERIFY( std::bitset<0>("000", 2).all() );
VERIFY( std::bitset<1>("100", 2).all() );
- VERIFY( std::bitset<1>("z00", 2, 'z').none() );
- VERIFY( std::bitset<2>("ab0", 3, 'a', 'b').count() == 1 );
return true;
}
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/common_reference/p2655r3.cc b/libstdc++-v3/testsuite/20_util/common_reference/p2655r3.cc
new file mode 100644
index 0000000..4188dd2
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/common_reference/p2655r3.cc
@@ -0,0 +1,15 @@
+// P2655R3 - common_reference_t of reference_wrapper Should Be a Reference Type
+// Implemented as a DR against C++20
+// { dg-do compile { target c++20 } }
+
+#include <type_traits>
+
+#if __cpp_lib_common_reference != 202302L
+# error "Feature-test macro __cpp_lib_common_reference has wrong value in <type_traits>"
+#endif
+
+struct A { };
+struct B { operator A&() const; };
+
+static_assert( std::is_same_v<std::common_reference_t<A&, const B&>, A&> );
+static_assert( std::is_same_v<std::common_reference_t<const B&, A&>, A&> );
diff --git a/libstdc++-v3/testsuite/20_util/constant_wrapper/adl.cc b/libstdc++-v3/testsuite/20_util/constant_wrapper/adl.cc
new file mode 100644
index 0000000..3cdc09c
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/constant_wrapper/adl.cc
@@ -0,0 +1,86 @@
+// { dg-do compile { target c++26 } }
+#include <type_traits>
+#include <concepts>
+
+#include <testsuite_hooks.h>
+
+namespace adl {
+
+struct Friend
+{};
+
+constexpr
+int operator+(Friend, int x)
+{ return x; };
+
+template<typename T>
+ struct TemplFriend
+ { };
+
+template<typename T>
+ constexpr
+ // templated, we cannot deduce T from cw<Friend<int>>
+ int operator+(TemplFriend<T>, int x)
+ { return x; };
+
+
+struct HiddenFriend
+{
+ constexpr friend
+ int operator+(HiddenFriend, int x)
+ { return x; }
+};
+
+template<typename T>
+ struct TemplHiddenFriend
+ {
+ constexpr friend
+ // note that this not not template itself
+ int operator+(TemplHiddenFriend, int x)
+ { return x; }
+ };
+}
+
+template<typename T>
+ concept supportMixedObj = requires
+ {
+ { std::cw<T{}> + 1 } -> std::same_as<int>;
+ };
+
+template<typename T>
+ concept supportMixedInt = requires(T t)
+ {
+ { t + std::cw<1> } -> std::same_as<int>;
+ };
+
+static_assert(supportMixedObj<adl::Friend>);
+static_assert(supportMixedInt<adl::Friend>);
+static_assert(!supportMixedObj<adl::TemplFriend<int>>);
+static_assert(supportMixedInt<adl::TemplFriend<int>>);
+
+static_assert(supportMixedObj<adl::HiddenFriend>);
+static_assert(supportMixedInt<adl::HiddenFriend>);
+static_assert(supportMixedObj<adl::TemplHiddenFriend<int>>);
+static_assert(supportMixedInt<adl::TemplHiddenFriend<int>>);
+
+struct Member
+{
+ constexpr
+ // conversion for the first argument is not allowed
+ int operator+(int x) const
+ { return x; }
+};
+
+static_assert(!supportMixedObj<Member>);
+static_assert(supportMixedInt<Member>);
+
+struct ExplicitThisMember
+{
+ constexpr
+ // conversion for the first argument is not allowed
+ int operator+(this ExplicitThisMember, int x)
+ { return x; }
+};
+
+static_assert(!supportMixedObj<ExplicitThisMember>);
+static_assert(supportMixedInt<ExplicitThisMember>);
diff --git a/libstdc++-v3/testsuite/20_util/constant_wrapper/ex.cc b/libstdc++-v3/testsuite/20_util/constant_wrapper/ex.cc
new file mode 100644
index 0000000..a4d967b
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/constant_wrapper/ex.cc
@@ -0,0 +1,39 @@
+// { dg-do compile { target c++26 } }
+#include <type_traits>
+#include <iostream>
+
+#include <testsuite_hooks.h>
+
+constexpr auto
+initial_phase(auto quantity_1, auto quantity_2)
+{ return quantity_1 + quantity_2; }
+
+constexpr auto
+middle_phase(auto tbd)
+{ return tbd; }
+
+constexpr void
+final_phase(auto gathered, auto available)
+{
+ if constexpr (gathered == available)
+ std::cout << "Profit!\n";
+}
+
+void
+impeccable_underground_planning()
+{
+ auto gathered_quantity = middle_phase(initial_phase(std::cw<42>, std::cw<13>));
+ static_assert(gathered_quantity == 55);
+ auto all_available = std::cw<55>;
+ final_phase(gathered_quantity, all_available);
+}
+
+void
+deeply_flawed_underground_planning()
+{
+ constexpr auto gathered_quantity = middle_phase(initial_phase(42, 13));
+ constexpr auto all_available = 55;
+ final_phase(gathered_quantity, all_available); // { dg-error "required from here" }
+}
+
+// { dg-prune-output "'gathered' is not a constant expression" }
diff --git a/libstdc++-v3/testsuite/20_util/constant_wrapper/generic.cc b/libstdc++-v3/testsuite/20_util/constant_wrapper/generic.cc
new file mode 100644
index 0000000..f632f8e
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/constant_wrapper/generic.cc
@@ -0,0 +1,391 @@
+// { dg-do run { target c++26 } }
+#include <type_traits>
+#include <utility>
+#include <string_view>
+
+#include <testsuite_hooks.h>
+
+constexpr void
+check_same(auto actual, auto expected)
+{
+ VERIFY(actual == expected);
+ static_assert(std::same_as<decltype(actual), decltype(expected)>);
+};
+
+
+constexpr void
+test_c_arrays()
+{
+ constexpr double x[] = {1.1, 2.2, 3.3};
+ auto cx = std::cw<x>;
+ auto access = [](auto x, size_t i)
+ { return x[i]; };
+
+ check_same(access(std::cw<x>, 0), x[0]);
+ check_same(access(std::cw<x>, 1), x[1]);
+ check_same(access(std::cw<x>, 2), x[2]);
+
+ check_same(cx[std::cw<0>], std::cw<x[0]>);
+ check_same(cx[std::cw<1>], std::cw<x[1]>);
+ check_same(cx[std::cw<2>], std::cw<x[2]>);
+}
+
+constexpr size_t
+deduce_cstr_size(auto str)
+{
+ size_t sz = 0;
+ while(str[sz++] != '\0') { }
+ return sz;
+}
+
+constexpr void
+test_string_literals()
+{
+ auto foo = std::cw<"foo">;
+ constexpr const typename decltype(foo)::value_type & cstr = foo;
+ constexpr size_t N = std::size(cstr);
+ constexpr auto foo_view = std::string_view(cstr, N-1);
+
+ constexpr const char (&cstr1)[deduce_cstr_size(foo)] = foo;
+ constexpr size_t N1 = std::size(cstr);
+
+ static_assert(static_cast<char const*>(cstr) ==
+ static_cast<char const*>(cstr1));
+ static_assert(N1 == N);
+
+ static_assert(foo[0] == 'f');
+ static_assert(foo[1] == 'o');
+ static_assert(foo[2] == 'o');
+ static_assert(foo[3] == '\0');
+ static_assert(static_cast<char const *>(foo) == foo_view);
+}
+
+constexpr bool
+convert_constexpr(auto c)
+{
+ if constexpr (int(c) > 0)
+ return true;
+ return false;
+}
+
+constexpr void
+test_converted_constexpr()
+{
+ VERIFY(!convert_constexpr(std::cw<-1>));
+ VERIFY(convert_constexpr(std::cw<1>));
+}
+
+constexpr void
+test_ints()
+{
+ std::constant_wrapper<2> two;
+ std::constant_wrapper<3> three;
+ std::constant_wrapper<5> five;
+
+ VERIFY(two + 3 == 5);
+ static_assert(std::same_as<decltype(two + 3), int>);
+
+ VERIFY(two + three == 5);
+ VERIFY(two + three == five);
+ static_assert(std::same_as<decltype(two + three), std::constant_wrapper<5>>);
+
+ VERIFY(two == std::cw<2>);
+ VERIFY(two + 3 == std::cw<5>);
+}
+
+constexpr int
+add(int i, int j)
+{ return i + j; }
+
+struct Add
+{
+ constexpr int
+ operator()(int i, int j) const noexcept
+ { return i + j; }
+};
+
+constexpr void
+test_function_object()
+{
+ auto check = [](auto cfo)
+ {
+ auto ci = std::cw<2>;
+ auto cj = std::cw<3>;
+
+ VERIFY(cfo(ci, cj) == 5);
+ static_assert(std::same_as<decltype(cfo(ci, cj)), std::constant_wrapper<5>>);
+
+ static_assert(std::invocable<decltype(cfo), decltype(ci), decltype(cj)>);
+ static_assert(!std::invocable<decltype(cfo), int, decltype(cj)>);
+ static_assert(!std::invocable<decltype(cfo), int, int>);
+ };
+
+ check(std::cw<Add{}>);
+ check(std::cw<[](int i, int j){ return i + j; }>);
+ check(std::cw<[](auto i, auto j){ return i + j; }>);
+}
+
+constexpr void
+test_function_pointer()
+{
+ auto cptr = std::cw<add>;
+ auto ci = std::cw<2>;
+ auto cj = std::cw<3>;
+
+ VERIFY(cptr(ci, cj) == 5);
+ static_assert(std::same_as<decltype(cptr(ci, cj)), std::constant_wrapper<5>>);
+
+ VERIFY(cptr(2, cj) == 5);
+ static_assert(std::same_as<decltype(cptr(2, cj)), int>);
+
+ VERIFY(cptr(2, 3) == 5);
+ static_assert(std::same_as<decltype(cptr(2, 3)), int>);
+}
+
+struct Indexable1
+{
+ constexpr int
+ operator[](int i, int j) const noexcept
+ { return i*j; }
+};
+
+template<typename Obj, typename... Args>
+ concept indexable = requires (Obj obj, Args... args)
+ {
+ obj[args...];
+ };
+
+constexpr void
+test_indexable1()
+{
+ auto cind = std::cw<Indexable1{}>;
+ auto ci = std::cw<2>;
+ auto cj = std::cw<3>;
+ VERIFY(cind[ci, cj] == ci*cj);
+ static_assert(std::same_as<decltype(cind[ci, cj]), std::constant_wrapper<6>>);
+
+ static_assert(indexable<decltype(cind), decltype(ci), decltype(cj)>);
+ static_assert(!indexable<decltype(cind), int, decltype(cj)>);
+ static_assert(!indexable<decltype(cind), int, int>);
+}
+
+struct Indexable2
+{
+ template<typename I, typename J>
+ constexpr int
+ operator[](I i, J j) const noexcept
+ { return i*j; }
+};
+
+constexpr void
+test_indexable2()
+{
+ auto cind = std::cw<Indexable2{}>;
+ auto ci = std::cw<2>;
+ auto cj = std::cw<3>;
+ VERIFY(cind[ci, cj] == ci*cj);
+ static_assert(std::same_as<decltype(cind[ci, cj]), std::constant_wrapper<6>>);
+
+ static_assert(indexable<decltype(cind), decltype(ci), decltype(cj)>);
+ static_assert(!indexable<decltype(cind), int, decltype(cj)>);
+ static_assert(!indexable<decltype(cind), int, int>);
+}
+
+struct Indexable3
+{
+ template<typename... Is>
+ constexpr int
+ operator[](Is... i) const noexcept
+ { return (1 * ... * i); }
+};
+
+constexpr void
+test_indexable3()
+{
+ auto cind = std::cw<Indexable3{}>;
+ auto ci = std::cw<2>;
+ auto cj = std::cw<3>;
+
+ check_same(cind[], std::cw<1>);
+ check_same(cind[ci], std::cw<2>);
+ check_same(cind[ci, cj], std::cw<2*3>);
+}
+
+struct Divide
+{
+ int value;
+
+ constexpr int
+ divide(int div) const
+ { return value / div; }
+
+};
+
+constexpr void
+test_member_pointer()
+{
+ constexpr int nom = 42;
+ constexpr int denom = 3;
+
+ auto cvalue = std::cw<&Divide::value>;
+ auto cdiv = std::cw<&Divide::divide>;
+ auto co = std::cw<Divide{nom}>;
+
+ check_same((&co)->*cvalue, std::cw<nom>);
+ check_same((&co)->*(&Divide::value), nom);
+ check_same(&(co.value)->*cvalue, nom);
+
+ auto expect_unwrapped = nom / denom;
+ check_same(((&co)->*(&Divide::divide))(denom), expect_unwrapped);
+ check_same((&(co.value)->*cdiv)(denom), expect_unwrapped);
+ check_same(((&decltype(co)::value)->*cdiv)(denom), expect_unwrapped);
+}
+
+constexpr void
+test_pseudo_mutator()
+{
+ auto ci = std::cw<3>;
+ auto cmmi = --ci;
+ VERIFY(ci.value == 3);
+ VERIFY(cmmi.value == 2);
+
+ auto cimm = ci--;
+ VERIFY(ci.value == 3);
+ VERIFY(cimm.value == 3);
+}
+
+struct Truthy
+{
+ constexpr operator bool() const
+ { return true; }
+};
+
+template<typename Lhs, typename Rhs>
+ concept has_op_and = requires (Lhs lhs, Rhs rhs)
+ {
+ lhs && rhs;
+ };
+
+constexpr void
+test_logic()
+{
+ auto ctrue = std::cw<true>;
+ auto cfalse = std::cw<false>;
+ auto truthy = Truthy{};
+
+ auto check_and = [](auto lhs, auto rhs)
+ {
+ static_assert(lhs && rhs);
+ static_assert(std::same_as<decltype(lhs && rhs), bool>);
+ };
+
+ auto check_or = [](auto lhs, auto rhs)
+ {
+ static_assert(lhs || rhs);
+ static_assert(std::same_as<decltype(lhs || rhs), bool>);
+ };
+
+ check_and(ctrue, ctrue);
+ check_or(ctrue, cfalse);
+ check_and((std::cw<0> < std::cw<1>), (std::cw<1> < std::cw<5>));
+ check_or((std::cw<0> < std::cw<1>), (std::cw<1> < std::cw<5>));
+
+ auto ctruthy = std::cw<Truthy{}>;
+ static_assert(has_op_and<decltype(truthy), bool>);
+ static_assert(!has_op_and<decltype(ctruthy), decltype(ctrue)>);
+ static_assert(!has_op_and<decltype(ctruthy), bool>);
+}
+
+struct ThreeWayComp
+{
+ friend
+ constexpr std::strong_ordering
+ operator<=>(ThreeWayComp lhs, ThreeWayComp rhs)
+ { return lhs.value <=> rhs.value; }
+
+ int value;
+};
+
+constexpr void
+test_three_way()
+{
+ auto ctrue = std::cw<true>;
+ auto cfalse = std::cw<false>;
+
+ check_same(std::cw<ThreeWayComp{0}> < std::cw<ThreeWayComp{1}>, ctrue);
+ check_same(std::cw<ThreeWayComp{2}> > std::cw<ThreeWayComp{1}>, ctrue);
+ check_same(std::cw<ThreeWayComp{2}> >= std::cw<ThreeWayComp{1}>, ctrue);
+ check_same(std::cw<ThreeWayComp{0}> <= std::cw<ThreeWayComp{1}>, ctrue);
+ check_same(std::cw<ThreeWayComp{0}> >= std::cw<ThreeWayComp{1}>, cfalse);
+
+ check_same(std::cw<ThreeWayComp{0}> < ThreeWayComp{1}, true);
+ check_same(ThreeWayComp{2} > std::cw<ThreeWayComp{1}>, true);
+}
+
+struct EqualityComp
+{
+ friend
+ constexpr bool
+ operator==(EqualityComp lhs, EqualityComp rhs)
+ { return lhs.value == rhs.value; }
+
+ int value;
+};
+
+constexpr void
+test_equality()
+{
+ auto ctrue = std::cw<true>;
+ check_same(std::cw<EqualityComp{1}> == std::cw<EqualityComp{1}>, ctrue);
+ check_same(std::cw<EqualityComp{0}> != std::cw<EqualityComp{1}>, ctrue);
+
+ check_same(std::cw<EqualityComp{1}> == EqualityComp{1}, true);
+ check_same(EqualityComp{0} != std::cw<EqualityComp{1}>, true);
+}
+
+struct ConstAssignable
+{
+ int value;
+
+ constexpr ConstAssignable
+ operator=(int rhs) const
+ { return ConstAssignable{rhs}; }
+
+ friend constexpr bool
+ operator==(const ConstAssignable& lhs, const ConstAssignable& rhs)
+ { return lhs.value == rhs.value; }
+};
+
+constexpr void
+test_assignment()
+{
+ check_same(std::cw<ConstAssignable{3}> = std::cw<2>,
+ std::cw<ConstAssignable{2}>);
+}
+
+
+constexpr bool
+test_all()
+{
+ test_c_arrays();
+ test_ints();
+ test_function_object();
+ test_function_pointer();
+ test_indexable1();
+ test_indexable2();
+ test_indexable3();
+ test_member_pointer();
+ test_pseudo_mutator();
+ test_logic();
+ test_three_way();
+ test_equality();
+ return true;
+}
+
+int
+main()
+{
+ test_all();
+ static_assert(test_all());
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/20_util/constant_wrapper/instantiate.cc b/libstdc++-v3/testsuite/20_util/constant_wrapper/instantiate.cc
new file mode 100644
index 0000000..4f12325
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/constant_wrapper/instantiate.cc
@@ -0,0 +1,575 @@
+// { dg-do run { target c++26 } }
+#include <type_traits>
+#include <utility>
+
+#include <testsuite_hooks.h>
+
+namespace free_ops
+{
+ template<int OpId>
+ struct UnaryOps
+ {
+ friend constexpr int
+ operator+(UnaryOps) noexcept requires (OpId == 0)
+ { return OpId; }
+
+ friend constexpr int
+ operator-(UnaryOps) noexcept requires (OpId == 1)
+ { return OpId; }
+
+ friend constexpr int
+ operator~(UnaryOps) noexcept requires (OpId == 2)
+ { return OpId; }
+
+ friend constexpr int
+ operator!(UnaryOps) noexcept requires (OpId == 3)
+ { return OpId; }
+
+ friend constexpr int
+ operator&(UnaryOps) noexcept requires (OpId == 4)
+ { return OpId; }
+
+ friend constexpr int
+ operator*(UnaryOps) noexcept requires (OpId == 5)
+ { return OpId; }
+
+ friend constexpr int
+ operator++(UnaryOps) noexcept requires (OpId == 6)
+ { return OpId; }
+
+ friend constexpr int
+ operator++(UnaryOps, int) noexcept requires (OpId == 7)
+ { return OpId; }
+
+ friend constexpr int
+ operator--(UnaryOps) noexcept requires (OpId == 8)
+ { return OpId; }
+
+ friend constexpr int
+ operator--(UnaryOps, int) noexcept requires (OpId == 9)
+ { return OpId; }
+ };
+}
+
+namespace member_ops
+{
+ template<int OpId>
+ struct UnaryOps
+ {
+ constexpr int
+ operator+() const noexcept requires (OpId == 0)
+ { return OpId; }
+
+ constexpr int
+ operator-() const noexcept requires (OpId == 1)
+ { return OpId; }
+
+ constexpr int
+ operator~() const noexcept requires (OpId == 2)
+ { return OpId; }
+
+ constexpr int
+ operator!() const noexcept requires (OpId == 3)
+ { return OpId; }
+
+ constexpr int
+ operator&() const noexcept requires (OpId == 4)
+ { return OpId; }
+
+ constexpr int
+ operator*() const noexcept requires (OpId == 5)
+ { return OpId; }
+
+ constexpr int
+ operator++() const noexcept requires (OpId == 6)
+ { return OpId; }
+
+ constexpr int
+ operator++(int) const noexcept requires (OpId == 7)
+ { return OpId; }
+
+ constexpr int
+ operator--() const noexcept requires (OpId == 8)
+ { return OpId; }
+
+ constexpr int
+ operator--(int) const noexcept requires (OpId == 9)
+ { return OpId; }
+ };
+}
+
+constexpr size_t n_unary_ops = 10;
+
+template<template<int> typename Ops, int OpId>
+ constexpr void
+ test_unary_operator()
+ {
+ auto x = std::cw<Ops<OpId>{}>;
+
+ auto check = [](auto c)
+ {
+ VERIFY(c == OpId);
+ static_assert(std::same_as<decltype(c), std::constant_wrapper<OpId>>);
+ };
+
+ if constexpr (OpId == 0)
+ check(+x);
+ if constexpr (OpId == 1)
+ check(-x);
+ if constexpr (OpId == 2)
+ check(~x);
+ if constexpr (OpId == 3)
+ check(!x);
+ if constexpr (OpId == 4)
+ check(&x);
+ if constexpr (OpId == 5)
+ check(*x);
+ if constexpr (OpId == 6)
+ check(++x);
+ if constexpr (OpId == 7)
+ check(x++);
+ if constexpr (OpId == 8)
+ check(--x);
+ if constexpr (OpId == 9)
+ check(x--);
+
+ static_assert(n_unary_ops == 10);
+ }
+
+constexpr void
+test_unary_operators_all()
+{
+ auto run = []<size_t... Idx>(std::integer_sequence<size_t, Idx...>)
+ {
+ (test_unary_operator<free_ops::UnaryOps, Idx>(), ...);
+ (test_unary_operator<member_ops::UnaryOps, Idx>(), ...);
+ };
+ run(std::make_index_sequence<n_unary_ops>());
+}
+
+namespace free_ops
+{
+ template<int OpId>
+ struct BinaryOps
+ {
+ friend constexpr int
+ operator+(BinaryOps, BinaryOps) noexcept requires (OpId == 0)
+ { return OpId; }
+
+ friend constexpr int
+ operator-(BinaryOps, BinaryOps) noexcept requires (OpId == 1)
+ { return OpId; }
+
+ friend constexpr int
+ operator*(BinaryOps, BinaryOps) noexcept requires (OpId == 2)
+ { return OpId; }
+
+ friend constexpr int
+ operator/(BinaryOps, BinaryOps) noexcept requires (OpId == 3)
+ { return OpId; }
+
+ friend constexpr int
+ operator%(BinaryOps, BinaryOps) noexcept requires (OpId == 4)
+ { return OpId; }
+
+ friend constexpr int
+ operator<<(BinaryOps, BinaryOps) noexcept requires (OpId == 5)
+ { return OpId; }
+
+ friend constexpr int
+ operator>>(BinaryOps, BinaryOps) noexcept requires (OpId == 6)
+ { return OpId; }
+
+ friend constexpr int
+ operator&(BinaryOps, BinaryOps) noexcept requires (OpId == 7)
+ { return OpId; }
+
+ friend constexpr int
+ operator|(BinaryOps, BinaryOps) noexcept requires (OpId == 8)
+ { return OpId; }
+
+ friend constexpr int
+ operator^(BinaryOps, BinaryOps) noexcept requires (OpId == 9)
+ { return OpId; }
+
+ friend constexpr int
+ operator&&(BinaryOps, BinaryOps) noexcept requires (OpId == 10)
+ { return OpId; }
+
+ friend constexpr int
+ operator||(BinaryOps, BinaryOps) noexcept requires (OpId == 11)
+ { return OpId; }
+
+ friend constexpr int
+ operator<=>(BinaryOps, BinaryOps) noexcept requires (OpId == 12)
+ { return OpId; }
+
+ friend constexpr int
+ operator<(BinaryOps, BinaryOps) noexcept requires (OpId == 13)
+ { return OpId; }
+
+ friend constexpr int
+ operator<=(BinaryOps, BinaryOps) noexcept requires (OpId == 14)
+ { return OpId; }
+
+ friend constexpr int
+ operator==(BinaryOps, BinaryOps) noexcept requires (OpId == 15)
+ { return OpId; }
+
+ friend constexpr int
+ operator!=(BinaryOps, BinaryOps) noexcept requires (OpId == 16)
+ { return OpId; }
+
+ friend constexpr int
+ operator>(BinaryOps, BinaryOps) noexcept requires (OpId == 17)
+ { return OpId; }
+
+ friend constexpr int
+ operator>=(BinaryOps, BinaryOps) noexcept requires (OpId == 18)
+ { return OpId; }
+
+ friend constexpr int
+ operator+=(BinaryOps, BinaryOps) noexcept requires (OpId == 19)
+ { return OpId; }
+
+ friend constexpr int
+ operator-=(BinaryOps, BinaryOps) noexcept requires (OpId == 20)
+ { return OpId; }
+
+ friend constexpr int
+ operator*=(BinaryOps, BinaryOps) noexcept requires (OpId == 21)
+ { return OpId; }
+
+ friend constexpr int
+ operator/=(BinaryOps, BinaryOps) noexcept requires (OpId == 22)
+ { return OpId; }
+
+ friend constexpr int
+ operator%=(BinaryOps, BinaryOps) noexcept requires (OpId == 23)
+ { return OpId; }
+
+ friend constexpr int
+ operator&=(BinaryOps, BinaryOps) noexcept requires (OpId == 24)
+ { return OpId; }
+
+ friend constexpr int
+ operator|=(BinaryOps, BinaryOps) noexcept requires (OpId == 25)
+ { return OpId; }
+ friend constexpr int
+
+ operator^=(BinaryOps, BinaryOps) noexcept requires (OpId == 26)
+ { return OpId; }
+
+ friend constexpr int
+ operator<<=(BinaryOps, BinaryOps) noexcept requires (OpId == 27)
+ { return OpId; }
+
+ friend constexpr int
+ operator>>=(BinaryOps, BinaryOps) noexcept requires (OpId == 28)
+ { return OpId; }
+ };
+}
+
+namespace member_ops
+{
+ template<int OpId>
+ struct BinaryOps
+ {
+ constexpr int
+ operator+(BinaryOps) const noexcept requires (OpId == 0)
+ { return OpId; }
+
+ constexpr int
+ operator-(BinaryOps) const noexcept requires (OpId == 1)
+ { return OpId; }
+
+ constexpr int
+ operator*(BinaryOps) const noexcept requires (OpId == 2)
+ { return OpId; }
+
+ constexpr int
+ operator/(BinaryOps) const noexcept requires (OpId == 3)
+ { return OpId; }
+
+ constexpr int
+ operator%(BinaryOps) const noexcept requires (OpId == 4)
+ { return OpId; }
+
+ constexpr int
+ operator<<(BinaryOps) const noexcept requires (OpId == 5)
+ { return OpId; }
+
+ constexpr int
+ operator>>(BinaryOps) const noexcept requires (OpId == 6)
+ { return OpId; }
+
+ constexpr int
+ operator&(BinaryOps) const noexcept requires (OpId == 7)
+ { return OpId; }
+
+ constexpr int
+ operator|(BinaryOps) const noexcept requires (OpId == 8)
+ { return OpId; }
+
+ constexpr int
+ operator^(BinaryOps) const noexcept requires (OpId == 9)
+ { return OpId; }
+
+ constexpr int
+ operator&&(BinaryOps) const noexcept requires (OpId == 10)
+ { return OpId; }
+
+ constexpr int
+ operator||(BinaryOps) const noexcept requires (OpId == 11)
+ { return OpId; }
+
+ constexpr int
+ operator<=>(BinaryOps) const noexcept requires (OpId == 12)
+ { return OpId; }
+
+ constexpr int
+ operator<(BinaryOps) const noexcept requires (OpId == 13)
+ { return OpId; }
+
+ constexpr int
+ operator<=(BinaryOps) const noexcept requires (OpId == 14)
+ { return OpId; }
+
+ constexpr int
+ operator==(BinaryOps) const noexcept requires (OpId == 15)
+ { return OpId; }
+
+ constexpr int
+ operator!=(BinaryOps) const noexcept requires (OpId == 16)
+ { return OpId; }
+
+ constexpr int
+ operator>(BinaryOps) const noexcept requires (OpId == 17)
+ { return OpId; }
+
+ constexpr int
+ operator>=(BinaryOps) const noexcept requires (OpId == 18)
+ { return OpId; }
+
+ constexpr int
+ operator+=(BinaryOps) const noexcept requires (OpId == 19)
+ { return OpId; }
+
+ constexpr int
+ operator-=(BinaryOps) const noexcept requires (OpId == 20)
+ { return OpId; }
+
+ constexpr int
+ operator*=(BinaryOps) const noexcept requires (OpId == 21)
+ { return OpId; }
+
+ constexpr int
+ operator/=(BinaryOps) const noexcept requires (OpId == 22)
+ { return OpId; }
+
+ constexpr int
+ operator%=(BinaryOps) const noexcept requires (OpId == 23)
+ { return OpId; }
+
+ constexpr int
+ operator&=(BinaryOps) const noexcept requires (OpId == 24)
+ { return OpId; }
+
+ constexpr int
+ operator|=(BinaryOps) const noexcept requires (OpId == 25)
+ { return OpId; }
+
+ constexpr int
+ operator^=(BinaryOps) const noexcept requires (OpId == 26)
+ { return OpId; }
+
+ constexpr int
+ operator<<=(BinaryOps) const noexcept requires (OpId == 27)
+ { return OpId; }
+
+ constexpr int
+ operator>>=(BinaryOps) const noexcept requires (OpId == 28)
+ { return OpId; }
+ };
+}
+
+constexpr size_t n_binary_ops = 29;
+
+template<template<int> typename Ops, int OpId>
+ constexpr void
+ test_binary_operator()
+ {
+ auto cx = std::cw<Ops<OpId>{}>;
+ auto cy = std::cw<Ops<OpId>{}>;
+
+ auto check = [](auto c)
+ {
+ VERIFY(c == OpId);
+ static_assert(std::same_as<decltype(c), std::constant_wrapper<OpId>>);
+ };
+
+ if constexpr (OpId == 0)
+ check(cx + cy);
+ if constexpr (OpId == 1)
+ check(cx - cy);
+ if constexpr (OpId == 2)
+ check(cx * cy);
+ if constexpr (OpId == 3)
+ check(cx / cy);
+ if constexpr (OpId == 4)
+ check(cx % cy);
+ if constexpr (OpId == 5)
+ check(cx << cy);
+ if constexpr (OpId == 6)
+ check(cx >> cy);
+ if constexpr (OpId == 7)
+ check(cx & cy);
+ if constexpr (OpId == 8)
+ check(cx | cy);
+ if constexpr (OpId == 10)
+ check(cx && cy);
+ if constexpr (OpId == 11)
+ check(cx || cy);
+ if constexpr (OpId == 12)
+ check(cx <=> cy);
+ if constexpr (OpId == 13)
+ check(cx < cy);
+ if constexpr (OpId == 14)
+ check(cx <= cy);
+ if constexpr (OpId == 15)
+ check(cx == cy);
+ if constexpr (OpId == 16)
+ check(cx != cy);
+ if constexpr (OpId == 17)
+ check(cx > cy);
+ if constexpr (OpId == 18)
+ check(cx >= cy);
+ if constexpr (OpId == 19)
+ check(cx += cy);
+ if constexpr (OpId == 20)
+ check(cx -= cy);
+ if constexpr (OpId == 21)
+ check(cx *= cy);
+ if constexpr (OpId == 22)
+ check(cx /= cy);
+ if constexpr (OpId == 23)
+ check(cx %= cy);
+ if constexpr (OpId == 24)
+ check(cx &= cy);
+ if constexpr (OpId == 25)
+ check(cx |= cy);
+ if constexpr (OpId == 26)
+ check(cx ^= cy);
+ if constexpr (OpId == 27)
+ check(cx <<= cy);
+ if constexpr (OpId == 28)
+ check(cx >>= cy);
+ static_assert(n_binary_ops == 29);
+ }
+
+template<template<int> typename Ops, int OpId>
+ constexpr void
+ test_mixed_binary_operators()
+ {
+ constexpr auto x = Ops<OpId>{};
+ auto cx = std::cw<x>;
+ constexpr auto y = Ops<OpId>{};
+ auto cy = std::cw<y>;
+
+ auto check = [](auto vc, auto cv)
+ {
+ auto impl = [](auto c)
+ {
+ VERIFY(c == OpId);
+ static_assert(std::same_as<decltype(c), int>);
+ };
+
+ impl(vc);
+ impl(cv);
+ };
+
+ if constexpr (OpId == 0)
+ check(x + cy, cx + y);
+ if constexpr (OpId == 1)
+ check(x - cy, cx - y);
+ if constexpr (OpId == 2)
+ check(x * cy, cx * y);
+ if constexpr (OpId == 3)
+ check(x / cy, cx / y);
+ if constexpr (OpId == 4)
+ check(x % cy, cx % y);
+ if constexpr (OpId == 5)
+ check(x << cy, cx << y);
+ if constexpr (OpId == 6)
+ check(x >> cy, cx >> y);
+ if constexpr (OpId == 7)
+ check(x & cy, cx & y);
+ if constexpr (OpId == 8)
+ check(x | cy, cx | y);
+ if constexpr (OpId == 10)
+ check(x && cy, cx && y);
+ if constexpr (OpId == 11)
+ check(x || cy, cx || y);
+ if constexpr (OpId == 12)
+ check(x <=> cy, cx <=> y);
+ if constexpr (OpId == 13)
+ check(x < cy, cx < y);
+ if constexpr (OpId == 14)
+ check(x <= cy, cx <= y);
+ if constexpr (OpId == 15)
+ check(x == cy, cx == y);
+ if constexpr (OpId == 16)
+ check(x != cy, cx != y);
+ if constexpr (OpId == 17)
+ check(x > cy, cx > y);
+ if constexpr (OpId == 18)
+ check(x >= cy, cx >= y);
+ if constexpr (OpId == 19)
+ check(x += cy, cx += y);
+ if constexpr (OpId == 20)
+ check(x -= cy, cx -= y);
+ if constexpr (OpId == 21)
+ check(x *= cy, cx *= y);
+ if constexpr (OpId == 22)
+ check(x /= cy, cx /= y);
+ if constexpr (OpId == 23)
+ check(x %= cy, cx %= y);
+ if constexpr (OpId == 24)
+ check(x &= cy, cx &= y);
+ if constexpr (OpId == 25)
+ check(x |= cy, cx |= y);
+ if constexpr (OpId == 26)
+ check(x ^= cy, cx ^= y);
+ if constexpr (OpId == 27)
+ check(x <<= cy, cx <<= y);
+ if constexpr (OpId == 28)
+ check(x >>= cy, cx >>= y);
+ static_assert(n_binary_ops == 29);
+ }
+
+constexpr void
+test_binary_operators_all()
+{
+ auto run = []<size_t... Idx>(std::integer_sequence<size_t, Idx...>)
+ {
+ (test_binary_operator<free_ops::BinaryOps, Idx>(), ...);
+ (test_mixed_binary_operators<free_ops::BinaryOps, Idx>(), ...);
+ (test_binary_operator<member_ops::BinaryOps, Idx>(), ...);
+ };
+ run(std::make_index_sequence<n_binary_ops>());
+}
+
+constexpr bool
+test_all()
+{
+ test_unary_operators_all();
+ test_binary_operators_all();
+ return true;
+}
+
+int
+main()
+{
+ test_all();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/20_util/constant_wrapper/op_comma_neg.cc b/libstdc++-v3/testsuite/20_util/constant_wrapper/op_comma_neg.cc
new file mode 100644
index 0000000..4384e92
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/constant_wrapper/op_comma_neg.cc
@@ -0,0 +1,14 @@
+// { dg-do compile { target c++26 } }
+#include <type_traits>
+
+constexpr void
+test_comma_same_types()
+{
+ (std::cw<1>, std::cw<2>); // { dg-error "use of deleted function" }
+}
+
+constexpr void
+test_comma_different_types()
+{
+ (std::cw<1>, std::cw<2.0>); // { dg-error "use of deleted function" }
+}
diff --git a/libstdc++-v3/testsuite/20_util/constant_wrapper/other_wrappers.cc b/libstdc++-v3/testsuite/20_util/constant_wrapper/other_wrappers.cc
new file mode 100644
index 0000000..3c3cfaf
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/constant_wrapper/other_wrappers.cc
@@ -0,0 +1,75 @@
+// { dg-do run { target c++26 } }
+#include <type_traits>
+#include <concepts>
+
+#include <testsuite_hooks.h>
+
+template<typename Type, Type Value>
+ struct ConstWrapper
+ {
+ constexpr static Type value = Value;
+ };
+
+constexpr void
+check_same(auto actual, auto expected)
+{
+ VERIFY(actual == expected);
+ static_assert(std::same_as<decltype(actual), decltype(expected)>);
+}
+
+constexpr void
+test_mix_integer_constant()
+{
+ auto i4 = std::integral_constant<int, 4>{};
+ auto c3 = std::cw<3>;
+ auto w2 = ConstWrapper<int, 2>{};
+
+ check_same(i4 + c3, std::cw<7>);
+ check_same(c3 + i4, std::cw<7>);
+ check_same(c3 + w2, std::cw<5>);
+ check_same(w2 + c3, std::cw<5>);
+}
+
+constexpr void
+test_array()
+{
+ constexpr double x[] = {1.1, 2.2, 3.3};
+ auto cx = std::cw<x>;
+ auto i2 = std::integral_constant<int, 2>{};
+ auto w2 = ConstWrapper<int, 2>{};
+
+ check_same(x[i2], x[2]);
+ check_same(cx[i2], std::cw<x[2]>);
+ check_same(cx[w2], std::cw<x[2]>);
+}
+
+constexpr void
+test_function_object()
+{
+ auto cadd = std::cw<[](int i, int j) { return i + j; }>;
+ auto i4 = std::integral_constant<int, 4>{};
+ auto c3 = std::cw<3>;
+ auto w2 = ConstWrapper<int, 2>{};
+
+ check_same(cadd(i4, c3), std::cw<7>);
+ check_same(cadd(c3, i4), std::cw<7>);
+ check_same(cadd(w2, c3), std::cw<5>);
+ check_same(cadd(c3, w2), std::cw<5>);
+}
+
+constexpr bool
+test_all()
+{
+ test_mix_integer_constant();
+ test_array();
+ test_function_object();
+ return true;
+}
+
+int
+main()
+{
+ test_all();
+ static_assert(test_all());
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/20_util/constant_wrapper/version.cc b/libstdc++-v3/testsuite/20_util/constant_wrapper/version.cc
new file mode 100644
index 0000000..4fee615
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/constant_wrapper/version.cc
@@ -0,0 +1,11 @@
+// { dg-do preprocess { target c++26 } }
+// { dg-add-options no_pch }
+
+#include <type_traits>
+
+#ifndef __cpp_lib_constant_wrapper
+#error "Feature test macro __cpp_lib_constant_wrapper is missing for <type_traits>"
+#if __cpp_lib_constant_wrapper < 202506L
+#error "Feature test macro __cpp_lib_constant_wrapper has the wrong value"
+#endif
+#endif
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..605422d
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/copyable_function/call.cc
@@ -0,0 +1,248 @@
+// { 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;
+}
+
+struct EmptyIdFunc
+{
+ EmptyIdFunc* operator()()
+ { return this; }
+};
+
+struct Composed : EmptyIdFunc
+{
+ std::move_only_function<EmptyIdFunc*()> nested;
+};
+
+void
+test_aliasing()
+{
+ Composed c;
+ c.nested = EmptyIdFunc{};
+
+ EmptyIdFunc* baseAddr = c();
+ EmptyIdFunc* nestedAddr = c.nested();
+ VERIFY( baseAddr != nestedAddr );
+};
+
+int main()
+{
+ test01();
+ test02();
+ test03();
+ test04();
+ test05();
+ test_params();
+ test_aliasing();
+}
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/duration/114244.cc b/libstdc++-v3/testsuite/20_util/duration/114244.cc
index 55a7670..12701bf 100644
--- a/libstdc++-v3/testsuite/20_util/duration/114244.cc
+++ b/libstdc++-v3/testsuite/20_util/duration/114244.cc
@@ -13,8 +13,8 @@ test_pr114244()
{
using namespace std::chrono;
seconds s;
- milliseconds ms;
- microseconds us;
+ milliseconds ms{};
+ microseconds us{};
std::istringstream is;
diff --git a/libstdc++-v3/testsuite/20_util/duration/io.cc b/libstdc++-v3/testsuite/20_util/duration/io.cc
index 0117673..6ada4fc 100644
--- a/libstdc++-v3/testsuite/20_util/duration/io.cc
+++ b/libstdc++-v3/testsuite/20_util/duration/io.cc
@@ -193,8 +193,8 @@ test_parse()
{
using namespace std::chrono;
seconds s;
- milliseconds ms;
- microseconds us;
+ milliseconds ms{};
+ microseconds us{};
std::istringstream is(" 2023-07-24 13:05");
VERIFY( is >> parse(" %Y-%m-%d %H:%M", s) );
@@ -289,13 +289,13 @@ test_parse()
is.clear();
is.str("0.5");
- std::chrono::duration<double> ds;
+ std::chrono::duration<double> ds{};
VERIFY( is >> parse("%S", ds) );
VERIFY( ds == 0.5s );
is.clear();
is.str("0.125");
- std::chrono::duration<double, std::milli> dms;
+ std::chrono::duration<double, std::milli> dms{};
VERIFY( is >> parse("%S", dms) );
VERIFY( dms == 0.125s );
}
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.cc b/libstdc++-v3/testsuite/20_util/expected/equality.cc
index db19b15..cc122f4 100644
--- a/libstdc++-v3/testsuite/20_util/expected/equality.cc
+++ b/libstdc++-v3/testsuite/20_util/expected/equality.cc
@@ -28,19 +28,45 @@ test_eq()
std::expected<int, int> e2;
VERIFY(e2 == e2);
VERIFY(e1 == e2);
+ VERIFY(e2 == e1);
VERIFY(e1 != std::unexpected<int>(1));
+
e1 = std::unexpected<int>(1);
VERIFY(e1 == std::unexpected<int>(1));
VERIFY(e1 != std::unexpected<int>(2));
VERIFY(e1 != e2);
+ VERIFY(e2 != e1);
+ VERIFY(e1 != 1);
+
+ e2 = std::unexpected<int>(1);
+ VERIFY(e1 == e2);
+ VERIFY(e2 == e1);
+
+ e2 = std::unexpected<int>(2);
+ VERIFY(e1 != e2);
+ VERIFY(e2 != e1);
std::expected<void, int> e3;
VERIFY(e3 == e3);
VERIFY(e3 != std::unexpected<int>(1));
+ std::expected<const void, long> e4;
+ VERIFY(e3 == e4);
+ VERIFY(e4 == e3);
+
e3 = std::unexpected<int>(1);
VERIFY(e3 == e3);
VERIFY(e3 == std::unexpected<int>(1));
VERIFY(e3 != std::unexpected<int>(2));
+ VERIFY(e3 != e4);
+ VERIFY(e4 != e3);
+
+ e4 = e3;
+ VERIFY(e3 == e4);
+ VERIFY(e4 == e3);
+
+ e4 = std::unexpected<int>(4);
+ VERIFY(e3 != e4);
+ VERIFY(e4 != e3);
return true;
}
diff --git a/libstdc++-v3/testsuite/20_util/expected/illformed_neg.cc b/libstdc++-v3/testsuite/20_util/expected/illformed_neg.cc
index 69c13b4..69aa4a1 100644
--- a/libstdc++-v3/testsuite/20_util/expected/illformed_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/expected/illformed_neg.cc
@@ -13,6 +13,7 @@ test_unexpected()
std::unexpected<void()> func(test_unexpected); // { dg-error "here" }
// { dg-error "no matching function for call to" "" { target *-*-* } 0 }
// { dg-error "invalidly declared function type" "" { target *-*-* } 0 }
+ // { dg-error "could not convert" "" { target *-*-* } 0 }
// an array type,
std::unexpected<int[2]> array(i); // { dg-error "here" }
diff --git a/libstdc++-v3/testsuite/20_util/expected/lwg4222.cc b/libstdc++-v3/testsuite/20_util/expected/lwg4222.cc
new file mode 100644
index 0000000..5c10779
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/expected/lwg4222.cc
@@ -0,0 +1,39 @@
+// { dg-do run { target c++23 } }
+
+// LWG 4222. 'expected' constructor from a single value missing a constraint
+
+#include <expected>
+#include <type_traits>
+#include <testsuite_hooks.h>
+
+struct T {
+ explicit T(auto) {}
+};
+struct E {
+ E(int) {}
+};
+
+struct V {
+ explicit constexpr V(std::unexpect_t) {}
+};
+
+static_assert(!std::is_constructible_v<std::expected<T, E>, std::unexpect_t>);
+static_assert(!std::is_constructible_v<std::expected<T, E>, std::unexpect_t &>);
+static_assert(!std::is_constructible_v<std::expected<T, E>, std::unexpect_t &&>);
+static_assert(!std::is_constructible_v<std::expected<T, E>, const std::unexpect_t>);
+static_assert(!std::is_constructible_v<std::expected<T, E>, const std::unexpect_t &>);
+static_assert(!std::is_constructible_v<std::expected<T, E>, const std::unexpect_t &&>);
+
+constexpr bool test() {
+ std::expected<V, int> e1(std::in_place, std::unexpect);
+ VERIFY( e1.has_value() );
+ std::expected<int, V> e2(std::unexpect, std::unexpect);
+ VERIFY( !e2.has_value() );
+ return true;
+}
+
+int main() {
+ test();
+ static_assert(test());
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/20_util/expected/lwg4366.cc b/libstdc++-v3/testsuite/20_util/expected/lwg4366.cc
new file mode 100644
index 0000000..35d5371
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/expected/lwg4366.cc
@@ -0,0 +1,33 @@
+// { dg-do run { target c++23 } }
+
+// LWG 4366. Heterogeneous comparison of expected may be ill-formed
+
+#include <expected>
+#include <testsuite_hooks.h>
+
+struct Bool
+{
+ operator bool() const { return true; }
+ explicit operator bool() { throw; }
+};
+
+struct E1 {
+ friend Bool operator==(E1, E1) { return {}; }
+} e1;
+
+struct E2 {
+ friend Bool operator==(E1, E2) { return {}; }
+} e2;
+
+int main()
+{
+ std::expected<int, E1> u1(std::unexpect, e1);
+ VERIFY(u1 == u1);
+
+ std::unexpected<E2> u2(e2);
+ VERIFY(u1 == u2);
+
+ std::expected<void, E1> u3(std::unexpect, e1);
+ VERIFY(u3 == u3);
+ VERIFY(u3 == u2);
+}
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_objects/121782.cc b/libstdc++-v3/testsuite/20_util/function_objects/121782.cc
new file mode 100644
index 0000000..f18fb1e
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/function_objects/121782.cc
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++17 } }
+// libstdc++/121782
+// Missing Mandates for operator() of std::boyer_moore_[horspool]_searcher
+
+// N.B. we only enforce this for C++20 and later.
+// { dg-error "static assertion failed" "" { target c++20 } 0 }
+
+#include <algorithm>
+#include <functional>
+#include <testsuite_iterators.h>
+
+template<typename T>
+using Range = __gnu_test::random_access_container<T>;
+
+void
+test_bm(Range<char> needle, Range<unsigned char> haystack)
+{
+ std::boyer_moore_searcher s(needle.begin(), needle.end());
+ (void) std::search(haystack.begin(), haystack.end(), s); // { dg-error "here" "" { target c++20 } }
+ // { dg-error "'char' is not the same as 'unsigned char'" "" { target c++20 } 0 }
+}
+
+void
+test_bmh(Range<char> needle, Range<signed char> haystack)
+{
+ std::boyer_moore_horspool_searcher s(needle.begin(), needle.end());
+ (void) std::search(haystack.begin(), haystack.end(), s); // { dg-error "here" "" { target c++20 } }
+ // { dg-error "'char' is not the same as 'signed char'" "" { target c++20 } 0 }
+}
+
diff --git a/libstdc++-v3/testsuite/20_util/function_objects/bind_back/1.cc b/libstdc++-v3/testsuite/20_util/function_objects/bind_back/1.cc
index c31d322..743b7b0 100644
--- a/libstdc++-v3/testsuite/20_util/function_objects/bind_back/1.cc
+++ b/libstdc++-v3/testsuite/20_util/function_objects/bind_back/1.cc
@@ -48,6 +48,15 @@ test01()
decltype(bind_back(std::declval<const F&>(), std::declval<const int&>()))
>);
+ static_assert(std::is_same_v<
+ decltype(bind_back(std::declval<F>(), std::declval<int>(), std::declval<float>())),
+ decltype(bind_back(std::declval<F&>(), std::declval<int&>(), std::declval<float&>()))
+ >);
+ static_assert(std::is_same_v<
+ decltype(bind_back(std::declval<F>(), std::declval<int>(), std::declval<float>())),
+ decltype(bind_back(std::declval<const F&>(), std::declval<const int&>(), std::declval<const float&>()))
+ >);
+
// Reference wrappers should be handled:
static_assert(!std::is_same_v<
decltype(bind_back(std::declval<F>(), std::declval<int&>())),
@@ -63,29 +72,58 @@ test01()
>);
}
+struct quals
+{
+ bool as_const;
+ bool as_lvalue;
+};
+
+template<typename... Args>
void
-test02()
+testTarget(Args... args)
{
- struct quals
+ struct F
{
- bool as_const;
- bool as_lvalue;
+ quals operator()(Args...) & { return { false, true }; }
+ quals operator()(Args...) const & { return { true, true }; }
+ quals operator()(Args...) && { return { false, false }; }
+ quals operator()(Args...) const && { return { true, false }; }
};
+ F f;
+ auto g = bind_back(f, args...);
+ const auto& cg = g;
+ quals q;
+
+ // constness and value category should be forwarded to the target object:
+ q = g();
+ VERIFY( ! q.as_const && q.as_lvalue );
+ q = std::move(g)();
+ VERIFY( ! q.as_const && ! q.as_lvalue );
+ q = cg();
+ VERIFY( q.as_const && q.as_lvalue );
+ q = std::move(cg)();
+ VERIFY( q.as_const && ! q.as_lvalue );
+}
+
+template<typename... Args>
+void
+testBoundArgs(Args... args)
+{
struct F
{
- quals operator()() & { return { false, true }; }
- quals operator()() const & { return { true, true }; }
- quals operator()() && { return { false, false }; }
- quals operator()() const && { return { true, false }; }
+ quals operator()(Args..., int&) const { return { false, true }; }
+ quals operator()(Args..., int const&) const { return { true, true }; }
+ quals operator()(Args..., int&&) const { return { false, false }; }
+ quals operator()(Args..., int const&&) const { return { true, false }; }
};
F f;
- auto g = bind_back(f);
+ auto g = bind_back(f, args..., 10);
const auto& cg = g;
quals q;
- // constness and value category should be forwarded to the target object:
+ // constness and value category should be forwarded to the bound objects:
q = g();
VERIFY( ! q.as_const && q.as_lvalue );
q = std::move(g)();
@@ -94,6 +132,85 @@ test02()
VERIFY( q.as_const && q.as_lvalue );
q = std::move(cg)();
VERIFY( q.as_const && ! q.as_lvalue );
+
+ int i = 0;
+ auto gr = bind_back(f, args..., std::ref(i));
+ const auto& cgr = gr;
+
+ // bound object is reference wrapper
+ q = gr();
+ VERIFY( ! q.as_const && q.as_lvalue );
+ q = std::move(gr)();
+ VERIFY( ! q.as_const && q.as_lvalue );
+ q = cgr();
+ VERIFY( ! q.as_const && q.as_lvalue );
+ q = std::move(cgr)();
+ VERIFY( ! q.as_const && q.as_lvalue );
+
+ auto gcr = bind_back(f, args..., std::cref(i));
+ const auto& cgcr = gcr;
+
+ q = gcr();
+ VERIFY( q.as_const && q.as_lvalue );
+ q = std::move(gcr)();
+ VERIFY( q.as_const && q.as_lvalue );
+ q = cgcr();
+ VERIFY( q.as_const && q.as_lvalue );
+ q = std::move(cgcr)();
+ VERIFY( q.as_const && q.as_lvalue );
+}
+
+template<typename... Args>
+void
+testCallArgs(Args... args)
+{
+ struct F
+ {
+ quals operator()(int&, Args...) const { return { false, true }; }
+ quals operator()(int const&, Args...) const { return { true, true }; }
+ quals operator()(int&&, Args...) const { return { false, false }; }
+ quals operator()(int const&&, Args...) const { return { true, false }; }
+ };
+
+ F f;
+ auto g = bind_back(f, args...);
+ const auto& cg = g;
+ quals q;
+ int i = 10;
+ const int ci = i;
+
+ q = g(i);
+ VERIFY( ! q.as_const && q.as_lvalue );
+ q = g(std::move(i));
+ VERIFY( ! q.as_const && ! q.as_lvalue );
+ q = g(ci);
+ VERIFY( q.as_const && q.as_lvalue );
+ q = g(std::move(ci));
+ VERIFY( q.as_const && ! q.as_lvalue );
+
+ q = cg(i);
+ VERIFY( ! q.as_const && q.as_lvalue );
+ q = cg(std::move(i));
+ VERIFY( ! q.as_const && ! q.as_lvalue );
+ q = cg(ci);
+ VERIFY( q.as_const && q.as_lvalue );
+ q = cg(std::move(ci));
+ VERIFY( q.as_const && ! q.as_lvalue );
+
+ struct S
+ {
+ int operator()(long, long, Args...) const { return 1; }
+ int operator()(int, void*, Args...) const { return 2; }
+ };
+
+ S s;
+ // literal zero can be converted to any pointer, so (int, void*)
+ // is best candidate
+ VERIFY( s(0, 0, args...) == 2 );
+ // both arguments are bound to int&&, and no longer can be
+ // converted to pointer, (long, long) is only candidate
+ VERIFY( bind_back(s)(0, 0, args...) == 1 );
+ VERIFY( bind_back(s, args...)(0, 0) == 1 );
}
void
@@ -149,30 +266,71 @@ test03()
static_assert(is_invocable_r_v<void*, const G4&&>);
}
-constexpr int f(int i, int j, int k) { return i + 2*(j + k); }
+constexpr int f(int i, int j, int k) { return i + 2*j + 3*k; }
constexpr bool
test04()
{
auto g = bind_back(f);
- VERIFY( g(1, 2, 3) == 1 + 2*(2 + 3) );
+ VERIFY( g(1, 2, 3) == 1 + 2*2 + 3*3 );
auto g1 = bind_back(f, 1);
- VERIFY( g1(2, 3) == 2 + 2*(3 + 1) );
- VERIFY( bind_back(g, 1)(2, 3) == 2 + 2*(3 + 1) );
+ VERIFY( g1(2, 3) == 3*1 + 2 + 3*2);
+ VERIFY( bind_back(g, 1)(2, 3) == 3*1 + 2 + 2*3 );
auto g2 = bind_back(f, 1, 2);
- VERIFY( g2(3) == 3 + 2*(1 + 2) );
- VERIFY( bind_back(g1, 2)(3) == 3 + 2*(2 + 1) );
+ VERIFY( g2(3) == 3 + 2*1 + 3*2);
+ VERIFY( bind_back(g1, 2)(3) == 3*1 + 2*2 + 3 );
auto g3 = bind_back(f, 1, 2, 3);
- VERIFY( g3() == 1 + 2*(2 + 3) );
- VERIFY( bind_back(g2, 3)() == 3 + 2*(1 + 2) );
+ VERIFY( g3() == 1 + 2*2 + 3*3 );
+ VERIFY( bind_back(g2, 3)() == 3*1 + 1*2 + 2*3);
return true;
}
+struct CountedArg
+{
+ CountedArg() = default;
+ CountedArg(CountedArg&& f) noexcept : counter(f.counter) { ++counter; }
+ CountedArg& operator=(CountedArg&&) = delete;
+
+ int counter = 0;
+};
+CountedArg const c;
+
+void
+testMaterialization()
+{
+ struct F
+ {
+ int operator()(CountedArg arg, int) const
+ { return arg.counter; };
+ };
+
+ // CountedArg is bound to rvalue-reference thus moved
+ auto f0 = std::bind_back(F{});
+ VERIFY( f0(CountedArg(), 10) == 1 );
+
+ auto f1 = std::bind_back(F{}, 10);
+ VERIFY( f1(CountedArg()) == 1 );
+}
+
int
main()
{
test01();
- test02();
test03();
+
+ testTarget();
+ testTarget(10);
+ testTarget(10, 20, 30);
+
+ testBoundArgs();
+ testBoundArgs(10);
+ testBoundArgs(10, 20, 30);
+
+ testCallArgs();
+ testCallArgs(10);
+ testCallArgs(10, 20, 30);
+
+ testMaterialization();
+
static_assert(test04());
}
diff --git a/libstdc++-v3/testsuite/20_util/function_objects/bind_back/111327.cc b/libstdc++-v3/testsuite/20_util/function_objects/bind_back/111327.cc
index d634db9..8e7dacf 100644
--- a/libstdc++-v3/testsuite/20_util/function_objects/bind_back/111327.cc
+++ b/libstdc++-v3/testsuite/20_util/function_objects/bind_back/111327.cc
@@ -37,6 +37,18 @@ int main() {
g1(); // { dg-error "deleted|no match" }
std::move(g1)(); // { dg-error "deleted|no match" }
std::move(std::as_const(g1))();
+
+ auto f2 = std::bind_back(F{}, 42, 10);
+ f2(); // { dg-error "deleted|no match" }
+ std::move(f2)();
+ std::as_const(f2)();
+ std::move(std::as_const(f2))();
+
+ auto g2 = std::bind_back(G{}, 42, 10);
+ g2(); // { dg-error "deleted|no match" }
+ std::move(g2)(); // { dg-error "deleted|no match" }
+ std::move(std::as_const(g2))();
}
-// { dg-error "no type named 'type' in 'struct std::invoke_result" "" { target c++23 } 0 }
+// { dg-error "no type named 'type' in 'std::__conditional_t<false, std::invoke_result<" "" { target c++23 } 0 }
+// { dg-error "no type named 'type' in 'std::__conditional_t<true, std::invoke_result<" "" { target c++23 } 0 }
diff --git a/libstdc++-v3/testsuite/20_util/function_objects/bind_back/nttp.cc b/libstdc++-v3/testsuite/20_util/function_objects/bind_back/nttp.cc
new file mode 100644
index 0000000..24bf046
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/function_objects/bind_back/nttp.cc
@@ -0,0 +1,345 @@
+// { dg-do run { target c++26 } }
+// { dg-add-options no_pch }
+
+// Test NTTP bind_back<f>(Args...), P2714
+
+#include <functional>
+
+#ifndef __cpp_lib_bind_back
+# error "Feature test macro for bind_back is missing in <functional>"
+#elif __cpp_lib_bind_back < 202306L
+# error "Feature test macro for bind_back has wrong value in <functional>"
+#endif
+
+#include <testsuite_hooks.h>
+
+using std::bind_back;
+using std::is_same_v;
+using std::is_invocable_v;
+using std::is_invocable_r_v;
+
+void
+test01()
+{
+ struct F { void operator()(int) {} };
+ constexpr F f{};
+
+ // Arguments should be decayed:
+ static_assert(std::is_same_v<
+ decltype(bind_back<f>(std::declval<int>())),
+ decltype(bind_back<f>(std::declval<int&>()))
+ >);
+ static_assert(std::is_same_v<
+ decltype(bind_back<f>(std::declval<int>())),
+ decltype(bind_back<f>(std::declval<const int&>()))
+ >);
+
+ static_assert(std::is_same_v<
+ decltype(bind_back<f>(std::declval<int>(), std::declval<float>())),
+ decltype(bind_back<f>(std::declval<int&>(), std::declval<float&>()))
+ >);
+ static_assert(std::is_same_v<
+ decltype(bind_back<f>(std::declval<int>(), std::declval<float>())),
+ decltype(bind_back<f>(std::declval<const int&>(), std::declval<const float&>()))
+ >);
+
+ // Reference wrappers should be handled:
+ static_assert(!std::is_same_v<
+ decltype(bind_back<f>(std::declval<int&>())),
+ decltype(bind_back<f>(std::ref(std::declval<int&>())))
+ >);
+ static_assert(!std::is_same_v<
+ decltype(bind_back<f>(std::declval<const int&>())),
+ decltype(bind_back<f>(std::cref(std::declval<int&>())))
+ >);
+ static_assert(!std::is_same_v<
+ decltype(bind_back<f>(std::ref(std::declval<int&>()))),
+ decltype(bind_back<f>(std::cref(std::declval<int&>())))
+ >);
+}
+
+struct quals
+{
+ bool as_const;
+ bool as_lvalue;
+};
+
+template<typename... Args>
+void
+testTarget(Args... args)
+{
+ struct F
+ {
+ quals operator()(Args...) & { return { false, true }; }
+ quals operator()(Args...) const & { return { true, true }; }
+ quals operator()(Args...) && { return { false, false }; }
+ quals operator()(Args...) const && { return { true, false }; }
+ };
+
+ constexpr F f;
+ auto g = bind_back<f>(args...);
+ const auto& cg = g;
+ quals q;
+
+ // template parameter object is always constant lvalue
+ q = g();
+ VERIFY( q.as_const && q.as_lvalue );
+ q = std::move(g)();
+ VERIFY( q.as_const && q.as_lvalue );
+ q = cg();
+ VERIFY( q.as_const && q.as_lvalue );
+ q = std::move(cg)();
+ VERIFY( q.as_const && q.as_lvalue );
+}
+
+template<typename... Args>
+void
+testBoundArgs(Args... args)
+{
+ struct F
+ {
+ quals operator()(Args..., int&) const { return { false, true }; }
+ quals operator()(Args..., int const&) const { return { true, true }; }
+ quals operator()(Args..., int&&) const { return { false, false }; }
+ quals operator()(Args..., int const&&) const { return { true, false }; }
+ };
+
+ constexpr F f;
+ auto g = bind_back<f>(args..., 10);
+ const auto& cg = g;
+ quals q;
+
+ // constness and value category should be forwarded to the bound objects:
+ q = g();
+ VERIFY( ! q.as_const && q.as_lvalue );
+ q = std::move(g)();
+ VERIFY( ! q.as_const && ! q.as_lvalue );
+ q = cg();
+ VERIFY( q.as_const && q.as_lvalue );
+ q = std::move(cg)();
+ VERIFY( q.as_const && ! q.as_lvalue );
+
+ int i = 0;
+ auto gr = bind_back<f>(args..., std::ref(i));
+ const auto& cgr = gr;
+
+ // bound object is reference wrapper, converts to same type of reference
+ q = gr();
+ VERIFY( ! q.as_const && q.as_lvalue );
+ q = std::move(gr)();
+ VERIFY( ! q.as_const && q.as_lvalue );
+ q = cgr();
+ VERIFY( ! q.as_const && q.as_lvalue );
+ q = std::move(cgr)();
+ VERIFY( ! q.as_const && q.as_lvalue );
+
+ auto gcr = bind_back<f>(args..., std::cref(i));
+ const auto& cgcr = gcr;
+
+ q = gcr();
+ VERIFY( q.as_const && q.as_lvalue );
+ q = std::move(gcr)();
+ VERIFY( q.as_const && q.as_lvalue );
+ q = cgcr();
+ VERIFY( q.as_const && q.as_lvalue );
+ q = std::move(cgcr)();
+ VERIFY( q.as_const && q.as_lvalue );
+}
+
+template<typename... Args>
+void
+testCallArgs(Args... args)
+{
+ struct F
+ {
+ quals operator()(int&, Args...) const { return { false, true }; }
+ quals operator()(int const&, Args...) const { return { true, true }; }
+ quals operator()(int&&, Args...) const { return { false, false }; }
+ quals operator()(int const&&, Args...) const { return { true, false }; }
+ };
+
+ constexpr F f;
+ auto g = bind_back<f>(args...);
+ const auto& cg = g;
+ quals q;
+ int i = 10;
+ const int ci = i;
+
+ q = g(i);
+ VERIFY( ! q.as_const && q.as_lvalue );
+ q = g(std::move(i));
+ VERIFY( ! q.as_const && ! q.as_lvalue );
+ q = g(ci);
+ VERIFY( q.as_const && q.as_lvalue );
+ q = g(std::move(ci));
+ VERIFY( q.as_const && ! q.as_lvalue );
+
+ q = cg(i);
+ VERIFY( ! q.as_const && q.as_lvalue );
+ q = cg(std::move(i));
+ VERIFY( ! q.as_const && ! q.as_lvalue );
+ q = cg(ci);
+ VERIFY( q.as_const && q.as_lvalue );
+ q = cg(std::move(ci));
+ VERIFY( q.as_const && ! q.as_lvalue );
+
+ struct S
+ {
+ int operator()(long, long, Args...) const { return 1; }
+ int operator()(int, void*, Args...) const { return 2; }
+ };
+
+ constexpr S s;
+ // literal zero can be converted to any pointer, so (int, void*)
+ // is best candidate
+ VERIFY( s(0, 0, args...) == 2 );
+ // both arguments are bound to int&&, and no longer can be
+ // converted to pointer, (long, long) is only candidate
+ VERIFY( bind_back<s>()(0, 0, args...) == 1 );
+ VERIFY( bind_back<s>(args...)(0, 0) == 1 );
+}
+
+void
+test03()
+{
+ struct F
+ {
+ int& operator()(void*, int& i) { return i; }
+ void* operator()(void* p, int) const { return p; }
+ };
+
+ int i = 5;
+ void* vp = &vp; // arbitrary void* value
+ constexpr F f;
+
+ // Bound arg always forwarded as const int& so can only call second overload:
+
+ auto g0 = bind_back<f>(); // call wrapper has no bound arg
+ using G0 = decltype(g0);
+ static_assert(is_invocable_r_v<void*, G0&, void*, int>);
+ static_assert(is_invocable_r_v<void*, G0&, void*, int&>);
+ static_assert(is_invocable_r_v<void*, G0&, void*, const int&>);
+ static_assert(is_invocable_r_v<void*, const G0&, void*, int>);
+ static_assert(is_invocable_r_v<void*, G0&&, void*, int>);
+ void* p0 = static_cast<G0&&>(g0)(vp, i);
+ VERIFY( p0 == vp );
+
+ auto g1 = bind_back<f>(i); // call wrapper has bound arg of type int
+ using G1 = decltype(g1);
+ static_assert(!is_invocable_r_v<int&, G1&, void*>);
+ static_assert(is_invocable_r_v<void*, const G1&, void*>);
+ static_assert(is_invocable_r_v<void*, G1&&, void*>);
+ void* p1 = static_cast<G1&&>(g1)(vp);
+ VERIFY( p1 == vp );
+
+ auto g2 = bind_back<f>(std::ref(i)); // bound arg of type int&
+ using G2 = decltype(g2);
+ static_assert(is_invocable_r_v<void*, G2&, void*>);
+ static_assert(is_invocable_r_v<void*, G2&&, void*>);
+ static_assert(is_invocable_r_v<void*, const G2&, void*>);
+ static_assert(is_invocable_r_v<void*, const G2&&, void*>);
+ void* p2 = g2(vp);
+ VERIFY( p2 == vp );
+ p2 = static_cast<G2&&>(g2)(vp);
+ VERIFY( p2 == vp );
+ p2 = const_cast<const G2&>(g2)(vp);
+ VERIFY( p2 == vp );
+
+ auto g3 = bind_back<f>(std::cref(i)); // bound arg of type const int&
+ using G3 = decltype(g3);
+ static_assert(is_invocable_r_v<void*, G3&, void*>);
+ static_assert(is_invocable_r_v<void*, G3&&, void*>);
+ static_assert(is_invocable_r_v<void*, const G3&, void*>);
+ static_assert(is_invocable_r_v<void*, const G3&&, void*>);
+}
+
+void test03a()
+{
+ struct F
+ {
+ int& operator()(void*, int& i) { return i; }
+ void* operator()(void* p, long) const { return p; }
+ };
+
+ int i = 5;
+ void* vp = &vp; // arbitrary void* value
+ constexpr F f;
+
+ // Bound arg always forwarded as const int& so can only call second overload:
+ auto g1 = bind_back<f>(i); // call wrapper has bound arg of type int
+ using G1 = decltype(g1);
+ static_assert(is_invocable_r_v<void*, G1&, void*>);
+ static_assert(is_invocable_r_v<void*, const G1&, void*>);
+ static_assert(is_invocable_r_v<void*, G1&&, void*>);
+ void* p1 = static_cast<G1&&>(g1)(vp);
+ VERIFY( p1 == vp );
+}
+
+
+constexpr int f(int i, int j, int k) { return i + 2*j + 3*k; }
+
+consteval bool
+test04()
+{
+ constexpr auto g = bind_back<f>();
+ VERIFY( std::is_empty_v<decltype(g)> );
+ VERIFY(g(1, 2, 3) == 1 + 2*2 + 3*3 );
+ constexpr auto g1 = bind_back<f>(1);
+ VERIFY(g1(2, 3) == 3*1 + 1*2 + 2*3 );
+ VERIFY(bind_back<g>(1)(2, 3) == 3*1 + 1*2 + 2*3 );
+ constexpr auto g2 = bind_back<f>(1, 2);
+ VERIFY(g2(3) == 2*1 + 3*2 + 1*3 );
+ constexpr auto g3 = bind_back<f>(1, 2, 3);
+ VERIFY(g3() == 1 + 2*2 + 3*3);
+ return true;
+}
+
+struct CountedArg
+{
+ CountedArg() = default;
+ CountedArg(CountedArg&& f) noexcept : counter(f.counter) { ++counter; }
+ CountedArg& operator=(CountedArg&&) = delete;
+
+ int counter = 0;
+};
+CountedArg const c;
+
+void
+testMaterialization()
+{
+ struct F
+ {
+ int operator()(CountedArg arg, int) const
+ { return arg.counter; };
+ };
+
+ // CountedArg is bound to rvalue-reference thus moved
+ auto f0 = std::bind_back<F{}>();
+ VERIFY( f0(CountedArg(), 10) == 1 );
+
+ auto f1 = std::bind_back<F{}>(10);
+ VERIFY( f1(CountedArg()) == 1 );
+}
+
+int
+main()
+{
+ test01();
+ test03();
+ test03a();
+ static_assert(test04());
+
+ testTarget();
+ testTarget(10);
+ testTarget(10, 20, 30);
+
+ testBoundArgs();
+ testBoundArgs(10);
+ testBoundArgs(10, 20, 30);
+
+ testCallArgs();
+ testCallArgs(10);
+ testCallArgs(10, 20, 30);
+
+ testMaterialization();
+}
diff --git a/libstdc++-v3/testsuite/20_util/function_objects/bind_back/nttp_neg.cc b/libstdc++-v3/testsuite/20_util/function_objects/bind_back/nttp_neg.cc
new file mode 100644
index 0000000..d64d49e
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/function_objects/bind_back/nttp_neg.cc
@@ -0,0 +1,38 @@
+// { dg-do compile { target c++26 } }
+
+#include <functional>
+
+void f() {};
+using fp = decltype(&f);
+constexpr fp nfp = nullptr;
+
+struct A { void mf() const {} };
+using mfp = decltype(&A::mf);
+constexpr mfp nnmfp = &A::mf;
+constexpr mfp nmfp = nullptr;
+
+struct B { B() = default; B(B const&) = delete; };
+void bf(B const&) {};
+
+struct C { C() = default; C(C&&) = delete; };
+void cf(C&&) {};
+
+int main()
+{
+ std::bind_back<f>()();
+ // Verify bind_back<fn> with fn a null pointer fails.
+ std::bind_back<nfp>()(); // { dg-error "here" }
+
+ std::bind_back<nnmfp>(A{})();
+ // Verify bind_back<mfn> with mfn a null member pointer fails.
+ std::bind_back<nmfp>(A{})(); // { dg-error "here" }
+
+ // Verify passing uncopyable type fails.
+ std::bind_back<bf>(B{}); // { dg-error "here" }
+ //
+ // Verify passing unmovable type fails.
+ std::bind_back<cf>(C{}); // { dg-error "here" }
+}
+
+// { dg-error "static assertion failed" "" { target *-*-* } 0 }
+// { dg-error "use of deleted function" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/20_util/function_objects/bind_front/1.cc b/libstdc++-v3/testsuite/20_util/function_objects/bind_front/1.cc
index 57482c5..56bdaaa 100644
--- a/libstdc++-v3/testsuite/20_util/function_objects/bind_front/1.cc
+++ b/libstdc++-v3/testsuite/20_util/function_objects/bind_front/1.cc
@@ -48,6 +48,15 @@ test01()
decltype(bind_front(std::declval<const F&>(), std::declval<const int&>()))
>);
+ static_assert(std::is_same_v<
+ decltype(bind_front(std::declval<F>(), std::declval<int>(), std::declval<float>())),
+ decltype(bind_front(std::declval<F&>(), std::declval<int&>(), std::declval<float&>()))
+ >);
+ static_assert(std::is_same_v<
+ decltype(bind_front(std::declval<F>(), std::declval<int>(), std::declval<float>())),
+ decltype(bind_front(std::declval<const F&>(), std::declval<const int&>(), std::declval<const float&>()))
+ >);
+
// Reference wrappers should be handled:
static_assert(!std::is_same_v<
decltype(bind_front(std::declval<F>(), std::declval<int&>())),
@@ -63,29 +72,58 @@ test01()
>);
}
+struct quals
+{
+ bool as_const;
+ bool as_lvalue;
+};
+
+template<typename... Args>
void
-test02()
+testTarget(Args... args)
{
- struct quals
+ struct F
{
- bool as_const;
- bool as_lvalue;
+ quals operator()(Args...) & { return { false, true }; }
+ quals operator()(Args...) const & { return { true, true }; }
+ quals operator()(Args...) && { return { false, false }; }
+ quals operator()(Args...) const && { return { true, false }; }
};
+ F f;
+ auto g = bind_front(f, args...);
+ const auto& cg = g;
+ quals q;
+
+ // constness and value category should be forwarded to the target object:
+ q = g();
+ VERIFY( ! q.as_const && q.as_lvalue );
+ q = std::move(g)();
+ VERIFY( ! q.as_const && ! q.as_lvalue );
+ q = cg();
+ VERIFY( q.as_const && q.as_lvalue );
+ q = std::move(cg)();
+ VERIFY( q.as_const && ! q.as_lvalue );
+}
+
+template<typename... Args>
+void
+testBoundArgs(Args... args)
+{
struct F
{
- quals operator()() & { return { false, true }; }
- quals operator()() const & { return { true, true }; }
- quals operator()() && { return { false, false }; }
- quals operator()() const && { return { true, false }; }
+ quals operator()(Args..., int&) const { return { false, true }; }
+ quals operator()(Args..., int const&) const { return { true, true }; }
+ quals operator()(Args..., int&&) const { return { false, false }; }
+ quals operator()(Args..., int const&&) const { return { true, false }; }
};
F f;
- auto g = bind_front(f);
+ auto g = bind_front(f, args..., 10);
const auto& cg = g;
quals q;
- // constness and value category should be forwarded to the target object:
+ // constness and value category should be forwarded to the bound objects:
q = g();
VERIFY( ! q.as_const && q.as_lvalue );
q = std::move(g)();
@@ -94,6 +132,85 @@ test02()
VERIFY( q.as_const && q.as_lvalue );
q = std::move(cg)();
VERIFY( q.as_const && ! q.as_lvalue );
+
+ int i = 0;
+ auto gr = bind_front(f, args..., std::ref(i));
+ const auto& cgr = gr;
+
+ // bound object is reference wrapper, converts to same type of reference
+ q = gr();
+ VERIFY( ! q.as_const && q.as_lvalue );
+ q = std::move(gr)();
+ VERIFY( ! q.as_const && q.as_lvalue );
+ q = cgr();
+ VERIFY( ! q.as_const && q.as_lvalue );
+ q = std::move(cgr)();
+ VERIFY( ! q.as_const && q.as_lvalue );
+
+ auto gcr = bind_front(f, args..., std::cref(i));
+ const auto& cgcr = gcr;
+
+ q = gcr();
+ VERIFY( q.as_const && q.as_lvalue );
+ q = std::move(gcr)();
+ VERIFY( q.as_const && q.as_lvalue );
+ q = cgcr();
+ VERIFY( q.as_const && q.as_lvalue );
+ q = std::move(cgcr)();
+ VERIFY( q.as_const && q.as_lvalue );
+}
+
+template<typename... Args>
+void
+testCallArgs(Args... args)
+{
+ struct F
+ {
+ quals operator()(Args..., int&) const { return { false, true }; }
+ quals operator()(Args..., int const&) const { return { true, true }; }
+ quals operator()(Args..., int&&) const { return { false, false }; }
+ quals operator()(Args..., int const&&) const { return { true, false }; }
+ };
+
+ F f;
+ auto g = bind_front(f, args...);
+ const auto& cg = g;
+ quals q;
+ int i = 10;
+ const int ci = i;
+
+ q = g(i);
+ VERIFY( ! q.as_const && q.as_lvalue );
+ q = g(std::move(i));
+ VERIFY( ! q.as_const && ! q.as_lvalue );
+ q = g(ci);
+ VERIFY( q.as_const && q.as_lvalue );
+ q = g(std::move(ci));
+ VERIFY( q.as_const && ! q.as_lvalue );
+
+ q = cg(i);
+ VERIFY( ! q.as_const && q.as_lvalue );
+ q = cg(std::move(i));
+ VERIFY( ! q.as_const && ! q.as_lvalue );
+ q = cg(ci);
+ VERIFY( q.as_const && q.as_lvalue );
+ q = cg(std::move(ci));
+ VERIFY( q.as_const && ! q.as_lvalue );
+
+ struct S
+ {
+ int operator()(Args..., long, long) const { return 1; }
+ int operator()(Args..., int, void*) const { return 2; }
+ };
+
+ S s;
+ // literal zero can be converted to any pointer, so (int, void*)
+ // is best candidate
+ VERIFY( s(args..., 0, 0) == 2 );
+ // both arguments are bound to int&&, and no longer can be
+ // converted to pointer, (long, long) is only candidate
+ VERIFY( bind_front(s)(args..., 0, 0) == 1 );
+ VERIFY( bind_front(s, args...)(0, 0) == 1 );
}
void
@@ -149,29 +266,69 @@ test03()
static_assert(is_invocable_r_v<void*, const G4&&>);
}
-int f(int i, int j, int k) { return i + j + k; }
+int f(int i, int j, int k) { return i + 2*j + 3*k; }
void
test04()
{
auto g = bind_front(f);
- VERIFY( g(1, 2, 3) == 6 );
+ VERIFY( g(1, 2, 3) == 14 );
auto g1 = bind_front(f, 1);
- VERIFY( g1(2, 3) == 6 );
- VERIFY( bind_front(g, 1)(2, 3) == 6 );
+ VERIFY( g1(2, 3) == 14 );
+ VERIFY( bind_front(g, 1)(2, 3) == 14 );
auto g2 = bind_front(f, 1, 2);
- VERIFY( g2(3) == 6 );
- VERIFY( bind_front(g1, 2)(3) == 6 );
+ VERIFY( g2(3) == 14 );
+ VERIFY( bind_front(g1, 2)(3) == 14 );
auto g3 = bind_front(f, 1, 2, 3);
- VERIFY( g3() == 6 );
- VERIFY( bind_front(g2, 3)() == 6 );
+ VERIFY( g3() == 14 );
+ VERIFY( bind_front(g2, 3)() == 14 );
+}
+
+struct CountedArg
+{
+ CountedArg() = default;
+ CountedArg(CountedArg&& f) noexcept : counter(f.counter) { ++counter; }
+ CountedArg& operator=(CountedArg&&) = delete;
+
+ int counter = 0;
+};
+CountedArg const c;
+
+void
+testMaterialization()
+{
+ struct F
+ {
+ int operator()(int, CountedArg arg) const
+ { return arg.counter; };
+ };
+
+ // CountedArg is bound to rvalue-reference thus moved
+ auto f0 = std::bind_front(F{});
+ VERIFY( f0(10, CountedArg()) == 1 );
+
+ auto f1 = std::bind_front(F{}, 10);
+ VERIFY( f1(CountedArg()) == 1 );
}
int
main()
{
test01();
- test02();
test03();
test04();
+
+ testTarget();
+ testTarget(10);
+ testTarget(10, 20, 30);
+
+ testBoundArgs();
+ testBoundArgs(10);
+ testBoundArgs(10, 20, 30);
+
+ testCallArgs();
+ testCallArgs(10);
+ testCallArgs(10, 20, 30);
+
+ testMaterialization();
}
diff --git a/libstdc++-v3/testsuite/20_util/function_objects/bind_front/111327.cc b/libstdc++-v3/testsuite/20_util/function_objects/bind_front/111327.cc
index 5fe0a83..493ef08 100644
--- a/libstdc++-v3/testsuite/20_util/function_objects/bind_front/111327.cc
+++ b/libstdc++-v3/testsuite/20_util/function_objects/bind_front/111327.cc
@@ -37,6 +37,17 @@ int main() {
g1(); // { dg-error "deleted|no match" }
std::move(g1)(); // { dg-error "deleted|no match" }
std::move(std::as_const(g1))();
+
+ auto f2 = std::bind_front(F{}, 42, 10);
+ f2(); // { dg-error "deleted|no match" }
+ std::move(f2)();
+ std::as_const(f2)();
+ std::move(std::as_const(f2))();
+
+ auto g2 = std::bind_front(G{}, 42, 10);
+ g2(); // { dg-error "deleted|no match" }
+ std::move(g2)(); // { dg-error "deleted|no match" }
+ std::move(std::as_const(g2))();
}
-// { dg-error "no type named 'type' in 'struct std::invoke_result" "" { target c++23 } 0 }
+// { dg-error "no type named 'type' in 'std::__conditional_t<false, std::invoke_result<" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/20_util/function_objects/bind_front/nttp.cc b/libstdc++-v3/testsuite/20_util/function_objects/bind_front/nttp.cc
new file mode 100644
index 0000000..cf84353
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/function_objects/bind_front/nttp.cc
@@ -0,0 +1,345 @@
+// { dg-do run { target c++26 } }
+// { dg-add-options no_pch }
+
+// Test NTTP bind_front<f>(Args...), P2714
+
+#include <functional>
+
+#ifndef __cpp_lib_bind_front
+# error "Feature test macro for bind_front is missing in <functional>"
+#elif __cpp_lib_bind_front < 202306L
+# error "Feature test macro for bind_front has wrong value in <functional>"
+#endif
+
+#include <testsuite_hooks.h>
+
+using std::bind_front;
+using std::is_same_v;
+using std::is_invocable_v;
+using std::is_invocable_r_v;
+
+void
+test01()
+{
+ struct F { void operator()(int) {} };
+ constexpr F f{};
+
+ // Arguments should be decayed:
+ static_assert(std::is_same_v<
+ decltype(bind_front<f>(std::declval<int>())),
+ decltype(bind_front<f>(std::declval<int&>()))
+ >);
+ static_assert(std::is_same_v<
+ decltype(bind_front<f>(std::declval<int>())),
+ decltype(bind_front<f>(std::declval<const int&>()))
+ >);
+
+ static_assert(std::is_same_v<
+ decltype(bind_front<f>(std::declval<int>(), std::declval<float>())),
+ decltype(bind_front<f>(std::declval<int&>(), std::declval<float&>()))
+ >);
+ static_assert(std::is_same_v<
+ decltype(bind_front<f>(std::declval<int>(), std::declval<float>())),
+ decltype(bind_front<f>(std::declval<const int&>(), std::declval<const float&>()))
+ >);
+
+ // Reference wrappers should be handled:
+ static_assert(!std::is_same_v<
+ decltype(bind_front<f>(std::declval<int&>())),
+ decltype(bind_front<f>(std::ref(std::declval<int&>())))
+ >);
+ static_assert(!std::is_same_v<
+ decltype(bind_front<f>(std::declval<const int&>())),
+ decltype(bind_front<f>(std::cref(std::declval<int&>())))
+ >);
+ static_assert(!std::is_same_v<
+ decltype(bind_front<f>(std::ref(std::declval<int&>()))),
+ decltype(bind_front<f>(std::cref(std::declval<int&>())))
+ >);
+}
+
+struct quals
+{
+ bool as_const;
+ bool as_lvalue;
+};
+
+template<typename... Args>
+void
+testTarget(Args... args)
+{
+ struct F
+ {
+ quals operator()(Args...) & { return { false, true }; }
+ quals operator()(Args...) const & { return { true, true }; }
+ quals operator()(Args...) && { return { false, false }; }
+ quals operator()(Args...) const && { return { true, false }; }
+ };
+
+ constexpr F f;
+ auto g = bind_front<f>(args...);
+ const auto& cg = g;
+ quals q;
+
+ // template parameter object is always constant lvalue
+ q = g();
+ VERIFY( q.as_const && q.as_lvalue );
+ q = std::move(g)();
+ VERIFY( q.as_const && q.as_lvalue );
+ q = cg();
+ VERIFY( q.as_const && q.as_lvalue );
+ q = std::move(cg)();
+ VERIFY( q.as_const && q.as_lvalue );
+}
+
+template<typename... Args>
+void
+testBoundArgs(Args... args)
+{
+ struct F
+ {
+ quals operator()(Args..., int&) const { return { false, true }; }
+ quals operator()(Args..., int const&) const { return { true, true }; }
+ quals operator()(Args..., int&&) const { return { false, false }; }
+ quals operator()(Args..., int const&&) const { return { true, false }; }
+ };
+
+ constexpr F f;
+ auto g = bind_front<f>(args..., 10);
+ const auto& cg = g;
+ quals q;
+
+ // constness and value category should be forwarded to the bound objects:
+ q = g();
+ VERIFY( ! q.as_const && q.as_lvalue );
+ q = std::move(g)();
+ VERIFY( ! q.as_const && ! q.as_lvalue );
+ q = cg();
+ VERIFY( q.as_const && q.as_lvalue );
+ q = std::move(cg)();
+ VERIFY( q.as_const && ! q.as_lvalue );
+
+ int i = 0;
+ auto gr = bind_front<f>(args..., std::ref(i));
+ const auto& cgr = gr;
+
+ // bound object is reference wrapper, converts to same type of reference
+ q = gr();
+ VERIFY( ! q.as_const && q.as_lvalue );
+ q = std::move(gr)();
+ VERIFY( ! q.as_const && q.as_lvalue );
+ q = cgr();
+ VERIFY( ! q.as_const && q.as_lvalue );
+ q = std::move(cgr)();
+ VERIFY( ! q.as_const && q.as_lvalue );
+
+ auto gcr = bind_front<f>(args..., std::cref(i));
+ const auto& cgcr = gcr;
+
+ q = gcr();
+ VERIFY( q.as_const && q.as_lvalue );
+ q = std::move(gcr)();
+ VERIFY( q.as_const && q.as_lvalue );
+ q = cgcr();
+ VERIFY( q.as_const && q.as_lvalue );
+ q = std::move(cgcr)();
+ VERIFY( q.as_const && q.as_lvalue );
+}
+
+template<typename... Args>
+void
+testCallArgs(Args... args)
+{
+ struct F
+ {
+ quals operator()(Args..., int&) const { return { false, true }; }
+ quals operator()(Args..., int const&) const { return { true, true }; }
+ quals operator()(Args..., int&&) const { return { false, false }; }
+ quals operator()(Args..., int const&&) const { return { true, false }; }
+ };
+
+ constexpr F f;
+ auto g = bind_front<f>(args...);
+ const auto& cg = g;
+ quals q;
+ int i = 10;
+ const int ci = i;
+
+ q = g(i);
+ VERIFY( ! q.as_const && q.as_lvalue );
+ q = g(std::move(i));
+ VERIFY( ! q.as_const && ! q.as_lvalue );
+ q = g(ci);
+ VERIFY( q.as_const && q.as_lvalue );
+ q = g(std::move(ci));
+ VERIFY( q.as_const && ! q.as_lvalue );
+
+ q = cg(i);
+ VERIFY( ! q.as_const && q.as_lvalue );
+ q = cg(std::move(i));
+ VERIFY( ! q.as_const && ! q.as_lvalue );
+ q = cg(ci);
+ VERIFY( q.as_const && q.as_lvalue );
+ q = cg(std::move(ci));
+ VERIFY( q.as_const && ! q.as_lvalue );
+
+ struct S
+ {
+ int operator()(Args..., long, long) const { return 1; }
+ int operator()(Args..., int, void*) const { return 2; }
+ };
+
+ constexpr S s;
+ // literal zero can be converted to any pointer, so (int, void*)
+ // is best candidate
+ VERIFY( s(args..., 0, 0) == 2 );
+ // both arguments are bound to int&&, and no longer can be
+ // converted to pointer, (long, long) is only candidate
+ VERIFY( bind_front<s>()(args..., 0, 0) == 1 );
+ VERIFY( bind_front<s>(args...)(0, 0) == 1 );
+}
+
+void
+test03()
+{
+ struct F
+ {
+ int& operator()(int& i, void*) { return i; }
+ void* operator()(long, void* p) const { return p; }
+ };
+
+ int i = 5;
+ void* vp = &vp; // arbitrary void* value
+ constexpr F f;
+
+ // Bound arg always forwarded as const int& so can only call second overload:
+
+ auto g0 = bind_front<f>(); // call wrapper has no bound arg
+ using G0 = decltype(g0);
+ static_assert(is_invocable_r_v<void*, G0&, int, void*>);
+ static_assert(is_invocable_r_v<void*, G0&, int&, void*>);
+ static_assert(is_invocable_r_v<void*, G0&, const int&, void*>);
+ static_assert(is_invocable_r_v<void*, const G0&, int, void*>);
+ static_assert(is_invocable_r_v<void*, G0&&, int, void*>);
+ void* p0 = static_cast<G0&&>(g0)(i, vp);
+ VERIFY( p0 == vp );
+
+ auto g1 = bind_front<f>(i); // call wrapper has bound arg of type int
+ using G1 = decltype(g1);
+ static_assert(!is_invocable_r_v<int&, G1&, void*>);
+ static_assert(is_invocable_r_v<void*, const G1&, void*>);
+ static_assert(is_invocable_r_v<void*, G1&&, void*>);
+ void* p1 = static_cast<G1&&>(g1)(vp);
+ VERIFY( p1 == vp );
+
+ auto g2 = bind_front<f>(std::ref(i)); // bound arg of type int&
+ using G2 = decltype(g2);
+ static_assert(is_invocable_r_v<void*, G2&, void*>);
+ static_assert(is_invocable_r_v<void*, G2&&, void*>);
+ static_assert(is_invocable_r_v<void*, const G2&, void*>);
+ static_assert(is_invocable_r_v<void*, const G2&&, void*>);
+ void* p2 = g2(vp);
+ VERIFY( p2 == vp );
+ p2 = static_cast<G2&&>(g2)(vp);
+ VERIFY( p2 == vp );
+ p2 = const_cast<const G2&>(g2)(vp);
+ VERIFY( p2 == vp );
+
+ auto g3 = bind_front<f>(std::cref(i)); // bound arg of type const int&
+ using G3 = decltype(g3);
+ static_assert(is_invocable_r_v<void*, G3&, void*>);
+ static_assert(is_invocable_r_v<void*, G3&&, void*>);
+ static_assert(is_invocable_r_v<void*, const G3&, void*>);
+ static_assert(is_invocable_r_v<void*, const G3&&, void*>);
+}
+
+void test03a()
+{
+ struct F
+ {
+ int& operator()(int& i, void*) { return i; }
+ void* operator()(long, void* p) const { return p; }
+ };
+
+ int i = 5;
+ void* vp = &vp; // arbitrary void* value
+ constexpr F f;
+
+ // Bound arg always forwarded as const int& so can only call second overload:
+ auto g1 = bind_front<f>(i); // call wrapper has bound arg of type int
+ using G1 = decltype(g1);
+ static_assert(is_invocable_r_v<void*, G1&, void*>);
+ static_assert(is_invocable_r_v<void*, const G1&, void*>);
+ static_assert(is_invocable_r_v<void*, G1&&, void*>);
+ void* p1 = static_cast<G1&&>(g1)(vp);
+ VERIFY( p1 == vp );
+}
+
+constexpr int f(int i, int j, int k) { return i + 2*j + 3*k; }
+
+consteval bool
+test04()
+{
+ constexpr auto g = bind_front<f>();
+ VERIFY( std::is_empty_v<decltype(g)> );
+ VERIFY( g(1, 2, 3) == 1 + 2*2 + 3*3 );
+ constexpr auto g1 = bind_front<f>(1);
+ VERIFY( g1(2, 3) == 1 + 2*2 + 3*3 );
+ VERIFY( bind_front<g>(1)(2, 3) == 1 + 2*2 + 3*3 );
+ constexpr auto g2 = bind_front<f>(1, 2);
+ VERIFY( g2(3) == 1 + 2*2 + 3*3 );
+ constexpr auto g3 = bind_front<f>(1, 2, 3);
+ VERIFY( g3() == 1 + 2*2 + 3*3 );
+ return true;
+}
+
+struct CountedArg
+{
+ CountedArg() = default;
+ CountedArg(CountedArg&& f) noexcept : counter(f.counter) { ++counter; }
+ CountedArg& operator=(CountedArg&&) = delete;
+
+ int counter = 0;
+};
+CountedArg const c;
+
+void
+testMaterialization()
+{
+ struct F
+ {
+ int operator()(int, CountedArg arg) const
+ { return arg.counter; };
+ };
+
+ // CountedArg is bound to rvalue-reference thus moved
+ auto f0 = std::bind_front<F{}>();
+ VERIFY( f0(10, CountedArg()) == 1 );
+
+ auto f1 = std::bind_front<F{}>(10);
+ VERIFY( f1(CountedArg()) == 1 );
+}
+
+int
+main()
+{
+ test01();
+ test03();
+ test03a();
+ static_assert(test04());
+
+ testTarget();
+ testTarget(10);
+ testTarget(10, 20, 30);
+
+ testBoundArgs();
+ testBoundArgs(10);
+ testBoundArgs(10, 20, 30);
+
+ testCallArgs();
+ testCallArgs(10);
+ testCallArgs(10, 20, 30);
+
+ testMaterialization();
+
+}
diff --git a/libstdc++-v3/testsuite/20_util/function_objects/bind_front/nttp_neg.cc b/libstdc++-v3/testsuite/20_util/function_objects/bind_front/nttp_neg.cc
new file mode 100644
index 0000000..d274c19
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/function_objects/bind_front/nttp_neg.cc
@@ -0,0 +1,38 @@
+// { dg-do compile { target c++26 } }
+
+#include <functional>
+
+void f() {}
+using fp = decltype(&f);
+constexpr fp nfp = nullptr;
+
+struct A { void mf() const {} };
+using mfp = decltype(&A::mf);
+constexpr mfp nnmfp = &A::mf;
+constexpr mfp nmfp = nullptr;
+
+struct B { B() = default; B(B const&) = delete; };
+void bf(B const&) {};
+
+struct C { C() = default; C(C&&) = delete; };
+void cf(C&&) {};
+
+int main()
+{
+ std::bind_front<f>()();
+ // Verify bind_front<fn> with fn a null pointer fails:
+ std::bind_front<nfp>()(); // { dg-error "here" }
+
+ std::bind_front<nnmfp>(A{})();
+ // Verify bind_front<mfn> with mfn a null member pointer fails:
+ std::bind_front<nmfp>(A{})(); // { dg-error "here" }
+
+ // Verify passing uncopyable type fails:
+ std::bind_front<bf>(B{}); // { dg-error "here" }
+ //
+ // Verify passing unmovable type fails:
+ std::bind_front<cf>(C{}); // { dg-error "here" }
+}
+
+// { dg-error "static assertion failed" "" { target *-*-* } 0 }
+// { dg-error "use of deleted function" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/20_util/function_objects/not_fn/111327.cc b/libstdc++-v3/testsuite/20_util/function_objects/not_fn/111327.cc
index 725a842..be58b0e 100644
--- a/libstdc++-v3/testsuite/20_util/function_objects/not_fn/111327.cc
+++ b/libstdc++-v3/testsuite/20_util/function_objects/not_fn/111327.cc
@@ -15,15 +15,28 @@ struct G {
bool operator()(...) const &&;
};
+struct Weird {
+ void operator()();
+ bool operator()() const { return true; }
+};
+
int main() {
auto f = std::not_fn(F{});
- f(); // { dg-error "deleted" }
+ f(); // { dg-error "no match" }
std::move(f)();
std::as_const(f)();
std::move(std::as_const(f))();
auto g = std::not_fn(G{});
- g(); // { dg-error "deleted" }
- std::move(g)(); // { dg-error "deleted" }
+ g(); // { dg-error "no match" }
+ std::move(g)(); // { dg-error "no match" }
std::move(std::as_const(g))();
+
+ auto h = std::not_fn(Weird{});
+ h(); // { dg-error "no match" }
}
+
+// { dg-error "no type named 'type' in 'struct std::__invoke_result<" "" { target *-*-* } 0 }
+// { dg-error "no matching function for call to 'std::_Not_fn<Weird>" "" { target *-*-* } 0 }
+// { dg-error "could not convert 'std::declval<void>\\(\\)' from 'void' to 'bool'" "" { target *-*-* } 0 }
+// { dg-error "in argument to unary !" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/20_util/function_objects/not_fn/nttp.cc b/libstdc++-v3/testsuite/20_util/function_objects/not_fn/nttp.cc
new file mode 100644
index 0000000..3567d67
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/function_objects/not_fn/nttp.cc
@@ -0,0 +1,141 @@
+// Test NTTP version of not_fn, from P2714
+
+// { dg-do run { target c++26 } }
+
+#include <functional>
+#include <testsuite_hooks.h>
+
+using std::not_fn;
+
+int func(int, char) { return 0; }
+
+struct F
+{
+ bool operator()() { return false; }
+ bool operator()() const { return true; }
+ bool operator()(int) const { return false; }
+};
+
+void
+test01()
+{
+ auto f1 = not_fn<func>();
+ VERIFY( std::is_empty_v<decltype(f1)> );
+ VERIFY( f1(1, '2') == true );
+
+ auto f2 = not_fn<[] { return true; }>();
+ VERIFY( std::is_empty_v<decltype(f2)> );
+ VERIFY( f2() == false );
+
+ auto f3 = not_fn<F{}>();
+ VERIFY( f3() == false ); // Prefer the const member.
+ VERIFY( f3(1) == true );
+ const auto f4 = f3;
+ VERIFY( f4() == false );
+}
+
+void
+test04()
+{
+ struct abstract { virtual void f() = 0; };
+ struct derived : abstract { void f() { } };
+ struct F { bool operator()(const abstract&) const { return false; } };
+ constexpr F f;
+ constexpr derived d;
+ VERIFY( not_fn<f>()(d) );
+}
+
+void
+test05()
+{
+ auto nf = std::not_fn<[] { return false; }>();
+ auto copy(nf); // PR libstdc++/70564
+}
+
+void
+test06()
+{
+ struct Boolean {
+ Boolean operator!() const noexcept(false) { return *this; }
+ };
+ struct F {
+ Boolean operator()() const { return {}; }
+ };
+ const F f;
+ const auto notf = std::not_fn<f>();
+ using NotF = decltype(notf);
+ static_assert( std::is_invocable<NotF>::value, "cannot negate" );
+ static_assert( !noexcept(notf()), "conversion to bool affects noexcept" );
+}
+
+void
+test07()
+{
+ struct NonNegatable { }; // there is no operator!(NonNegatable)
+ struct F {
+ NonNegatable operator()() const { return {}; }
+ };
+ F f;
+ constexpr auto notf = std::not_fn<f>();
+ using NotF = decltype(notf);
+ static_assert( !std::is_invocable<NotF>::value, "cannot negate" );
+}
+
+void
+test08()
+{
+ struct quals
+ {
+ bool as_const;
+ bool as_lvalue;
+
+ quals operator!() const
+ { return *this; };
+ };
+
+ struct F
+ {
+ quals operator()(int&) const { return { false, true }; }
+ quals operator()(int const&) const { return { true, true }; }
+ quals operator()(int&&) const { return { false, false }; }
+ quals operator()(int const&&) const { return { true, false }; }
+ };
+
+ constexpr F f;
+ auto g = not_fn<f>();
+ const auto& cg = g;
+ quals q;
+ int i = 10;
+ const int ci = i;
+
+ q = g(i);
+ VERIFY( ! q.as_const && q.as_lvalue );
+ q = g(std::move(i));
+ VERIFY( ! q.as_const && ! q.as_lvalue );
+ q = g(ci);
+ VERIFY( q.as_const && q.as_lvalue );
+ q = g(std::move(ci));
+ VERIFY( q.as_const && ! q.as_lvalue );
+
+ q = cg(i);
+ VERIFY( ! q.as_const && q.as_lvalue );
+ q = cg(std::move(i));
+ VERIFY( ! q.as_const && ! q.as_lvalue );
+ q = cg(ci);
+ VERIFY( q.as_const && q.as_lvalue );
+ q = cg(std::move(ci));
+ VERIFY( q.as_const && ! q.as_lvalue );
+}
+
+int
+main()
+{
+ test01();
+ test04();
+ test05();
+ test06();
+ test07();
+ test08();
+ constexpr auto f = []{ return false; };
+ static_assert(std::not_fn<f>()());
+}
diff --git a/libstdc++-v3/testsuite/20_util/function_objects/not_fn/nttp_neg.cc b/libstdc++-v3/testsuite/20_util/function_objects/not_fn/nttp_neg.cc
new file mode 100644
index 0000000..7875273
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/function_objects/not_fn/nttp_neg.cc
@@ -0,0 +1,28 @@
+// { dg-do compile { target c++26 } }
+
+#include <functional>
+
+bool f() { return {}; }
+using fp = decltype(&f);
+constexpr fp nfp = nullptr;
+
+struct A { bool mf() const { return {}; } };
+using mfp = decltype(&A::mf);
+constexpr mfp nnmfp = &A::mf;
+constexpr mfp nmfp = nullptr;
+constexpr A a;
+
+int main()
+{
+ (void) std::not_fn<f>()();
+
+ // Verify not_fn<fn> with fn a null pointer fails.
+ (void) std::not_fn<nfp>()(); // { dg-error "here" }
+ //
+ (void) std::not_fn<nnmfp>()(a);
+
+ // Verify not_fn<mfn> with mfn a null member pointer fails.
+ return std::not_fn<nmfp>()(a); // { dg-error "here" }
+}
+
+// { dg-error "static assertion failed" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/20_util/function_objects/not_fn/version.cc b/libstdc++-v3/testsuite/20_util/function_objects/not_fn/version.cc
new file mode 100644
index 0000000..fc8a3c9
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/function_objects/not_fn/version.cc
@@ -0,0 +1,12 @@
+// { dg-do preprocess { target c++17 } }
+// { dg-add-options no_pch }
+
+#include <functional>
+
+#ifndef __cpp_lib_not_fn
+# error "Feature test macro for not_fn is missing in <functional>"
+#elif __cpp_lib_not_fn < 201603L
+# error "Feature test macro __cpp_lib_not_fn has the wrong value for C++17 or later"
+#elif __cplusplus > 202302L && __cpp_lib_not_fn < 202306L
+# error "Feature test macro __cpp_lib_not_fn has the wrong value for C++26 or later"
+#endif
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..49c6030
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/function_ref/call.cc
@@ -0,0 +1,263 @@
+// { 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 );
+}
+
+void
+test06()
+{
+ struct S {
+ int v;
+ int& m() { return v; }
+ const int& c() const { return v; }
+
+ int& operator()(int) { return v; }
+ int const& operator()(int, int) const { return v; }
+ };
+ S s{10};
+ std::reference_wrapper<S> sr(s);
+ std::reference_wrapper<const S> csr(s);
+
+ std::function_ref<int&(int)> e1(sr);
+ VERIFY( &e1(0) == &s.v );
+ std::function_ref<int&(int) const> e2(sr);
+ VERIFY( &e2(0) == &s.v );
+ std::function_ref<int&(int) const> e3(std::as_const(sr));
+ VERIFY( &e3(0) == &s.v );
+
+ std::function_ref<const int&(int, int)> e4(sr);
+ VERIFY( &e4(0, 0) == &s.v );
+ std::function_ref<const int&(int, int) const> e5(sr);
+ VERIFY( &e5(0, 0) == &s.v );
+ std::function_ref<const int&(int, int)> e6(csr);
+ VERIFY( &e6(0, 0) == &s.v );
+ std::function_ref<const int&(int, int) const> e7(csr);
+ VERIFY( &e7(0, 0) == &s.v );
+ std::function_ref<const int&(int, int) const> e8(std::as_const(csr));
+ VERIFY( &e8(0, 0) == &s.v );
+
+ std::function_ref<int&()> f1(std::nontype<&S::v>, sr);
+ VERIFY( &f1() == &s.v );
+ std::function_ref<const int&()> f2(std::nontype<&S::v>, sr);
+ VERIFY( &f2() == &s.v );
+ std::function_ref<int&()> f3(std::nontype<&S::m>, sr);
+ VERIFY( &f3() == &s.v );
+ std::function_ref<const int&()> f4(std::nontype<&S::c>, sr);
+ VERIFY( &f4() == &s.v );
+
+ std::function_ref<const int&()> f5(std::nontype<&S::v>, csr);
+ VERIFY( &f5() == &s.v );
+ std::function_ref<const int&()> f6(std::nontype<&S::c>, sr);
+ VERIFY( &f6() == &s.v );
+ static_assert( !std::is_constructible_v<
+ std::function_ref<int&()>,
+ std::nontype_t<&S::c>, std::reference_wrapper<S>&>
+ );
+
+ std::function_ref<int&()> f7(std::nontype<&S::v>, std::as_const(sr));
+ VERIFY( &f7() == &s.v );
+ std::function_ref<const int&()> f8(std::nontype<&S::m>, std::as_const(sr));
+ VERIFY( &f8() == &s.v );
+
+ // No rvalue reference_wrapper support
+ static_assert( !std::is_constructible_v<
+ std::function_ref<int&()>,
+ std::nontype_t<&S::v>, std::reference_wrapper<S>>
+ );
+ static_assert( !std::is_constructible_v<
+ std::function_ref<int&()>,
+ std::nontype_t<&S::v>, std::reference_wrapper<const S>>
+ );
+
+ // reference to reference_wrapper are bound, so mutation are visible
+ S s2{20};
+ sr = s2;
+ csr = s2;
+ VERIFY( &e1(0) == &s2.v );
+ VERIFY( &e2(0) == &s2.v );
+ VERIFY( &e3(0) == &s2.v );
+ VERIFY( &e4(0, 0) == &s2.v );
+ VERIFY( &e5(0, 0) == &s2.v );
+ VERIFY( &e6(0, 0) == &s2.v );
+ VERIFY( &e7(0, 0) == &s2.v );
+ VERIFY( &e8(0, 0) == &s2.v );
+ VERIFY( &f1() == &s2.v );
+ VERIFY( &f2() == &s2.v );
+ VERIFY( &f3() == &s2.v );
+ VERIFY( &f4() == &s2.v );
+ VERIFY( &f5() == &s2.v );
+ VERIFY( &f6() == &s2.v );
+ VERIFY( &f7() == &s2.v );
+ VERIFY( &f8() == &s2.v );
+
+ constexpr auto id = []<typename T>(const std::reference_wrapper<T>& x)
+ { return &x; };
+
+ // identity of reference_wrapper is preserved
+ std::function_ref<const std::reference_wrapper<S>*()> g1(std::nontype<id>, sr);
+ VERIFY( g1() == &sr );
+ std::function_ref<const std::reference_wrapper<const S>*()> g2(std::nontype<id>, csr);
+ VERIFY( g2() == &csr );
+}
+
+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();
+ test05();
+ test06();
+ 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..b034c7a
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/function_ref/deduction.cc
@@ -0,0 +1,131 @@
+// { 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;
+
+template<auto f, class... Args>
+ concept deductible = requires (Args&... args)
+ { std::function_ref(std::nontype<f>, args...); };
+
+static_assert( !deductible<1> );
+static_assert( !deductible<1, int> );
+
+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>> );
+static_assert( !deductible<f0, char*> );
+static_assert( !deductible<f0n, char*> );
+
+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>> );
+static_assert( !deductible<f1, char*> );
+static_assert( !deductible<f1n, char*> );
+
+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>> );
+static_assert( !deductible<f2, char*> );
+static_assert( !deductible<f2n, char*> );
+
+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;
+
+ int fr(int) &&;
+ int frn(int) && noexcept;
+};
+S s{};
+const S cs{};
+
+static_assert( is_same_v<decltype(function_ref(nontype<&S::mem>, s)),
+ function_ref<int&() noexcept>> );
+static_assert( is_same_v<decltype(function_ref(nontype<&S::mem>, cs)),
+ function_ref<const int&() noexcept>> );
+static_assert( is_same_v<decltype(function_ref(nontype<&S::mem>, &s)),
+ function_ref<int&() noexcept>> );
+static_assert( is_same_v<decltype(function_ref(nontype<&S::mem>, &cs)),
+ function_ref<const int&() noexcept>> );
+static_assert( !deductible<&S::mem, 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( !deductible<&S::f, char*> );
+static_assert( !deductible<&S::fn, char*> );
+static_assert( !deductible<&S::f, const S> );
+static_assert( !deductible<&S::fn, const S> );
+
+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( !deductible<&S::fc, char*> );
+static_assert( !deductible<&S::fcn, char*> );
+
+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>> );
+
+static_assert( !deductible<&S::fr, char*> );
+static_assert( !deductible<&S::frn, char*> );
+static_assert( !deductible<&S::fr, S> );
+static_assert( !deductible<&S::frn, S> );
+
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/hash/int128.cc b/libstdc++-v3/testsuite/20_util/hash/int128.cc
new file mode 100644
index 0000000..a26d2e2
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/hash/int128.cc
@@ -0,0 +1,20 @@
+// { dg-do run { target c++11 } }
+// { dg-add-options strict_std }
+
+#include <functional>
+#include <testsuite_hooks.h>
+
+int main()
+{
+#ifdef __SIZEOF_INT128__
+ std::hash<__int128> h;
+ __int128 i = (__int128)0x123456789;
+ VERIFY( h(i) == (std::size_t)i );
+ VERIFY( h(-i) == (std::size_t)-i );
+ VERIFY( h(~i) == (std::size_t)~i );
+ std::hash<unsigned __int128> hu;
+ unsigned __int128 u = i;
+ VERIFY( hu(u) == (std::size_t)u );
+ VERIFY( hu(~u) == (std::size_t)~u );
+#endif
+}
diff --git a/libstdc++-v3/testsuite/20_util/headers/functional/synopsis.cc b/libstdc++-v3/testsuite/20_util/headers/functional/synopsis.cc
index e3e9207..d58353e 100644
--- a/libstdc++-v3/testsuite/20_util/headers/functional/synopsis.cc
+++ b/libstdc++-v3/testsuite/20_util/headers/functional/synopsis.cc
@@ -18,7 +18,7 @@
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
-// { dg-options "-Wno-deprecated" }
+// { dg-options "-Wno-deprecated-declarations" }
#include <functional>
@@ -57,6 +57,13 @@ namespace std {
template <class Predicate>
_GLIBCXX14_CONSTEXPR
binary_negate<Predicate> not2(const Predicate&);
+#ifdef __cpp_lib_not_fn
+ template <typename F> _GLIBCXX20_CONSTEXPR auto not_fn(F&&)
+ noexcept(std::is_nothrow_constructible<std::decay_t<F>, F&&>::value);
+#if __cpp_lib_not_fn >= 202306L
+ template <auto f> constexpr decltype(auto) not_fn() noexcept;
+#endif
+#endif
// lib.binders, binders:
template <class Operation> class binder1st;
@@ -65,6 +72,24 @@ namespace std {
template <class Operation> class binder2nd;
template <class Operation, class T>
binder2nd<Operation> bind2nd(const Operation&, const T&);
+#ifdef __cpp_lib_bind_front
+ template <typename F, typename... Args>
+ _GLIBCXX20_CONSTEXPR auto bind_front(F&&, Args&&...);
+#if __cpp_lib_bind_front >= 202306L
+ template <auto f, typename... Args>
+ constexpr decltype(auto) bind_front(Args&&...)
+ noexcept(__and_v<is_nothrow_constructible<Args>...>);
+#endif
+#endif
+#ifdef __cpp_lib_bind_back
+ template <typename F, typename... Args>
+ _GLIBCXX20_CONSTEXPR auto bind_back(F&&, Args&&...);
+#if __cpp_lib_bind_back >= 202306L
+ template <auto f, typename... Args>
+ constexpr decltype(auto) bind_back(Args&&...)
+ noexcept(__and_v<is_nothrow_constructible<Args>...>);
+#endif
+#endif
// lib.function.pointer.adaptors, adaptors:
template <class Arg, class Result> class pointer_to_unary_function;
diff --git a/libstdc++-v3/testsuite/20_util/headers/memory/version.cc b/libstdc++-v3/testsuite/20_util/headers/memory/version.cc
index c82c9a0..5366a5d 100644
--- a/libstdc++-v3/testsuite/20_util/headers/memory/version.cc
+++ b/libstdc++-v3/testsuite/20_util/headers/memory/version.cc
@@ -6,3 +6,11 @@
#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
+
+#if __cplusplus > 202302L && __cpp_lib_is_sufficiently_aligned != 202411L
+# error "Feature-test macro __cpp_lib_is_sufficiently_aligned has wrong value in <version>"
+#endif
diff --git a/libstdc++-v3/testsuite/20_util/integer_comparisons/extended.cc b/libstdc++-v3/testsuite/20_util/integer_comparisons/extended.cc
new file mode 100644
index 0000000..d862b16
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/integer_comparisons/extended.cc
@@ -0,0 +1,60 @@
+// { dg-do compile { target c++20 } }
+
+#include <utility>
+
+template<typename T>
+constexpr bool
+test()
+{
+ using S = std::make_signed_t<T>;
+ using U = std::make_unsigned_t<T>;
+
+ static_assert( std::cmp_less((S)-1, (U)1));
+ static_assert( ! std::cmp_less((S)20, (U)10));
+ static_assert( ! std::cmp_less((U)20, (S)10));
+
+ static_assert( std::cmp_greater((S)100, (U)1) );
+ static_assert( std::cmp_greater((U)100, (S)1) );
+ static_assert( ! std::cmp_greater((S)-100, (U)1) );
+
+ static_assert( std::cmp_less_equal((S)-1, (U)1));
+ static_assert( std::cmp_less_equal((U)10, (S)10));
+ static_assert( ! std::cmp_less_equal((U)-100, (S)-100));
+
+ static_assert( std::cmp_greater_equal((S)200, (U)2) );
+ static_assert( std::cmp_greater_equal((U)2000, (S)2000) );
+ static_assert( ! std::cmp_greater_equal((S)-100, (U)100) );
+
+ static_assert( std::cmp_equal((S)1, (U)1) );
+ static_assert( ! std::cmp_equal((S)-2, (U)-2) );
+
+ static_assert( std::cmp_not_equal((S)-1, (U)-1) );
+ static_assert( ! std::cmp_not_equal((S)100, (U)100) );
+
+ static_assert( std::in_range<S>((U)5) );
+ static_assert( std::in_range<U>((S)5) );
+ static_assert( ! std::in_range<S>((U)-5) );
+ static_assert( ! std::in_range<U>((S)-5) );
+
+ return true;
+}
+
+#ifdef __SIZEOF_INT128__
+static_assert(test<__int128>());
+#endif
+
+#ifdef __GLIBCXX_TYPE_INT_N_0
+static_assert(test<__GLIBCXX_TYPE_INT_N_0>());
+#endif
+
+#ifdef __GLIBCXX_TYPE_INT_N_1
+static_assert(test<__GLIBCXX_TYPE_INT_N_1>());
+#endif
+
+#ifdef __GLIBCXX_TYPE_INT_N_2
+static_assert(test<__GLIBCXX_TYPE_INT_N_2>());
+#endif
+
+#ifdef __GLIBCXX_TYPE_INT_N_3
+static_assert(test<__GLIBCXX_TYPE_INT_N_3>());
+#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/is_implicit_lifetime/value.cc b/libstdc++-v3/testsuite/20_util/is_implicit_lifetime/value.cc
new file mode 100644
index 0000000..d8cb181
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/is_implicit_lifetime/value.cc
@@ -0,0 +1,129 @@
+// 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++23 } }
+// { dg-add-options no_pch }
+
+#include <type_traits>
+
+#ifndef __cpp_lib_is_implicit_lifetime
+# error "Feature test macro for is_implicit_lifetime is missing in <type_traits>"
+#elif __cpp_lib_is_implicit_lifetime < 202302L
+# error "Feature test macro for is_implicit_lifetime has wrong value in <type_traits>"
+#endif
+
+#include <testsuite_tr1.h>
+
+template<typename T>
+ concept Is_implicit_lifetime
+ = __gnu_test::test_category<std::is_implicit_lifetime, T>(true);
+
+static_assert( ! Is_implicit_lifetime<void> );
+static_assert( ! Is_implicit_lifetime<const void> );
+static_assert( ! Is_implicit_lifetime<volatile void> );
+static_assert( Is_implicit_lifetime<char> );
+static_assert( Is_implicit_lifetime<signed char> );
+static_assert( Is_implicit_lifetime<const unsigned char> );
+static_assert( Is_implicit_lifetime<short> );
+static_assert( Is_implicit_lifetime<volatile unsigned short> );
+static_assert( Is_implicit_lifetime<int> );
+static_assert( Is_implicit_lifetime<unsigned int> );
+static_assert( Is_implicit_lifetime<const volatile long> );
+static_assert( Is_implicit_lifetime<unsigned long> );
+static_assert( Is_implicit_lifetime<long long> );
+static_assert( Is_implicit_lifetime<unsigned long long> );
+static_assert( Is_implicit_lifetime<float> );
+static_assert( Is_implicit_lifetime<double> );
+static_assert( Is_implicit_lifetime<long double volatile> );
+enum W { W1 };
+static_assert( Is_implicit_lifetime<W> );
+enum class X : int { X1 };
+static_assert( Is_implicit_lifetime<const volatile X> );
+static_assert( Is_implicit_lifetime<int *> );
+static_assert( Is_implicit_lifetime<int (*) (int)> );
+struct Y { int g; int foo (int); };
+static_assert( Is_implicit_lifetime<int (Y::*)> );
+static_assert( Is_implicit_lifetime<int (Y::*) (int)> );
+static_assert( ! Is_implicit_lifetime<int &> );
+static_assert( ! Is_implicit_lifetime<char &&> );
+static_assert( Is_implicit_lifetime<int []> );
+static_assert( Is_implicit_lifetime<int [1]> );
+static_assert( Is_implicit_lifetime<const Y [42]> );
+static_assert( ! Is_implicit_lifetime<int ()> );
+static_assert( ! Is_implicit_lifetime<int () &> );
+static_assert( ! Is_implicit_lifetime<int () const> );
+static_assert( ! Is_implicit_lifetime<int (&) ()> );
+struct Z;
+static_assert( Is_implicit_lifetime<Z []> );
+static_assert( Is_implicit_lifetime<Z [5]> );
+struct A { int a, b, c; };
+static_assert( Is_implicit_lifetime<A> );
+class B { static int a; private: static int b; public: int c; };
+static_assert( Is_implicit_lifetime<B> );
+struct C { C () {} int a, b, c; };
+static_assert( Is_implicit_lifetime<C> );
+struct D { explicit D (int) {} int a, b, c; };
+static_assert( Is_implicit_lifetime<D> );
+struct E : public A { int d, e, f; };
+static_assert( Is_implicit_lifetime<E> );
+struct F : public C { using C::C; int d, e, f; };
+static_assert( Is_implicit_lifetime<F> );
+class G { int a, b; };
+static_assert( Is_implicit_lifetime<G> );
+struct H { private: int a, b; };
+static_assert( Is_implicit_lifetime<H> );
+struct I { protected: int a, b; };
+static_assert( Is_implicit_lifetime<I> );
+struct J { int a, b; void foo (); };
+static_assert( Is_implicit_lifetime<J> );
+struct K { int a, b; virtual void foo (); };
+static_assert( ! Is_implicit_lifetime<K> );
+struct L : virtual public A { int d, e; };
+static_assert( ! Is_implicit_lifetime<L> );
+struct M : protected A { int d, e; };
+static_assert( Is_implicit_lifetime<M> );
+struct N : private A { int d, e; };
+static_assert( Is_implicit_lifetime<N> );
+struct O { O () = delete; int a, b, c; };
+static_assert( Is_implicit_lifetime<O> );
+struct P { P () = default; int a, b, c; };
+static_assert( Is_implicit_lifetime<P> );
+struct Q { Q (); Q (const Q &); int a, b, c; };
+static_assert( ! Is_implicit_lifetime<Q> );
+struct R { R (); R (const R &); R (R &&) = default; int a, b, c; };
+static_assert( Is_implicit_lifetime<R> );
+struct S { S (); ~S (); int a, b, c; };
+static_assert( ! Is_implicit_lifetime<S> );
+static_assert( Is_implicit_lifetime<S [3]> );
+struct T { T (); ~T () = default; int a, b, c; };
+static_assert( Is_implicit_lifetime<T> );
+struct U { U (); U (const U &) = default; int a, b, c; };
+static_assert( Is_implicit_lifetime<U> );
+struct V { V () = default; V (const V &); int a, b, c; };
+static_assert( Is_implicit_lifetime<V> );
+struct AA { Q a; Q b; };
+static_assert( Is_implicit_lifetime<AA> );
+struct AB { Q a; Q b; ~AB () = default; };
+static_assert( Is_implicit_lifetime<AB> );
+struct AC { Q a; Q b; ~AC () {} };
+static_assert( ! Is_implicit_lifetime<AC> );
+struct AD : public Q {};
+static_assert( Is_implicit_lifetime<AD> );
+struct AE : public Q { ~AE () = default; };
+static_assert( Is_implicit_lifetime<AE> );
+struct AF : public Q { ~AF () {} };
+static_assert( ! Is_implicit_lifetime<AF> );
diff --git a/libstdc++-v3/testsuite/20_util/is_implicit_lifetime/version.cc b/libstdc++-v3/testsuite/20_util/is_implicit_lifetime/version.cc
new file mode 100644
index 0000000..ed90b47
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/is_implicit_lifetime/version.cc
@@ -0,0 +1,27 @@
+// 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++23 } }
+// { dg-add-options no_pch }
+
+#include <version>
+
+#ifndef __cpp_lib_is_implicit_lifetime
+# error "Feature test macro for is_implicit_lifetime is missing in <version>"
+#elif __cpp_lib_is_implicit_lifetime < 202302L
+# error "Feature test macro for is_implicit_lifetime has wrong value in <version>"
+#endif
diff --git a/libstdc++-v3/testsuite/20_util/is_literal_type/requirements/explicit_instantiation.cc b/libstdc++-v3/testsuite/20_util/is_literal_type/requirements/explicit_instantiation.cc
index ca3676a..71d0f46 100644
--- a/libstdc++-v3/testsuite/20_util/is_literal_type/requirements/explicit_instantiation.cc
+++ b/libstdc++-v3/testsuite/20_util/is_literal_type/requirements/explicit_instantiation.cc
@@ -1,4 +1,4 @@
-// { dg-additional-options "-Wno-deprecated" { target c++17 } }
+// { dg-additional-options "-Wno-deprecated-declarations" { target c++17 } }
// { dg-do compile { target c++11 } }
// 2010-02-21 Paolo Carlini <paolo.carlini@oracle.com>
diff --git a/libstdc++-v3/testsuite/20_util/is_literal_type/requirements/typedefs.cc b/libstdc++-v3/testsuite/20_util/is_literal_type/requirements/typedefs.cc
index 353d89f..7cfce9e 100644
--- a/libstdc++-v3/testsuite/20_util/is_literal_type/requirements/typedefs.cc
+++ b/libstdc++-v3/testsuite/20_util/is_literal_type/requirements/typedefs.cc
@@ -1,4 +1,4 @@
-// { dg-additional-options "-Wno-deprecated" { target c++17 } }
+// { dg-additional-options "-Wno-deprecated-declarations" { target c++17 } }
// { dg-do compile { target c++11 } }
// 2010-02-21 Paolo Carlini <paolo.carlini@oracle.com>
diff --git a/libstdc++-v3/testsuite/20_util/is_literal_type/value.cc b/libstdc++-v3/testsuite/20_util/is_literal_type/value.cc
index b65d301..f8b1b8d 100644
--- a/libstdc++-v3/testsuite/20_util/is_literal_type/value.cc
+++ b/libstdc++-v3/testsuite/20_util/is_literal_type/value.cc
@@ -1,4 +1,4 @@
-// { dg-additional-options "-Wno-deprecated" { target c++17 } }
+// { dg-additional-options "-Wno-deprecated-declarations" { target c++17 } }
// { dg-do compile { target c++11 } }
// 2010-03-23 Paolo Carlini <paolo.carlini@oracle.com>
diff --git a/libstdc++-v3/testsuite/20_util/is_pod/requirements/explicit_instantiation.cc b/libstdc++-v3/testsuite/20_util/is_pod/requirements/explicit_instantiation.cc
index 0bffe21..bcf67e1 100644
--- a/libstdc++-v3/testsuite/20_util/is_pod/requirements/explicit_instantiation.cc
+++ b/libstdc++-v3/testsuite/20_util/is_pod/requirements/explicit_instantiation.cc
@@ -1,5 +1,5 @@
// { dg-do compile { target c++11 } }
-// { dg-additional-options "-Wno-deprecated" { target { c++2a } } }
+// { dg-additional-options "-Wno-deprecated-declarations" { target { c++2a } } }
// 2010-02-21 Paolo Carlini <paolo.carlini@oracle.com>
// Copyright (C) 2010-2025 Free Software Foundation, Inc.
diff --git a/libstdc++-v3/testsuite/20_util/is_pod/requirements/typedefs.cc b/libstdc++-v3/testsuite/20_util/is_pod/requirements/typedefs.cc
index 38c6e13..6a41ea0 100644
--- a/libstdc++-v3/testsuite/20_util/is_pod/requirements/typedefs.cc
+++ b/libstdc++-v3/testsuite/20_util/is_pod/requirements/typedefs.cc
@@ -1,5 +1,5 @@
// { dg-do compile { target c++11 } }
-// { dg-additional-options "-Wno-deprecated" { target { c++2a } } }
+// { dg-additional-options "-Wno-deprecated-declarations" { target { c++2a } } }
// 2010-02-21 Paolo Carlini <paolo.carlini@oracle.com>
//
diff --git a/libstdc++-v3/testsuite/20_util/is_pod/value.cc b/libstdc++-v3/testsuite/20_util/is_pod/value.cc
index ff53aed..3722309 100644
--- a/libstdc++-v3/testsuite/20_util/is_pod/value.cc
+++ b/libstdc++-v3/testsuite/20_util/is_pod/value.cc
@@ -1,5 +1,5 @@
// { dg-do compile { target c++11 } }
-// { dg-additional-options "-Wno-deprecated" { target { c++2a } } }
+// { dg-additional-options "-Wno-deprecated-declarations" { target { c++2a } } }
// 2010-02-21 Paolo Carlini <pcarlini@suse.de>
//
diff --git a/libstdc++-v3/testsuite/20_util/is_sufficiently_aligned/1.cc b/libstdc++-v3/testsuite/20_util/is_sufficiently_aligned/1.cc
new file mode 100644
index 0000000..4c2738b
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/is_sufficiently_aligned/1.cc
@@ -0,0 +1,31 @@
+// { dg-do run { target c++26 } }
+
+#include <memory>
+#include <array>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+ constexpr size_t N = 4;
+ constexpr size_t M = 2*N + 1;
+ alignas(N) std::array<char, M> buffer{};
+
+ auto* ptr = buffer.data();
+ VERIFY(std::is_sufficiently_aligned<1>(ptr+0));
+ VERIFY(std::is_sufficiently_aligned<1>(ptr+1));
+
+ VERIFY(std::is_sufficiently_aligned<2>(ptr+0));
+ VERIFY(!std::is_sufficiently_aligned<2>(ptr+1));
+ VERIFY(std::is_sufficiently_aligned<2>(ptr+2));
+
+ for (size_t i = 0; i < M; ++i)
+ VERIFY(std::is_sufficiently_aligned<N>(ptr + i) == (i % N == 0));
+}
+
+int
+main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/20_util/make_unsigned/int128.cc b/libstdc++-v3/testsuite/20_util/make_unsigned/int128.cc
new file mode 100644
index 0000000..46c07b7
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/make_unsigned/int128.cc
@@ -0,0 +1,14 @@
+// { dg-do compile { target c++11 } }
+// { dg-add-options strict_std }
+
+#include <type_traits>
+
+#ifdef __SIZEOF_INT128__
+enum E : __int128 { };
+using U = std::make_unsigned<E>::type;
+static_assert( std::is_integral<U>::value, "type is an integer" );
+static_assert( sizeof(U) == sizeof(E), "width of type is 128 bits" );
+using I = std::make_signed<E>::type;
+static_assert( std::is_integral<I>::value, "type is an integer" );
+static_assert( sizeof(I) == sizeof(E), "width of type is 128 bits" );
+#endif
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..34ca73b 100644
--- a/libstdc++-v3/testsuite/20_util/move_only_function/call.cc
+++ b/libstdc++-v3/testsuite/20_util/move_only_function/call.cc
@@ -190,21 +190,59 @@ 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;
}
+struct EmptyIdFunc
+{
+ EmptyIdFunc* operator()()
+ { return this; }
+};
+
+struct Composed : EmptyIdFunc
+{
+ std::move_only_function<EmptyIdFunc*()> nested;
+};
+
+void
+test_aliasing()
+{
+ Composed c;
+ c.nested = EmptyIdFunc{};
+
+ EmptyIdFunc* baseAddr = c();
+ EmptyIdFunc* nestedAddr = c.nested();
+ VERIFY( baseAddr != nestedAddr );
+};
+
int main()
{
test01();
test02();
test03();
test04();
+ test05();
test_params();
+ test_aliasing();
}
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/cons/value_neg.cc b/libstdc++-v3/testsuite/20_util/optional/cons/value_neg.cc
index d3abd03..f6b1886 100644
--- a/libstdc++-v3/testsuite/20_util/optional/cons/value_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/optional/cons/value_neg.cc
@@ -37,3 +37,4 @@ int main()
}
}
// { dg-prune-output "no type .*enable_if" }
+// { dg-prune-output "no matching function for call to 'main..::U::U..'" }
diff --git a/libstdc++-v3/testsuite/20_util/optional/make_optional-2.cc b/libstdc++-v3/testsuite/20_util/optional/make_optional-2.cc
index f383b51..0aa2ac5e 100644
--- a/libstdc++-v3/testsuite/20_util/optional/make_optional-2.cc
+++ b/libstdc++-v3/testsuite/20_util/optional/make_optional-2.cc
@@ -70,7 +70,9 @@ static_assert( can_make_optional2<int, int&>::value );
static_assert( noexcept(std::make_optional(i)) );
static_assert( ! can_make_optional2<void, void>::value );
static_assert( can_make_optional2<Cont, Cont>::value );
+#if __cplusplus <= 202302
static_assert( noexcept(std::make_optional<Cont>({})) );
+#endif
static_assert( can_make_optional2<Cont, const Cont&>::value );
static_assert( ! noexcept(std::make_optional(c)) );
static_assert( can_make_optional2<Cont, int>::value );
diff --git a/libstdc++-v3/testsuite/20_util/optional/make_optional_neg.cc b/libstdc++-v3/testsuite/20_util/optional/make_optional_neg.cc
new file mode 100644
index 0000000..0949947
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/optional/make_optional_neg.cc
@@ -0,0 +1,20 @@
+// { dg-do compile { target c++17 } }
+
+#include <initializer_list>
+#include <optional>
+
+struct S { int x; int* p; };
+int v;
+
+auto os1 = std::make_optional<S>({1, &v}); // { dg-error "no matching function for" "" { target c++26 } }
+
+struct Cont
+{
+ Cont();
+ Cont(std::initializer_list<int>, int);
+};
+
+auto oc1 = std::make_optional<Cont>({}); // { dg-error "no matching function for" "" { target c++26 } }
+
+// { dg-prune-output "no type named 'type' in 'struct std::enable_if" }
+// { dg-prune-output "type/value mismatch at argument 1 in template parameter list" }
diff --git a/libstdc++-v3/testsuite/20_util/optional/monadic/or_else_neg.cc b/libstdc++-v3/testsuite/20_util/optional/monadic/or_else_neg.cc
index f5028c1..12a67bb 100644
--- a/libstdc++-v3/testsuite/20_util/optional/monadic/or_else_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/optional/monadic/or_else_neg.cc
@@ -26,4 +26,5 @@ test02()
std::optional<move_only> mo;
mo.or_else([]{ return std::optional<move_only>{}; }); // { dg-error "no matching function" }
+ // { dg-error "use of deleted function" "" { target *-*-* } 0 }
}
diff --git a/libstdc++-v3/testsuite/20_util/optional/monadic/ref_neg.cc b/libstdc++-v3/testsuite/20_util/optional/monadic/ref_neg.cc
new file mode 100644
index 0000000..ed1b42b
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/optional/monadic/ref_neg.cc
@@ -0,0 +1,20 @@
+// { dg-do compile { target c++23 } }
+
+#include <optional>
+
+struct S { int x; int y; };
+
+void test()
+{
+ std::optional<S> o;
+ const std::optional<S>& co = o;
+
+ o.transform(&S::x); // { dg-error "from here" "optional<int&>" { target c++23_down } }
+ co.transform(&S::x); // { dg-error "from here" "optional<const int&>" { target c++23_down } }
+ std::move(o).transform(&S::x); // { dg-error "from here" "optional<int&&>" }
+ std::move(co).transform(&S::x); // { dg-error "from here" "optional<const int&&>" }
+}
+
+// { dg-prune-output "in a union may not have reference type" }
+// { dg-prune-output "static assertion failed" }
+// { dg-prune-output "forming pointer to reference type" }
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..4238c9c
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/optional/range.cc
@@ -0,0 +1,350 @@
+// { 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>
+
+struct NonMovable
+{
+ constexpr NonMovable() {}
+ constexpr NonMovable(int) {}
+
+ NonMovable(NonMovable&&) = delete;
+ NonMovable& operator=(NonMovable&&) = delete;
+
+ friend bool operator==(NonMovable const&, NonMovable const&) = default;
+};
+
+struct NonAssignable
+{
+ NonAssignable() = default;
+ NonAssignable(NonAssignable&&) = default;
+ NonAssignable& operator=(NonAssignable&&) = delete;
+
+ friend bool operator==(NonAssignable const&, NonAssignable const&) = default;
+};
+
+template<typename T>
+constexpr
+void
+test_range_concepts()
+{
+ using O = std::optional<T>;
+ static_assert(std::ranges::contiguous_range<O>);
+ static_assert(std::ranges::sized_range<O>);
+ static_assert(std::ranges::common_range<O>);
+
+ // an optional<T&> is borrowed range
+ constexpr bool is_ref_opt = std::is_reference_v<T>;
+ static_assert(std::ranges::borrowed_range<O> == is_ref_opt);
+
+ // for any T (including const U) such that optional<T> is not assignable,
+ // it does not satisfy ranges::view
+ constexpr bool is_opt_view = std::is_reference_v<T> || std::movable<T>;
+ static_assert(std::ranges::view<O> == is_opt_view);
+ static_assert(std::ranges::viewable_range<O> == is_opt_view);
+
+}
+
+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&>);
+}
+
+template<typename O>
+constexpr
+void
+test_const_iterator_concepts()
+{
+ using T = typename O::value_type;
+ 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 T>
+constexpr
+void
+test_empty()
+{
+ using O = std::optional<T>;
+ 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 T>
+constexpr
+void
+test_non_empty(const T& value)
+{
+ using O = std::optional<T>;
+ using V = typename O::value_type;
+ O non_empty(std::in_place, value);
+ VERIFY(non_empty);
+ if constexpr (!std::is_array_v<V>)
+ 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_move_assignable_v<V>) {
+ for (auto& x : non_empty)
+ x = V{};
+ VERIFY(non_empty);
+ VERIFY(*non_empty == V{});
+ }
+}
+
+template<typename T>
+constexpr
+void
+test(const T& value)
+{
+ using O = std::optional<T>;
+ test_range_concepts<T>();
+ test_iterator_concepts<O>();
+ if constexpr (!std::is_reference_v<T>)
+ test_const_iterator_concepts<O>();
+ test_empty<T>();
+ test_non_empty<T>(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);
+}
+
+template<typename T>
+constexpr void test_not_range()
+{
+ static_assert(!requires { typename std::optional<T>::iterator; });
+ static_assert(!requires(std::optional<T> o) { o.begin(); });
+ static_assert(!requires(std::optional<T> o) { o.end(); });
+};
+
+template<typename T>
+constexpr bool is_optional = false;
+
+template<typename T>
+constexpr bool is_optional<std::optional<T>> = true;
+
+template<bool usesOptional, typename T, typename U = std::remove_cv_t<T>>
+constexpr void test_as_const(std::type_identity_t<U> u)
+{
+ std::optional<T> o(std::in_place, std::forward<U>(u));
+ auto cv = std::views::as_const(o);
+ static_assert(is_optional<decltype(cv)> == usesOptional);
+ static_assert(std::is_same_v<decltype(*cv.begin()), const std::remove_reference_t<T>&>);
+ VERIFY(!std::ranges::empty(cv));
+
+ std::optional<T> e;
+ auto cve = std::views::as_const(e);
+ static_assert(is_optional<decltype(cve)> == usesOptional);
+ static_assert(std::is_same_v<decltype(*cve.begin()), const std::remove_reference_t<T>&>);
+ VERIFY(std::ranges::empty(cve));
+}
+
+template<bool usesOptional, typename T, typename U = std::remove_cv_t<T>>
+constexpr void
+test_reverse(std::type_identity_t<U> u)
+{
+ std::optional<T> o(std::in_place, std::forward<U>(u));
+ auto rv = std::views::reverse(o);
+ static_assert(is_optional<decltype(rv)> == usesOptional);
+ static_assert(std::is_same_v<decltype(*rv.begin()), T&>);
+ VERIFY(!std::ranges::empty(rv));
+
+ std::optional<T> e;
+ auto rve = std::views::reverse(e);
+ static_assert(is_optional<decltype(rve)> == usesOptional);
+ static_assert(std::is_same_v<decltype(*rve.begin()), T&>);
+ VERIFY(std::ranges::empty(rve));
+}
+
+template<bool usesOptional, typename T, typename U = std::remove_cv_t<T>>
+constexpr void
+test_take(std::type_identity_t<U> u)
+{
+ std::optional<T> o(std::in_place, std::forward<U>(u));
+ auto tvp = std::views::take(o, 3);
+ static_assert(is_optional<decltype(tvp)> == usesOptional);
+ static_assert(std::is_same_v<decltype(*tvp.begin()), T&>);
+ VERIFY(!std::ranges::empty(tvp));
+
+ auto tvz = std::views::take(o, 0);
+ static_assert(is_optional<decltype(tvz)> == usesOptional);
+ static_assert(std::is_same_v<decltype(*tvz.begin()), T&>);
+ VERIFY(std::ranges::empty(tvz));
+
+ std::optional<T> e;
+ auto tvep = std::views::take(e, 5);
+ static_assert(is_optional<decltype(tvep)> == usesOptional);
+ static_assert(std::is_same_v<decltype(*tvep.begin()), T&>);
+ VERIFY(std::ranges::empty(tvep));
+
+ auto tvez = std::views::take(e, 0);
+ static_assert(is_optional<decltype(tvez)> == usesOptional);
+ static_assert(std::is_same_v<decltype(*tvez.begin()), T&>);
+ VERIFY(std::ranges::empty(tvez));
+}
+
+template<bool usesOptional, typename T, typename U = std::remove_cv_t<T>>
+constexpr void
+test_drop(std::type_identity_t<U> u)
+{
+ std::optional<T> o(std::in_place, std::forward<U>(u));
+ auto dvp = std::views::drop(o, 3);
+ static_assert(is_optional<decltype(dvp)> == usesOptional);
+ static_assert(std::is_same_v<decltype(*dvp.begin()), T&>);
+ VERIFY(std::ranges::empty(dvp));
+
+ auto dvz = std::views::drop(o, 0);
+ static_assert(is_optional<decltype(dvz)> == usesOptional);
+ static_assert(std::is_same_v<decltype(*dvz.begin()), T&>);
+ VERIFY(!std::ranges::empty(dvz));
+
+ std::optional<T> e;
+ auto dvep = std::views::drop(e, 5);
+ static_assert(is_optional<decltype(dvep)> == usesOptional);
+ static_assert(std::is_same_v<decltype(*dvep.begin()), T&>);
+ VERIFY(std::ranges::empty(dvep));
+
+ auto dvez = std::views::drop(e, 0);
+ static_assert(is_optional<decltype(dvez)> == usesOptional);
+ static_assert(std::is_same_v<decltype(*dvez.begin()), T&>);
+ VERIFY(std::ranges::empty(dvez));
+}
+
+constexpr
+bool
+all_tests()
+{
+ test(42);
+ int i = 42;
+ int arr[10]{};
+ NonMovable nm;
+ NonAssignable na;
+ test(&i);
+ test(std::string_view("test"));
+ test(std::vector<int>{1, 2, 3, 4});
+ test(std::optional<int>(42));
+ test<const int>(42);
+
+ test<int&>(i);
+ test<const int&>(i);
+ test<int(&)[10]>(arr);
+ test<const int(&)[10]>(arr);
+ test<NonMovable&>(nm);
+ test<const NonMovable&>(nm);
+ test<NonAssignable&>(na);
+ test<const NonAssignable&>(na);
+ test_not_range<void(&)()>();
+ test_not_range<void(&)(int)>();
+ test_not_range<int(&)[]>();
+ test_not_range<const int(&)[]>();
+
+ range_chain_example();
+
+ test_as_const<false, int>(i);
+ test_as_const<false, const int>(i);
+ test_as_const<true, int&>(i);
+ test_as_const<true, const int&>(i);
+ test_as_const<false, NonMovable, int>(10);
+ test_as_const<false, const NonMovable, int>(10);
+ test_as_const<true, NonMovable&>(nm);
+ test_as_const<true, const NonMovable&>(nm);
+ test_as_const<false, NonAssignable>({});
+ test_as_const<false, const NonAssignable>({});
+ test_as_const<true, NonAssignable&>(na);
+ test_as_const<true, const NonAssignable&>(na);
+
+#define TEST_ADAPTOR(name) \
+ test_##name<true, int>(i); \
+ test_##name<false, const int>(i); \
+ test_##name<true, int&>(i); \
+ test_##name<true, const int&>(i); \
+ test_##name<false, NonMovable, int>(10); \
+ test_##name<false, const NonMovable, int>(10); \
+ test_##name<true, NonMovable&>(nm); \
+ test_##name<true, const NonMovable&>(nm); \
+ test_##name<false, NonAssignable>({}); \
+ test_##name<false, const NonAssignable>({}); \
+ test_##name<true, NonAssignable&>(na); \
+ test_##name<true, const NonAssignable&>(na)
+
+ TEST_ADAPTOR(reverse);
+ TEST_ADAPTOR(take);
+ TEST_ADAPTOR(drop);
+#undef TEST_ADAPTOR
+ return true;
+}
+
+static_assert(all_tests());
+
diff --git a/libstdc++-v3/testsuite/20_util/optional/ref/access.cc b/libstdc++-v3/testsuite/20_util/optional/ref/access.cc
new file mode 100644
index 0000000..37c8ff3
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/optional/ref/access.cc
@@ -0,0 +1,119 @@
+// { dg-do run { target c++26 } }
+
+#include <optional>
+#include <type_traits>
+#include <testsuite_hooks.h>
+
+struct NonMovable
+{
+ constexpr NonMovable() {}
+ NonMovable(NonMovable&&) = delete;
+};
+
+template<typename T>
+constexpr
+void test_value(T& t)
+{
+ std::optional<T&> o1(t);
+ const std::optional<T&> co1(t);
+
+ static_assert( std::is_same_v<decltype(o1.value()), T&> );
+ VERIFY( &o1.value() == &t );
+
+ static_assert( std::is_same_v<decltype(co1.value()), T&> );
+ VERIFY( &co1.value() == &t );
+
+ static_assert( std::is_same_v<decltype(std::move(o1).value()), T&> );
+ VERIFY( &std::move(o1).value() == &t );
+
+ static_assert( std::is_same_v<decltype(std::move(co1).value()), T&> );
+ VERIFY( &std::move(co1).value() == &t );
+
+ std::optional<const T&> o2(t);
+ static_assert( std::is_same_v<decltype(o2.value()), const T&> );
+ VERIFY( &o2.value() == &t );
+}
+
+struct Tracker
+{
+ int copy = 0;
+ int move = 0;
+
+ constexpr Tracker(int v) : copy(v), move(v) {}
+
+ constexpr Tracker(Tracker const& o)
+ : copy(o.copy+1), move(o.move)
+ {}
+
+ constexpr Tracker(Tracker&& o)
+ : copy(o.copy), move(o.move+1)
+ {}
+
+ Tracker& operator=(Tracker) = delete;
+};
+
+constexpr
+void test_value_or()
+{
+ Tracker t(100), u(200);
+ std::optional<Tracker&> o(t);
+
+ Tracker r1 = o.value_or(u);
+ VERIFY( r1.copy == 101 );
+ VERIFY( r1.move == 100 );
+ Tracker r2 = o.value_or(std::move(u));
+ VERIFY( r2.copy == 101 );
+ VERIFY( r2.move == 100 );
+ Tracker r3 = std::move(o).value_or(u);
+ VERIFY( r3.copy == 101 );
+ VERIFY( r3.move == 100 );
+ Tracker r4 = std::move(o).value_or(std::move(u));
+ VERIFY( r4.copy == 101 );
+ VERIFY( r4.move == 100 );
+
+ o.reset();
+ Tracker r5 = o.value_or(u);
+ VERIFY( r5.copy == 201 );
+ VERIFY( r5.move == 200 );
+ Tracker r6 = o.value_or(std::move(u));
+ VERIFY( r6.copy == 200 );
+ VERIFY( r6.move == 201 );
+ Tracker r7 = std::move(o).value_or(u);
+ VERIFY( r7.copy == 201 );
+ VERIFY( r7.move == 200 );
+ Tracker r8 = std::move(o).value_or(std::move(u));
+ VERIFY( r8.copy == 200 );
+ VERIFY( r8.move == 201 );
+}
+
+template<typename T>
+concept has_value_or_for = requires(std::optional<T&> t, T& u)
+{ t.value_or(u); };
+
+static_assert( has_value_or_for<int> );
+static_assert( has_value_or_for<NonMovable> );
+static_assert( !has_value_or_for<int[2]> );
+static_assert( has_value_or_for<int(*)[2]> );
+static_assert( !has_value_or_for<int()> );
+static_assert( has_value_or_for<int(*)()> );
+
+int i;
+NonMovable nm;
+int arr[2];
+int foo();
+
+int main()
+{
+ auto test_all = [] {
+ test_value<int>(i);
+ test_value<NonMovable>(nm);
+ test_value<int[2]>(arr);
+ test_value<int()>(foo);
+
+ test_value_or();
+ return true;
+ };
+
+ test_all();
+ static_assert(test_all());
+}
diff --git a/libstdc++-v3/testsuite/20_util/optional/ref/assign.cc b/libstdc++-v3/testsuite/20_util/optional/ref/assign.cc
new file mode 100644
index 0000000..be8b1c8
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/optional/ref/assign.cc
@@ -0,0 +1,430 @@
+// { dg-do run { target c++26 } }
+
+#include <optional>
+#include <type_traits>
+#include <testsuite_hooks.h>
+
+struct NonTrivial
+{
+ constexpr NonTrivial() {}
+ constexpr NonTrivial(NonTrivial const&) {};
+ constexpr ~NonTrivial() {};
+};
+
+struct NonMovable
+{
+ NonMovable() = default;
+ NonMovable(NonMovable&&) = delete;
+};
+
+template<typename T>
+struct Conv
+{
+ T t;
+
+ constexpr operator T() const noexcept
+ { return t; }
+};
+
+struct Tracker
+{
+ struct Counter
+ {
+ int copy;
+ int move;
+ };
+
+ Counter ctor{0,0};
+ Counter assign{0,0};
+
+ Tracker() = default;
+
+ constexpr Tracker(Tracker const& o)
+ : ctor(o.ctor), assign(o.assign)
+ {
+ ctor.copy += 1;
+ }
+
+ constexpr Tracker(Tracker&& o)
+ : ctor(o.ctor), assign(o.assign)
+ {
+ ctor.move += 1;
+ }
+
+ constexpr Tracker& operator=(const Tracker& o)
+ {
+ assign.copy += 1;
+ return *this;
+ }
+
+ constexpr Tracker& operator=(Tracker&& o)
+ {
+ assign.move += 1;
+ return *this;
+ }
+
+};
+
+template<typename T>
+void
+test_trivial()
+{
+ static_assert(std::is_copy_assignable_v<std::optional<T&>>);
+ static_assert(std::is_move_assignable_v<std::optional<T&>>);
+}
+
+constexpr void
+test_trivial_all()
+{
+ test_trivial<int>();
+ test_trivial<NonTrivial>();
+ test_trivial<std::optional<int&>>();
+}
+
+constexpr void
+test_copy()
+{
+ Tracker t, u;
+ std::optional<Tracker&> e;
+ std::optional<Tracker&> o1(t);
+ std::optional<Tracker&> o2(u);
+
+ o2 = o1;
+ VERIFY( o1.has_value() );
+ VERIFY( &o1.value() == &t );
+ VERIFY( o2.has_value() );
+ VERIFY( &o2.value() == &t );
+ VERIFY( t.ctor.copy == 0 );
+ VERIFY( t.ctor.move == 0 );
+ VERIFY( t.assign.copy == 0 );
+ VERIFY( t.assign.move == 0 );
+
+ o2 = e;
+ VERIFY( !o2.has_value() );
+
+ o2 = std::move(o1);
+ VERIFY( o1.has_value() );
+ VERIFY( &o1.value() == &t );
+ VERIFY( o2.has_value() );
+ VERIFY( &o2.value() == &t );
+ VERIFY( t.ctor.copy == 0 );
+ VERIFY( t.ctor.move == 0 );
+ VERIFY( t.assign.copy == 0 );
+ VERIFY( t.assign.move == 0 );
+
+ o2 = std::move(e);
+ VERIFY( !o2.has_value() );
+}
+
+template<typename T, typename U>
+concept can_emplace = requires (T t, U&& u)
+{ t.emplace(std::forward<U>(u)); };
+
+constexpr void
+test_from_value()
+{
+ NonTrivial v, u;
+ const NonTrivial& cv = v;
+ const std::optional<NonTrivial&> s(u);
+ std::optional<NonTrivial&> o1;
+ std::optional<const NonTrivial&> co1;
+
+ o1 = s;
+ o1 = v;
+ VERIFY( o1.has_value() );
+ VERIFY( &o1.value() == &v );
+
+ o1.reset();
+ VERIFY( !o1.has_value() );
+
+ o1 = v;
+ VERIFY( o1.has_value() );
+ VERIFY( &o1.value() == &v );
+ static_assert( !std::is_assignable_v<std::optional<NonTrivial&>,
+ const NonTrivial&> );
+ static_assert( !std::is_assignable_v<std::optional<NonTrivial&>,
+ NonTrivial> );
+ static_assert( !std::is_assignable_v<std::optional<NonTrivial&>,
+ const NonTrivial> );
+
+ o1 = s;
+ o1.emplace(v);
+ VERIFY( o1.has_value() );
+ VERIFY( &o1.value() == &v );
+
+ o1 = std::nullopt;
+ VERIFY( !o1.has_value() );
+
+ o1.emplace(v);
+ VERIFY( o1.has_value() );
+ VERIFY( &o1.value() == &v );
+
+ static_assert( !can_emplace<std::optional<NonTrivial&>, const NonTrivial&> );
+ static_assert( !can_emplace<std::optional<NonTrivial&>, NonTrivial> );
+ static_assert( !can_emplace<std::optional<NonTrivial&>, const NonTrivial> );
+
+ co1 = s;
+ co1 = v;
+ VERIFY( co1.has_value() );
+ VERIFY( &co1.value() == &v );
+
+ co1 = std::nullopt;
+ co1 = cv;
+ VERIFY( co1.has_value() );
+ VERIFY( &co1.value() == &v );
+ // No binding to rvalue
+ static_assert( !std::is_assignable_v<std::optional<const NonTrivial&>,
+ NonTrivial> );
+ static_assert( !std::is_assignable_v<std::optional<const NonTrivial&>,
+ const NonTrivial> );
+
+ co1 = std::nullopt;
+ co1.emplace(v);
+ VERIFY( co1.has_value() );
+ VERIFY( &co1.value() == &v );
+
+ co1 = s;
+ co1.emplace(cv);
+ VERIFY( co1.has_value() );
+ VERIFY( &co1.value() == &v );
+ // No binding to rvalue
+ static_assert( !can_emplace<std::optional<const NonTrivial&>, const NonTrivial> );
+ static_assert( !can_emplace<std::optional<const NonTrivial&>, NonTrivial> );
+
+
+ // Conversion create a pr-value that would bind to temporary
+ static_assert( !std::is_assignable_v<std::optional<NonTrivial&>,
+ Conv<NonTrivial>&> );
+ static_assert( !std::is_assignable_v<std::optional<NonTrivial&>,
+ const Conv<NonTrivial>&> );
+ static_assert( !std::is_assignable_v<std::optional<NonTrivial&>,
+ Conv<NonTrivial>> );
+ static_assert( !std::is_assignable_v<std::optional<NonTrivial&>,
+ const Conv<NonTrivial>> );
+
+ static_assert( !can_emplace<std::optional<NonTrivial&>, Conv<NonTrivial>&> );
+ static_assert( !can_emplace<std::optional<NonTrivial&>, const Conv<NonTrivial>&> );
+ static_assert( !can_emplace<std::optional<NonTrivial&>, Conv<NonTrivial>> );
+ static_assert( !can_emplace<std::optional<NonTrivial&>, const Conv<NonTrivial>> );
+
+ Conv<NonTrivial&> rw(v);
+ const Conv<NonTrivial&> crw(v);
+
+ o1 = std::nullopt;
+ o1 = rw;
+ VERIFY( o1.has_value() );
+ VERIFY( &o1.value() == &v );
+ o1 = s;
+ o1 = crw;
+ VERIFY( o1.has_value() );
+ VERIFY( &o1.value() == &v );
+ o1 = s;
+ o1 = std::move(rw);
+ VERIFY( o1.has_value() );
+ VERIFY( &o1.value() == &v );
+ o1 = std::nullopt;
+ o1 = std::move(crw);
+ VERIFY( o1.has_value() );
+ VERIFY( &o1.value() == &v );
+
+ o1 = s;
+ o1.emplace(rw);
+ VERIFY( o1.has_value() );
+ VERIFY( &o1.value() == &v );
+ o1 = std::nullopt;
+ o1.emplace(crw);
+ VERIFY( o1.has_value() );
+ VERIFY( &o1.value() == &v );
+ o1 = std::nullopt;
+ o1.emplace(std::move(rw));
+ VERIFY( o1.has_value() );
+ VERIFY( &o1.value() == &v );
+ o1 = s;
+ o1.emplace(std::move(crw));
+ VERIFY( o1.has_value() );
+ VERIFY( &o1.value() == &v );
+}
+
+constexpr void
+test_from_opt_value()
+{
+ NonTrivial u;
+ std::optional<NonTrivial> v(std::in_place);
+ const std::optional<NonTrivial>& cv = v;
+
+ const std::optional<NonTrivial&> s(u);
+ std::optional<NonTrivial&> o1;
+ std::optional<const NonTrivial&> co1;
+
+ o1 = s;
+ o1 = v;
+ VERIFY( o1.has_value() );
+ VERIFY( &o1.value() == &v.value() );
+ o1 = std::nullopt;
+ o1 = v;
+ VERIFY( o1.has_value() );
+ VERIFY( &o1.value() == &v.value() );
+ static_assert( !std::is_assignable_v<std::optional<NonTrivial&>,
+ const std::optional<NonTrivial>&> );
+ static_assert( !std::is_assignable_v<std::optional<NonTrivial&>,
+ std::optional<NonTrivial>> );
+ static_assert( !std::is_assignable_v<std::optional<NonTrivial&>,
+ const std::optional<NonTrivial>> );
+
+ co1 = s;
+ co1 = v;
+ VERIFY( co1.has_value() );
+ VERIFY( &co1.value() == &v.value() );
+ co1 = std::nullopt;
+ co1 = cv;
+ VERIFY( co1.has_value() );
+ VERIFY( &co1.value() == &v.value() );
+ // No binding to rvalue
+ static_assert( !std::is_assignable_v<std::optional<const NonTrivial&>,
+ std::optional<NonTrivial>> );
+ static_assert( !std::is_assignable_v<std::optional<const NonTrivial&>,
+ const std::optional<NonTrivial>> );
+
+ // Conversion create a pr-value that would bind to temporary
+ static_assert( !std::is_assignable_v<std::optional<NonTrivial&>,
+ std::optional<Conv<NonTrivial>>&> );
+ static_assert( !std::is_assignable_v<std::optional<NonTrivial&>,
+ const std::optional<Conv<NonTrivial>>&> );
+ static_assert( !std::is_assignable_v<std::optional<NonTrivial&>,
+ std::optional<Conv<NonTrivial>>> );
+ static_assert( !std::is_assignable_v<std::optional<NonTrivial&>,
+ const std::optional<Conv<NonTrivial>>> );
+
+ std::optional<Conv<NonTrivial&>> rw(*v);
+ std::optional<const Conv<NonTrivial&>> crw(*v);
+
+ o1 = std::nullopt;
+ o1 = rw;
+ VERIFY( o1.has_value() );
+ VERIFY( &o1.value() == &v.value() );
+ o1 = s;
+ o1 = crw;
+ VERIFY( o1.has_value() );
+ VERIFY( &o1.value() == &v.value() );
+ o1 = s;
+ o1 = std::move(rw);
+ VERIFY( o1.has_value() );
+ VERIFY( &o1.value() == &v.value() );
+ o1 = std::nullopt;
+ o1 = std::move(crw);
+ VERIFY( o1.has_value() );
+ VERIFY( &o1.value() == &v.value() );
+}
+
+constexpr void
+test_to_opt_value()
+{
+ Tracker t;
+ std::optional<Tracker&> er;
+ std::optional<Tracker&> r(t);
+ const std::optional<Tracker&> cr(t);
+
+ std::optional<Tracker> o1;
+ o1 = r;
+ VERIFY( o1.has_value() );
+ VERIFY( o1->ctor.copy == 1 );
+ VERIFY( o1->ctor.move == 0 );
+ VERIFY( o1->assign.copy == 0 );
+ VERIFY( o1->assign.move == 0 );
+
+ o1 = r;
+ VERIFY( o1.has_value() );
+ VERIFY( o1->ctor.copy == 1 );
+ VERIFY( o1->ctor.move == 0 );
+ VERIFY( o1->assign.copy == 1 );
+ VERIFY( o1->assign.move == 0 );
+
+ o1 = er;
+ VERIFY( !o1.has_value() );
+
+ o1 = cr;
+ VERIFY( o1.has_value() );
+ VERIFY( o1->ctor.copy == 1 );
+ VERIFY( o1->ctor.move == 0 );
+ VERIFY( o1->assign.copy == 0 );
+ VERIFY( o1->assign.move == 0 );
+
+ o1 = cr;
+ VERIFY( o1.has_value() );
+ VERIFY( o1->ctor.copy == 1 );
+ VERIFY( o1->ctor.move == 0 );
+ VERIFY( o1->assign.copy == 1 );
+ VERIFY( o1->assign.move == 0 );
+
+ o1 = std::move(er);
+
+ o1 = std::move(r);
+ VERIFY( o1.has_value() );
+ VERIFY( o1->ctor.copy == 1 );
+ VERIFY( o1->ctor.move == 0 );
+ VERIFY( o1->assign.copy == 0 );
+ VERIFY( o1->assign.move == 0 );
+
+ o1 = std::move(cr);
+ VERIFY( o1.has_value() );
+ VERIFY( o1->ctor.copy == 1 );
+ VERIFY( o1->ctor.move == 0 );
+ VERIFY( o1->assign.copy == 1 );
+ VERIFY( o1->assign.move == 0 );
+}
+
+constexpr void
+test_swap()
+{
+ NonMovable a, b;
+ std::optional<NonMovable&> oa(a), ob(b);
+
+ oa.swap(ob);
+ static_assert(noexcept(oa.swap(ob)));
+ VERIFY( oa.has_value() );
+ VERIFY( &oa.value() == &b );
+ VERIFY( ob.has_value() );
+ VERIFY( &ob.value() == &a );
+
+ swap(oa, ob);
+ static_assert(std::is_nothrow_swappable_v<std::optional<NonMovable&>>);
+ VERIFY( oa.has_value() );
+ VERIFY( &oa.value() == &a );
+ VERIFY( ob.has_value() );
+ VERIFY( &ob.value() == &b );
+
+ ob.reset();
+ oa.swap(ob);
+ VERIFY( !oa.has_value() );
+ VERIFY( ob.has_value() );
+ VERIFY( &ob.value() == &a );
+
+ ob.reset();
+ std::swap(oa, ob);
+ VERIFY( !oa.has_value() );
+ VERIFY( !ob.has_value() );
+
+ std::optional<const NonMovable&> ca(a), cb(b);
+ swap(ca, cb);
+ VERIFY( ca.has_value() );
+ VERIFY( &ca.value() == &b );
+ VERIFY( cb.has_value() );
+ VERIFY( &cb.value() == &a );
+
+ static_assert(!std::is_swappable_with_v<std::optional<int>&, std::optional<int&>&>);
+}
+
+int main()
+{
+ auto test_all = [] {
+ test_copy();
+ test_from_value();
+ test_from_opt_value();
+ test_to_opt_value();
+ test_swap();
+ return true;
+ };
+
+ test_all();
+ static_assert(test_all());
+}
diff --git a/libstdc++-v3/testsuite/20_util/optional/ref/cons.cc b/libstdc++-v3/testsuite/20_util/optional/ref/cons.cc
new file mode 100644
index 0000000..b13e8b9
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/optional/ref/cons.cc
@@ -0,0 +1,356 @@
+// { dg-do run { target c++26 } }
+
+#include <optional>
+#include <type_traits>
+#include <testsuite_hooks.h>
+
+struct NonTrivial
+{
+ constexpr NonTrivial() {}
+ constexpr NonTrivial(NonTrivial const&) {};
+ constexpr ~NonTrivial() {};
+};
+
+struct NonMovable
+{
+ constexpr NonMovable() {}
+ NonMovable(NonMovable&&) = delete;
+};
+
+template<typename T>
+struct Conv
+{
+ T t;
+
+ constexpr operator T() const noexcept
+ { return t; }
+};
+
+struct Tracker
+{
+ int copy = 0;
+ int move = 0;
+
+ Tracker() = default;
+
+ constexpr Tracker(Tracker const& o)
+ : copy(o.copy+1), move(o.move)
+ {}
+
+ constexpr Tracker(Tracker&& o)
+ : copy(o.copy), move(o.move+1)
+ {}
+
+ Tracker& operator=(Tracker) = delete;
+};
+
+template<typename T>
+void
+test_trivial()
+{
+ static_assert(std::is_trivially_copyable_v<std::optional<T&>>);
+ static_assert(std::is_copy_constructible_v<std::optional<T&>>);
+ static_assert(std::is_move_constructible_v<std::optional<T&>>);
+ static_assert(std::is_destructible_v<std::optional<T&>>);
+}
+
+constexpr void
+test_trivial_all()
+{
+ test_trivial<int>();
+ test_trivial<NonTrivial>();
+ test_trivial<NonMovable>();
+ test_trivial<std::optional<int&>>();
+}
+
+constexpr void
+test_copy()
+{
+ Tracker t;
+ std::optional<Tracker&> o1(t);
+ VERIFY( o1.has_value() );
+ VERIFY( &o1.value() == &t );
+ VERIFY( t.copy == 0 );
+ VERIFY( t.move == 0 );
+
+ std::optional<Tracker&> o2(o1);
+ VERIFY( o1.has_value() );
+ VERIFY( &o1.value() == &t );
+ VERIFY( o2.has_value() );
+ VERIFY( &o2.value() == &t );
+ VERIFY( t.copy == 0 );
+ VERIFY( t.move == 0 );
+
+ std::optional<Tracker&> o3(std::move(o1));
+ VERIFY( o1.has_value() );
+ VERIFY( &o1.value() == &t );
+ VERIFY( o3.has_value() );
+ VERIFY( &o3.value() == &t );
+ VERIFY( t.copy == 0 );
+ VERIFY( t.move == 0 );
+
+ std::optional<Tracker&> e;
+ VERIFY( !e.has_value() );
+
+ std::optional<Tracker&> o4(e);
+ VERIFY( !e.has_value() );
+ VERIFY( !o4.has_value() );
+
+ std::optional<Tracker&> o5(std::move(e));
+ VERIFY( !e.has_value() );
+ VERIFY( !o5.has_value() );
+}
+
+
+constexpr void
+test_from_value()
+{
+ NonTrivial v;
+ const NonTrivial& cv = v;
+
+ std::optional<NonTrivial&> o1(v);
+ VERIFY( o1.has_value() );
+ VERIFY( &o1.value() == &v );
+ static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
+ const NonTrivial&> );
+ static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
+ NonTrivial> );
+ static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
+ const NonTrivial> );
+
+ std::optional<NonTrivial&> o2(std::in_place, v);
+ VERIFY( o2.has_value() );
+ VERIFY( &o2.value() == &v );
+ static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
+ std::in_place_t, const NonTrivial&> );
+ static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
+ std::in_place_t, NonTrivial> );
+ static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
+ std::in_place_t, const NonTrivial> );
+
+ std::optional<const NonTrivial&> co1(v);
+ VERIFY( co1.has_value() );
+ VERIFY( &co1.value() == &v );
+ std::optional<const NonTrivial&> co2(cv);
+ VERIFY( co2.has_value() );
+ VERIFY( &co2.value() == &v );
+ // No binding to rvalue
+ static_assert( !std::is_constructible_v<std::optional<const NonTrivial&>,
+ NonTrivial> );
+ static_assert( !std::is_constructible_v<std::optional<const NonTrivial&>,
+ const NonTrivial> );
+
+ std::optional<const NonTrivial&> co3(std::in_place, v);
+ VERIFY( co3.has_value() );
+ VERIFY( &co3.value() == &v );
+ std::optional<const NonTrivial&> co4(std::in_place, cv);
+ VERIFY( co4.has_value() );
+ VERIFY( &co4.value() == &v );
+ // No binding to rvalue
+ static_assert( !std::is_constructible_v<std::optional<const NonTrivial&>,
+ std::in_place_t, NonTrivial> );
+ static_assert( !std::is_constructible_v<std::optional<const NonTrivial&>,
+ std::in_place_t, const NonTrivial> );
+
+ // Conversion create a pr-value that would bind to temporary
+ static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
+ Conv<NonTrivial>&> );
+ static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
+ const Conv<NonTrivial>&> );
+ static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
+ Conv<NonTrivial>> );
+ static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
+ const Conv<NonTrivial>> );
+
+ static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
+ std::in_place_t, Conv<NonTrivial>&> );
+ static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
+ std::in_place_t, const Conv<NonTrivial>&> );
+ static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
+ std::in_place_t, Conv<NonTrivial>> );
+ static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
+ std::in_place_t, const Conv<NonTrivial>> );
+
+ Conv<NonTrivial&> rw(v);
+ const Conv<NonTrivial&> crw(v);
+
+ std::optional<NonTrivial&> ro1(rw);
+ VERIFY( ro1.has_value() );
+ VERIFY( &ro1.value() == &v );
+ std::optional<NonTrivial&> ro2(crw);
+ VERIFY( ro2.has_value() );
+ VERIFY( &ro2.value() == &v );
+ std::optional<NonTrivial&> ro3(std::move(rw));
+ VERIFY( ro3.has_value() );
+ VERIFY( &ro3.value() == &v );
+ std::optional<NonTrivial&> ro4(std::move(crw));
+ VERIFY( ro4.has_value() );
+ VERIFY( &ro4.value() == &v );
+
+ std::optional<NonTrivial&> ro5(std::in_place, rw);
+ VERIFY( ro5.has_value() );
+ VERIFY( &ro5.value() == &v );
+ std::optional<NonTrivial&> ro6(std::in_place, crw);
+ VERIFY( ro6.has_value() );
+ VERIFY( &ro6.value() == &v );
+ std::optional<NonTrivial&> ro7(std::in_place, std::move(rw));
+ VERIFY( ro7.has_value() );
+ VERIFY( &ro7.value() == &v );
+ std::optional<NonTrivial&> ro8(std::in_place, std::move(crw));
+ VERIFY( ro8.has_value() );
+ VERIFY( &ro8.value() == &v );
+}
+
+constexpr void
+test_from_opt_value()
+{
+ std::optional<NonTrivial> v(std::in_place);
+ const std::optional<NonTrivial>& cv = v;
+
+ std::optional<NonTrivial&> o1(v);
+ VERIFY( o1.has_value() );
+ VERIFY( &o1.value() == &v.value() );
+ static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
+ const std::optional<NonTrivial>&> );
+ static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
+ std::optional<NonTrivial>> );
+ static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
+ const std::optional<NonTrivial>> );
+
+ std::optional<const NonTrivial&> co1(v);
+ VERIFY( co1.has_value() );
+ VERIFY( &co1.value() == &v.value() );
+ std::optional<const NonTrivial&> co2(cv);
+ VERIFY( co2.has_value() );
+ VERIFY( &co2.value() == &v.value() );
+ // No binding to rvalue
+ static_assert( !std::is_constructible_v<std::optional<const NonTrivial&>,
+ std::optional<NonTrivial>> );
+ static_assert( !std::is_constructible_v<std::optional<const NonTrivial&>,
+ const std::optional<NonTrivial>> );
+
+ // Conversion create a pr-value that would bind to temporary
+ static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
+ std::optional<Conv<NonTrivial>>&> );
+ static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
+ const std::optional<Conv<NonTrivial>>&> );
+ static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
+ std::optional<Conv<NonTrivial>>> );
+ static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
+ const std::optional<Conv<NonTrivial>>> );
+
+ std::optional<Conv<NonTrivial&>> rw(*v);
+ std::optional<const Conv<NonTrivial&>> crw(*v);
+
+ std::optional<NonTrivial&> ro1(rw);
+ VERIFY( ro1.has_value() );
+ VERIFY( &ro1.value() == &v.value() );
+ std::optional<NonTrivial&> ro2(crw);
+ VERIFY( ro2.has_value() );
+ VERIFY( &ro2.value() == &v.value() );
+ std::optional<NonTrivial&> ro3(std::move(rw));
+ VERIFY( ro3.has_value() );
+ VERIFY( &ro3.value() == &v.value() );
+ std::optional<NonTrivial&> ro4(std::move(crw));
+ VERIFY( ro4.has_value() );
+ VERIFY( &ro4.value() == &v.value() );
+}
+
+constexpr void
+test_to_opt_value()
+{
+ Tracker t;
+ std::optional<Tracker&> r(t);
+ const std::optional<Tracker&> cr(t);
+
+ std::optional<Tracker> o1(r);
+ VERIFY( o1.has_value() );
+ VERIFY( o1->copy == 1 );
+ VERIFY( o1->move == 0 );
+
+ std::optional<Tracker> o2(cr);
+ VERIFY( o2.has_value() );
+ VERIFY( o2->copy == 1 );
+ VERIFY( o2->move == 0 );
+
+ std::optional<Tracker> o3(std::move(r));
+ VERIFY( o3.has_value() );
+ VERIFY( o3->copy == 1 );
+ VERIFY( o3->move == 0 );
+
+ std::optional<Tracker> o4(std::move(cr));
+ VERIFY( o4.has_value() );
+ VERIFY( o4->copy == 1 );
+ VERIFY( o4->move == 0 );
+
+ std::optional<Tracker&> er;
+ const std::optional<Tracker&> cer;
+
+ std::optional<Tracker> e1(er);
+ VERIFY( !e1.has_value() );
+
+ std::optional<Tracker> e2(cer);
+ VERIFY( !e2.has_value() );
+
+ std::optional<Tracker> e3(std::move(er));
+ VERIFY( !e3.has_value() );
+
+ std::optional<Tracker> e4(std::move(cer));
+ VERIFY( !e4.has_value() );
+}
+
+constexpr void
+test_opt_opt()
+{
+ std::optional<int> s(43);
+
+ std::optional<std::optional<int>&> o1(s);
+ VERIFY( o1.has_value() );
+ VERIFY( &o1.value() == &s );
+
+ std::optional<std::optional<int>&> o2(std::in_place, s);
+ VERIFY( o2.has_value() );
+ VERIFY( &o2.value() == &s );
+
+ std::optional<std::optional<int>> o3(o1);
+ VERIFY( o2.has_value() );
+ VERIFY( o2.value().has_value() );
+ VERIFY( o2.value() == 43 );
+
+ s.reset();
+ std::optional<std::optional<int>&> o4(s);
+ VERIFY( o4.has_value() );
+ VERIFY( &o4.value() == &s );
+
+ std::optional<std::optional<int>&> o5(std::in_place, s);
+ VERIFY( o5.has_value() );
+ VERIFY( &o5.value() == &s );
+
+ std::optional<std::optional<int>> o6(o1);
+ VERIFY( o6.has_value() );
+ VERIFY( !o6.value().has_value() );
+
+ std::optional<std::optional<int>> s2(std::in_place);
+ std::optional<std::optional<int>&> oo1(s2);
+ VERIFY( oo1.has_value() );
+ VERIFY( &oo1.value() == &s2.value() );
+
+ s2.reset();
+ std::optional<std::optional<int>&> oo2(s2);
+ VERIFY( !oo2.has_value() );
+}
+
+int main()
+{
+ auto test_all = [] {
+ test_copy();
+ test_from_value();
+ test_from_opt_value();
+ test_to_opt_value();
+ test_opt_opt();
+ return true;
+ };
+
+ test_all();
+ static_assert(test_all());
+}
diff --git a/libstdc++-v3/testsuite/20_util/optional/ref/internal_traits.cc b/libstdc++-v3/testsuite/20_util/optional/ref/internal_traits.cc
new file mode 100644
index 0000000..ef50da7
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/optional/ref/internal_traits.cc
@@ -0,0 +1,11 @@
+// { dg-do compile { target c++26 } }
+
+#include <optional>
+#include <variant>
+
+template<typename T>
+constexpr bool _Never_valueless
+ = std::__detail::__variant::_Never_valueless_alt<T>::value;
+
+static_assert( _Never_valueless<std::optional<int&>> );
+static_assert( _Never_valueless<std::optional<const int&>> );
diff --git a/libstdc++-v3/testsuite/20_util/optional/ref/make_optional/1.cc b/libstdc++-v3/testsuite/20_util/optional/ref/make_optional/1.cc
new file mode 100644
index 0000000..d9946d0
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/optional/ref/make_optional/1.cc
@@ -0,0 +1,74 @@
+// { dg-do run { target c++20 } }
+
+#include <optional>
+#include <utility>
+#include <testsuite_hooks.h>
+
+struct NonTrivial
+{
+ constexpr NonTrivial() {}
+ constexpr NonTrivial(NonTrivial const&) {};
+ constexpr ~NonTrivial() {};
+};
+
+template<typename T>
+struct Conv
+{
+ T t;
+
+ constexpr operator T() const noexcept
+ { return t; }
+};
+
+constexpr bool test()
+{
+ NonTrivial t;
+ const NonTrivial& ct = t;
+
+#if __cplusplus > 202302
+ auto o1 = std::make_optional<NonTrivial&>(t);
+ VERIFY( o1.has_value() );
+ VERIFY( &o1.value() == &t );
+
+ auto o2 = std::make_optional<const NonTrivial&>(t);
+ VERIFY( o2.has_value() );
+ VERIFY( &o2.value() == &t );
+
+ auto o3 = std::make_optional<const NonTrivial&>(ct);
+ VERIFY( o3.has_value() );
+ VERIFY( &o3.value() == &t );
+
+ Conv<NonTrivial&> rw(t);
+ auto o4 = std::make_optional<NonTrivial&>(rw);
+ VERIFY( o4.has_value() );
+ VERIFY( &o4.value() == &t );
+
+ auto o5 = std::make_optional<NonTrivial&>(std::as_const(rw));
+ VERIFY( o5.has_value() );
+ VERIFY( &o5.value() == &t );
+
+ auto o6 = std::make_optional<NonTrivial&>(Conv<NonTrivial&>(t));
+ VERIFY( o6.has_value() );
+ VERIFY( &o6.value() == &t );
+#else
+ auto o1 = std::make_optional<NonTrivial&>(t);
+ VERIFY( o1.has_value() );
+ VERIFY( &o1.value() != &t );
+
+ auto o3 = std::make_optional<const NonTrivial&>(ct);
+ VERIFY( o3.has_value() );
+ VERIFY( &o3.value() != &t );
+
+ auto o2 = std::make_optional<NonTrivial&&>(std::move(t));
+ VERIFY( o2.has_value() );
+ VERIFY( &o2.value() != &t );
+#endif
+
+ return true;
+}
+
+int main()
+{
+ test();
+ static_assert(test());
+}
diff --git a/libstdc++-v3/testsuite/20_util/optional/ref/make_optional/from_args_neg.cc b/libstdc++-v3/testsuite/20_util/optional/ref/make_optional/from_args_neg.cc
new file mode 100644
index 0000000..6166c65
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/optional/ref/make_optional/from_args_neg.cc
@@ -0,0 +1,43 @@
+// { dg-do compile { target c++17 } }
+
+#include <optional>
+
+struct C {
+ C();
+ C(int);
+};
+C s(10);
+const C cs(1);
+
+template<typename T>
+using decay_pre26 =
+#if __cplusplus > 202302
+ T;
+#else
+ std::decay_t<T>;
+#endif
+
+auto z1 = std::make_optional<C&>(); // { dg-error "no matching function for call" }
+auto z2 = std::make_optional<const C&>(); // { dg-error "no matching function for call" }
+auto z3 = std::make_optional<C&&>(); // { dg-error "no matching function for call" }
+auto z4 = std::make_optional<const C&&>(); // { dg-error "no matching function for call" }
+
+auto o1 = std::make_optional<C&>(10); // { dg-error "no matching function for call" }
+auto o2 = std::make_optional<const C&>(10); // { dg-error "from here" }
+auto o3 = std::make_optional<C&&>(10); // { dg-error "from here" }
+auto o4 = std::make_optional<const C&&>(10); // { dg-error "from here" }
+
+auto t1 = std::make_optional<C&>(10, 20); // { dg-error "no matching function for call" }
+auto t2 = std::make_optional<const C&>(10, 20); // { dg-error "no matching function for call" }
+auto t3 = std::make_optional<C&&>(10, 20); // { dg-error "no matching function for call" }
+auto t3 = std::make_optional<const C&&>(10, 20); // { dg-error "no matching function for call" }
+
+// { dg-prune-output "no type named 'type' in 'struct std::enable_if" }
+// { dg-prune-output "type/value mismatch at argument 1 in template parameter list" }
+// { dg-prune-output "in a union may not have reference type" }
+// { dg-prune-output "static assertion failed" }
+// { dg-prune-output "forming pointer to reference type" }
+// { dg-prune-output "cannot bind .* reference of type" }
+// { dg-prune-output "binding reference of type" }
+// { dg-prune-output "no matching function for call to 'std::optional" }
+
diff --git a/libstdc++-v3/testsuite/20_util/optional/ref/make_optional/from_lvalue_neg.cc b/libstdc++-v3/testsuite/20_util/optional/ref/make_optional/from_lvalue_neg.cc
new file mode 100644
index 0000000..aed6791
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/optional/ref/make_optional/from_lvalue_neg.cc
@@ -0,0 +1,40 @@
+// { dg-do compile { target c++17 } }
+
+#include <optional>
+#include <type_traits>
+
+struct C {
+ C();
+ C(int);
+};
+C s(10);
+const C cs(1);
+
+template<typename T>
+using decay_pre26 =
+#if __cplusplus > 202302
+ T;
+#else
+ std::decay_t<T>;
+#endif
+
+auto lr1 = std::make_optional<C&>(s); // changed meaning
+static_assert( std::is_same_v< decltype(lr1), std::optional<decay_pre26<C&>>> );
+auto lr2 = std::make_optional<const C&>(s); // { dg-error "here" "" { target c++23_down } }
+auto lr3 = std::make_optional<C&&>(s); // { dg-error "no matching function for call" }
+auto lr4 = std::make_optional<const C&&>(s); // { dg-error "no matching function for call" }
+
+auto clr1 = std::make_optional<C&>(cs); // { dg-error "no matching function for call" }
+auto clr2 = std::make_optional<const C&>(cs); // changed meaning
+static_assert( std::is_same_v< decltype(clr2), std::optional<decay_pre26<const C&>>> );
+auto clr3 = std::make_optional<C&&>(cs); // { dg-error "no matching function for call" }
+auto clr3 = std::make_optional<const C&&>(cs); // { dg-error "no matching function for call" }
+
+// { dg-prune-output "no type named 'type' in 'struct std::enable_if" }
+// { dg-prune-output "type/value mismatch at argument 1 in template parameter list" }
+// { dg-prune-output "in a union may not have reference type" }
+// { dg-prune-output "static assertion failed" }
+// { dg-prune-output "forming pointer to reference type" }
+// { dg-prune-output "cannot bind .* reference of type" }
+// { dg-prune-output "binding reference of type" }
+// { dg-prune-output "no matching function for call to `std::optional" }
diff --git a/libstdc++-v3/testsuite/20_util/optional/ref/make_optional/from_rvalue_neg.cc b/libstdc++-v3/testsuite/20_util/optional/ref/make_optional/from_rvalue_neg.cc
new file mode 100644
index 0000000..22f669c
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/optional/ref/make_optional/from_rvalue_neg.cc
@@ -0,0 +1,38 @@
+// { dg-do compile { target c++17 } }
+
+#include <optional>
+#include <type_traits>
+
+struct C {
+ C();
+ C(int);
+};
+C s(10);
+const C cs(1);
+
+template<typename T>
+using decay_pre26 =
+#if __cplusplus > 202302
+ T;
+#else
+ std::decay_t<T>;
+#endif
+
+auto p1 = std::make_optional<C&>(C(10)); // { dg-error "no matching function for call" }
+auto p2 = std::make_optional<const C&>(C(10)); // { dg-error "from here" }
+auto p3 = std::make_optional<C&&>(C(10)); // { dg-error "from here" "" { target c++26 } }
+auto p4 = std::make_optional<const C&&>(C(10)); // { dg-error "from here" }
+
+auto b1 = std::make_optional<C&>({10}); // { dg-error "no matching function for call" }
+auto b2 = std::make_optional<const C&>({10}); // { dg-error "no matching function for call" "" { target c++26 } }
+auto b3 = std::make_optional<C&&>({10}); // { dg-error "no matching function for call" "" { target c++26 } }
+auto b4 = std::make_optional<const C&&>({10}); // { dg-error "no matching function for call" "" { target c++26 } }
+
+// { dg-prune-output "no type named 'type' in 'struct std::enable_if" }
+// { dg-prune-output "type/value mismatch at argument 1 in template parameter list" }
+// { dg-prune-output "in a union may not have reference type" }
+// { dg-prune-output "static assertion failed" }
+// { dg-prune-output "forming pointer to reference type" }
+// { dg-prune-output "cannot bind .* reference of type" }
+// { dg-prune-output "binding reference of type" }
+// { dg-prune-output "no matching function for call to 'std::optional" }
diff --git a/libstdc++-v3/testsuite/20_util/optional/ref/monadic.cc b/libstdc++-v3/testsuite/20_util/optional/ref/monadic.cc
new file mode 100644
index 0000000..e8460c6
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/optional/ref/monadic.cc
@@ -0,0 +1,192 @@
+// { dg-do run { target c++26 } }
+
+#include <optional>
+#include <type_traits>
+#include <testsuite_hooks.h>
+#include <utility>
+
+struct NonMovable
+{
+ constexpr NonMovable() {}
+ NonMovable(NonMovable&&) = delete;
+};
+
+struct Tracker
+{
+ int copy = 0;
+ int move = 0;
+
+ Tracker() = default;
+
+ constexpr Tracker(Tracker const& o)
+ : copy(o.copy+1), move(o.move)
+ {}
+
+ constexpr Tracker(Tracker&& o)
+ : copy(o.copy), move(o.move+1)
+ {}
+
+ Tracker& operator=(Tracker) = delete;
+
+ void reset() {
+ copy = move = 0;
+ }
+};
+
+template<typename T>
+auto identity_of = []<typename U>(U&& t) -> std::optional<T>
+{
+ static_assert( std::is_same_v<T, U&&> );
+ VERIFY( t.copy == 0 );
+ VERIFY( t.move == 0 );
+ return std::optional<T>(t);
+};
+
+constexpr void
+test_and_then()
+{
+ std::optional<Tracker> t(std::in_place);
+ std::optional<Tracker&> rt(t);
+ std::optional<const Tracker&> rct(t);
+
+ auto r1 = t.and_then(identity_of<Tracker&>);
+ VERIFY( r1.has_value() );
+ VERIFY( &r1.value() == &t.value() );
+
+ auto r2 = rt.and_then(identity_of<Tracker&>);
+ VERIFY( r2.has_value() );
+ VERIFY( &r2.value() == &t.value() );
+
+ std::as_const(rt).and_then(identity_of<Tracker&>);
+ std::move(rt).and_then(identity_of<Tracker&>);
+
+ auto r4 = rct.and_then(identity_of<const Tracker&>);
+ VERIFY( r4.has_value() );
+ VERIFY( &r4.value() == &t.value() );
+
+ std::as_const(rct).and_then(identity_of<const Tracker&>);
+ std::move(rct).and_then(identity_of<const Tracker&>);
+
+ auto r5 = rt.and_then([](Tracker&) { return std::optional<int>(42); });
+ static_assert( std::is_same_v<decltype(r5), std::optional<int>> );
+ VERIFY( r5.has_value() );
+ VERIFY( r5.value() == 42 );
+
+ auto r6 = rct.and_then([](const Tracker&) { return std::optional<int>(); });
+ static_assert( std::is_same_v<decltype(r6), std::optional<int>> );
+ VERIFY( !r6.has_value() );
+
+ rct.reset();
+ auto r7 = rct.and_then([](const Tracker&) { VERIFY(false); return std::optional<int>(42); });
+ static_assert( std::is_same_v<decltype(r7), std::optional<int>> );
+ VERIFY( !r7.has_value() );
+
+ rt.reset();
+ auto r8 = rt.and_then([](Tracker&) { VERIFY(false); return std::optional<int>(); });
+ static_assert( std::is_same_v<decltype(r8), std::optional<int>> );
+ VERIFY( !r8.has_value() );
+}
+
+template<typename T>
+constexpr void
+test_or_else()
+{
+ T t, u;
+
+ std::optional<T&> ot(t);
+ auto r1 = ot.or_else([&] { VERIFY(false); return std::optional<T&>(u); });
+ VERIFY( &ot.value() == &t );
+ VERIFY( r1.has_value() );
+ VERIFY( &r1.value() == &t );
+ auto r2 = std::move(ot).or_else([&] { VERIFY(false); return std::optional<T&>(); });
+ VERIFY( &ot.value() == &t );
+ VERIFY( r2.has_value() );
+ VERIFY( &r2.value() == &t );
+
+ ot.reset();
+ auto r3 = ot.or_else([&] { return std::optional<T&>(u); });
+ VERIFY( !ot.has_value() );
+ VERIFY( r3.has_value() );
+ VERIFY( &r3.value() == &u );
+ auto r4 = std::move(ot).or_else([] { return std::optional<T&>(); });
+ VERIFY( !ot.has_value() );
+ VERIFY( !r4.has_value() );
+}
+
+constexpr void
+test_transform()
+{
+ std::optional<Tracker> t(std::in_place);
+
+ auto r1 = t.transform(&Tracker::copy);
+ static_assert( std::is_same_v<decltype(r1), std::optional<int&>> );
+ VERIFY( r1.has_value() );
+ VERIFY( &r1.value() == &t->copy );
+ auto r2 = std::as_const(t).transform(&Tracker::move);
+ static_assert( std::is_same_v<decltype(r2), std::optional<const int&>> );
+ VERIFY( r2.has_value() );
+ VERIFY( &r2.value() == &t->move );
+
+ std::optional<Tracker&> rt(t);
+ auto r3 = rt.transform(&Tracker::copy);
+ static_assert( std::is_same_v<decltype(r3), std::optional<int&>> );
+ VERIFY( r3.has_value() );
+ VERIFY( &r3.value() == &t->copy );
+ auto r4 = std::as_const(rt).transform(&Tracker::copy);
+ static_assert( std::is_same_v<decltype(r4), std::optional<int&>> );
+ VERIFY( r4.has_value() );
+ VERIFY( &r4.value() == &t->copy );
+ auto r5 = std::move(rt).transform(&Tracker::copy);
+ static_assert( std::is_same_v<decltype(r5), std::optional<int&>> );
+ VERIFY( r5.has_value() );
+ VERIFY( &r5.value() == &t->copy );
+
+ auto r6 = rt.transform([] (Tracker& t) { return 10; });
+ static_assert( std::is_same_v<decltype(r6), std::optional<int>> );
+ VERIFY( r6.has_value() );
+ VERIFY( &r6.value() != &t->copy );
+ VERIFY( r6.value() == 10 );
+
+ auto r7 = rt.transform([] (Tracker& t) { return NonMovable(); });
+ static_assert( std::is_same_v<decltype(r7), std::optional<NonMovable>> );
+ VERIFY( r7.has_value() );
+
+ rt.reset();
+ auto r8 = rt.transform([] (Tracker& t) { VERIFY(false); return 42; });
+ static_assert( std::is_same_v<decltype(r8), std::optional<int>> );
+ VERIFY( !r8.has_value() );
+
+ std::optional<const Tracker&> crt(t);
+ auto r9 = crt.transform(&Tracker::copy);
+ static_assert( std::is_same_v<decltype(r9), std::optional<const int&>> );
+ VERIFY( r9.has_value() );
+ VERIFY( &r9.value() == &t->copy );
+ auto r10 = std::as_const(crt).transform(&Tracker::copy);
+ static_assert( std::is_same_v<decltype(r10), std::optional<const int&>> );
+ VERIFY( r10.has_value() );
+ VERIFY( &r10.value() == &t->copy );
+ auto r11 = std::move(crt).transform(&Tracker::copy);
+ static_assert( std::is_same_v<decltype(r11), std::optional<const int&>> );
+ VERIFY( r11.has_value() );
+ VERIFY( &r11.value() == &t->copy );
+
+ crt.reset();
+ auto r12 = rt.transform([] (Tracker& t) { VERIFY(false); return 42; });
+ static_assert( std::is_same_v<decltype(r12), std::optional<int>> );
+ VERIFY( !r12.has_value() );
+}
+
+int main()
+{
+ auto test_all = [] {
+ test_and_then();
+ test_transform();
+ test_or_else<Tracker>();
+ test_or_else<const Tracker>();
+ test_or_else<NonMovable>();
+ return true;
+ };
+
+ test_all();
+ static_assert(test_all());
+}
diff --git a/libstdc++-v3/testsuite/20_util/optional/ref/relops.cc b/libstdc++-v3/testsuite/20_util/optional/ref/relops.cc
new file mode 100644
index 0000000..e0b30c8
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/optional/ref/relops.cc
@@ -0,0 +1,229 @@
+// { dg-do run { target c++26 } }
+
+#include <optional>
+#include <functional>
+#include <testsuite_hooks.h>
+#include <type_traits>
+
+template<typename T, typename H = std::hash<T>>
+constexpr bool has_disabled_hash
+ = !std::is_default_constructible_v<H>
+ && !std::is_copy_constructible_v<H>
+ && !std::is_move_constructible_v<H>
+ && !std::is_copy_assignable_v<H>
+ && !std::is_move_assignable_v<H>;
+
+static_assert(has_disabled_hash<std::optional<int&>>);
+static_assert(has_disabled_hash<std::optional<const int&>>);
+
+template<typename T, typename V>
+constexpr void
+test_compare_val(V& l, V& h)
+{
+ std::optional<T> t;
+
+ VERIFY( !(t == l) );
+ VERIFY( (t != l) );
+ VERIFY( (t < l) );
+ VERIFY( (t <= l) );
+ VERIFY( !(t > l) );
+ VERIFY( !(t >= l) );
+ VERIFY( (t <=> l) < 0 );
+
+ VERIFY( !(l == t) );
+ VERIFY( (l != t) );
+ VERIFY( !(l < t) );
+ VERIFY( !(l <= t) );
+ VERIFY( (l > t) );
+ VERIFY( (l >= t) );
+ VERIFY( (l <=> t) > 0 );
+
+ t.emplace(l);
+ VERIFY( (t == l) );
+ VERIFY( !(t != l) );
+ VERIFY( !(t < l) );
+ VERIFY( (t <= l) );
+ VERIFY( !(t > l) );
+ VERIFY( (t >= l) );
+ VERIFY( (t <=> l) == 0 );
+
+ VERIFY( (l == t) );
+ VERIFY( !(l != t) );
+ VERIFY( !(l < t) );
+ VERIFY( (l <= t) );
+ VERIFY( !(l > t) );
+ VERIFY( (l >= t) );
+ VERIFY( (t <=> l) == 0 );
+
+ t.emplace(h);
+ VERIFY( !(t == l) );
+ VERIFY( (t != l) );
+ VERIFY( !(t < l) );
+ VERIFY( !(t <= l) );
+ VERIFY( (t > l) );
+ VERIFY( (t >= l) );
+ VERIFY( (t <=> l) > 0 );
+
+ VERIFY( !(l == t) );
+ VERIFY( (l != t) );
+ VERIFY( (l < t) );
+ VERIFY( (l <= t) );
+ VERIFY( !(l > t) );
+ VERIFY( !(l >= t) );
+ VERIFY( (l <=> t) < 0 );
+}
+
+template<typename T, typename U, typename V>
+constexpr void
+test_compare_opts(V& l, V& h)
+{
+ std::optional<T> t;
+ std::optional<U> u;
+
+ VERIFY( (t == u) );
+ VERIFY( !(t != u) );
+ VERIFY( !(t < u) );
+ VERIFY( (t <= u) );
+ VERIFY( !(t > u) );
+ VERIFY( (t >= u) );
+ VERIFY( (t <=> u) == 0 );
+
+ t.emplace(l);
+ VERIFY( !(t == u) );
+ VERIFY( (t != u) );
+ VERIFY( !(t < u) );
+ VERIFY( !(t <= u) );
+ VERIFY( (t > u) );
+ VERIFY( (t >= u) );
+ VERIFY( (t <=> u) > 0 );
+
+ u.emplace(l);
+ VERIFY( (t == u) );
+ VERIFY( !(t != u) );
+ VERIFY( !(t < u) );
+ VERIFY( (t <= u) );
+ VERIFY( !(t > u) );
+ VERIFY( (t <= u) );
+ VERIFY( (t <=> u) == 0 );
+
+ u.emplace(h);
+ VERIFY( !(t == u) );
+ VERIFY( (t != u) );
+ VERIFY( (t < u) );
+ VERIFY( (t <= u) );
+ VERIFY( !(t > u) );
+ VERIFY( !(t >= u) );
+ VERIFY( (t <=> u) < 0 );
+
+ t.reset();
+ u.emplace(l);
+ VERIFY( !(t == u) );
+ VERIFY( (t != u) );
+ VERIFY( (t < u) );
+ VERIFY( (t <= u) );
+ VERIFY( !(t > u) );
+ VERIFY( !(t >= u) );
+ VERIFY( (t <=> u) < 0 );
+
+ t.emplace(h);
+ VERIFY( !(t == u) );
+ VERIFY( (t != u) );
+ VERIFY( !(t < u) );
+ VERIFY( !(t <= u) );
+ VERIFY( (t > u) );
+ VERIFY( (t >= u) );
+ VERIFY( (t <=> u) > 0 );
+}
+
+template<typename V>
+constexpr void
+test_compare(V l, V h)
+{
+ test_compare_val<V&>(l, h);
+ test_compare_val<const V&>(l, h);
+
+ test_compare_opts<V&, V&>(l, h);
+ test_compare_opts<V, V&>(l, h);
+ test_compare_opts<V&, V>(l, h);
+
+ test_compare_opts<const V&, const V&>(l, h);
+ test_compare_opts<V, const V&>(l, h);
+ test_compare_opts<const V&, V>(l, h);
+
+ test_compare_opts<V&, const V&>(l, h);
+ test_compare_opts<const V&, V&>(l, h);
+}
+
+struct TreeWay
+{
+ int v;
+ friend auto operator<=>(TreeWay, TreeWay) = default;
+};
+
+struct Other
+{
+ int v;
+
+ constexpr Other(int p) : v(p) {}
+ constexpr Other(TreeWay p) : v(p.v) {}
+
+ friend bool operator==(Other, Other) = default;
+ friend auto operator<=>(Other, Other) = default;
+
+ friend constexpr bool
+ operator==(const Other& lhs, const TreeWay& rhs)
+ { return lhs.v == rhs.v; }
+
+ friend constexpr std::strong_ordering
+ operator<=>(const Other& lhs, const TreeWay& rhs)
+ { return lhs.v <=> rhs.v; }
+};
+
+constexpr void
+test_heterogeneus_cmp()
+{
+ TreeWay l{10};
+ Other h{20};
+
+ std::optional<TreeWay&> t;
+ std::optional<const Other&> u;
+
+ VERIFY( (t == u) );
+ VERIFY( !(t != u) );
+ VERIFY( !(t < u) );
+ VERIFY( (t <= u) );
+ VERIFY( !(t > u) );
+ VERIFY( (t >= u) );
+ VERIFY( (t <=> u) == 0 );
+
+ t.emplace(l);
+ VERIFY( !(t == u) );
+ VERIFY( (t != u) );
+ VERIFY( !(t < u) );
+ VERIFY( !(t <= u) );
+ VERIFY( (t > u) );
+ VERIFY( (t >= u) );
+ VERIFY( (t <=> u) > 0 );
+
+ u.emplace(h);
+ VERIFY( !(t == u) );
+ VERIFY( (t != u) );
+ VERIFY( (t < u) );
+ VERIFY( (t <= u) );
+ VERIFY( !(t > u) );
+ VERIFY( !(t >= u) );
+ VERIFY( (t <=> u) < 0 );
+}
+
+int main()
+{
+ auto test_all = [] {
+ test_compare(2, 5);
+ test_compare(TreeWay{11}, TreeWay{12});
+ test_heterogeneus_cmp();
+ return true;
+ };
+
+ test_all();
+ static_assert(test_all());
+}
diff --git a/libstdc++-v3/testsuite/20_util/optional/relops/constrained.cc b/libstdc++-v3/testsuite/20_util/optional/relops/constrained.cc
index 3e39325..ec47552 100644
--- a/libstdc++-v3/testsuite/20_util/optional/relops/constrained.cc
+++ b/libstdc++-v3/testsuite/20_util/optional/relops/constrained.cc
@@ -8,8 +8,8 @@
# error "Feature-test macro for constrained_equality has wrong value"
#endif
-template<typename T, typename U = T>
-concept eq_comparable
+template<typename T, typename U>
+concept eq_comparable_impl
= requires (const std::optional<T>& t, const std::optional<U>& u) {
t == u;
*t == u;
@@ -17,7 +17,19 @@ concept eq_comparable
};
template<typename T, typename U = T>
-concept ne_comparable
+concept eq_comparable =
+ eq_comparable_impl<T, U>
+#if __cplusplus > 202302l
+ && eq_comparable_impl<T&, U&>
+ && eq_comparable_impl<T const&, U const&>
+ && eq_comparable_impl<T const&, U&>
+ && eq_comparable_impl<T, U const&>
+ && eq_comparable_impl<T&, U>
+#endif
+;
+
+template<typename T, typename U>
+concept ne_comparable_impl
= requires (const std::optional<T>& t, const std::optional<U>& u) {
t != u;
*t != u;
@@ -25,7 +37,19 @@ concept ne_comparable
};
template<typename T, typename U = T>
-concept lt_comparable
+concept ne_comparable =
+ ne_comparable_impl<T, U>
+#if __cplusplus > 202302l
+ && ne_comparable_impl<T&, U&>
+ && ne_comparable_impl<T const&, U const&>
+ && ne_comparable_impl<T const&, U&>
+ && ne_comparable_impl<T, U const&>
+ && ne_comparable_impl<T&, U>
+#endif
+;
+
+template<typename T, typename U>
+concept lt_comparable_impl
= requires (const std::optional<T>& t, const std::optional<U>& u) {
t < u;
*t < u;
@@ -33,7 +57,19 @@ concept lt_comparable
};
template<typename T, typename U = T>
-concept le_comparable
+concept lt_comparable =
+ lt_comparable_impl<T, U>
+#if __cplusplus > 202302l
+ && lt_comparable_impl<T&, U&>
+ && lt_comparable_impl<T const&, U const&>
+ && lt_comparable_impl<T const&, U&>
+ && lt_comparable_impl<T, U const&>
+ && lt_comparable_impl<T&, U>
+#endif
+;
+
+template<typename T, typename U>
+concept le_comparable_impl
= requires (const std::optional<T>& t, const std::optional<U>& u) {
t <= u;
*t <= u;
@@ -41,7 +77,19 @@ concept le_comparable
};
template<typename T, typename U = T>
-concept gt_comparable
+concept le_comparable =
+ le_comparable_impl<T, U>
+#if __cplusplus > 202302l
+ && le_comparable_impl<T&, U&>
+ && le_comparable_impl<T const&, U const&>
+ && le_comparable_impl<T const&, U&>
+ && le_comparable_impl<T, U const&>
+ && le_comparable_impl<T&, U>
+#endif
+;
+
+template<typename T, typename U>
+concept gt_comparable_impl
= requires (const std::optional<T>& t, const std::optional<U>& u) {
t > u;
*t > u;
@@ -49,13 +97,37 @@ concept gt_comparable
};
template<typename T, typename U = T>
-concept ge_comparable
+concept gt_comparable =
+ gt_comparable_impl<T, U>
+#if __cplusplus > 202302l
+ && gt_comparable_impl<T&, U&>
+ && gt_comparable_impl<T const&, U const&>
+ && gt_comparable_impl<T const&, U&>
+ && gt_comparable_impl<T, U const&>
+ && gt_comparable_impl<T&, U>
+#endif
+;
+
+template<typename T, typename U>
+concept ge_comparable_impl
= requires (const std::optional<T>& t, const std::optional<U>& u) {
t >= u;
*t >= u;
t >= *u;
};
+template<typename T, typename U = T>
+concept ge_comparable =
+ ge_comparable_impl<T, U>
+#if __cplusplus > 202302l
+ && ge_comparable_impl<T&, U&>
+ && ge_comparable_impl<T const&, U const&>
+ && ge_comparable_impl<T const&, U&>
+ && ge_comparable_impl<T, U const&>
+ && ge_comparable_impl<T&, U>
+#endif
+;
+
static_assert( eq_comparable<int> );
static_assert( ne_comparable<int> );
static_assert( lt_comparable<int> );
diff --git a/libstdc++-v3/testsuite/20_util/optional/relops/lwg4370.cc b/libstdc++-v3/testsuite/20_util/optional/relops/lwg4370.cc
new file mode 100644
index 0000000..a292cbe
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/optional/relops/lwg4370.cc
@@ -0,0 +1,55 @@
+// { dg-do compile { target c++17 } }
+
+// LWG 4370. Comparison of optional<T> to T may be ill-formed
+
+#include <optional>
+#include <testsuite_hooks.h>
+
+struct Bool
+{
+ Bool(bool);
+ operator bool() const;
+};
+
+template<typename T> void operator&&(Bool, T) = delete;
+template<typename T> void operator&&(T, Bool) = delete;
+template<typename T> void operator||(Bool, T) = delete;
+template<typename T> void operator||(T, Bool) = delete;
+
+struct S
+{
+ Bool operator==(S) const;
+ Bool operator!=(S) const;
+ Bool operator<(S) const;
+ Bool operator>(S) const;
+ Bool operator<=(S) const;
+ Bool operator>=(S) const;
+};
+
+void
+test_lwg4370()
+{
+ std::optional<S> o;
+ (void)(o == o);
+ (void)(o != o);
+ (void)(o < o);
+ (void)(o > o);
+ (void)(o <= o);
+ (void)(o >= o);
+
+ S s;
+ (void)(o == s);
+ (void)(s == o);
+ (void)(o != s);
+ (void)(s != o);
+ (void)(o < s);
+ (void)(s < o);
+ (void)(o > s);
+ (void)(s > o);
+ (void)(o <= s);
+ (void)(s <= o);
+ (void)(o >= s);
+ (void)(s >= o);
+}
+
+
diff --git a/libstdc++-v3/testsuite/20_util/optional/requirements.cc b/libstdc++-v3/testsuite/20_util/optional/requirements.cc
index 68e5905..9e8cf83 100644
--- a/libstdc++-v3/testsuite/20_util/optional/requirements.cc
+++ b/libstdc++-v3/testsuite/20_util/optional/requirements.cc
@@ -26,8 +26,10 @@
# error "Feature test macro for optional has wrong value in <optional>"
#elif __cplusplus == 202002L && __cpp_lib_optional != 202106L
# error "Feature test macro for optional has wrong value for C++20 in <optional>"
-#elif __cplusplus > 202002L && __cpp_lib_optional != 202110L
-# error "Feature test macro for optional has wrong value for C++23 in <version>"
+#elif __cplusplus == 202302L && __cpp_lib_optional != 202110L
+# error "Feature test macro for optional has wrong value for C++23 in <optional>"
+#elif __cplusplus > 202302L && __cpp_lib_optional != 202506L
+# error "Feature test macro for optional has wrong value for C++26 in <optional>"
#endif
#include <testsuite_hooks.h>
diff --git a/libstdc++-v3/testsuite/20_util/optional/requirements_neg.cc b/libstdc++-v3/testsuite/20_util/optional/requirements_neg.cc
index 688c305..142fbbf 100644
--- a/libstdc++-v3/testsuite/20_util/optional/requirements_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/optional/requirements_neg.cc
@@ -2,17 +2,32 @@
#include <optional>
+// C++ < 26:
// T shall be a type other than cv in_place_t or cv nullopt_t
// that meets the Cpp17Destructible requirements
+// C++ >= 26:
+// A type X is a valid contained type for optional if X is an lvalue reference
+// type or a complete non-array object type, and remove_cvref_t<X> is a type
+// other than in_place_t or nullopt_t. If a specialization of optional
+// is instantiated with a type T that is not a valid contained type for
+// optional, the program is ill-formed. If T is an object type,
+// T shall meet the Cpp17Destructible requirements
std::optional<std::nullopt_t> o1; // { dg-error "here" }
std::optional<const std::nullopt_t> o2; // { dg-error "here" }
std::optional<std::in_place_t> o3; // { dg-error "here" }
std::optional<const std::in_place_t> o4; // { dg-error "here" }
-std::optional<int&> o5; // { dg-error "here" }
+std::optional<int&> o5; // { dg-error "here" "optional<T&> is a C++26 feature" { target c++23_down } }
std::optional<int[1]> o6; // { dg-error "here" }
std::optional<int[]> o7; // { dg-error "here" }
std::optional<int()> o8; // { dg-error "here" }
+std::optional<const int &> o9; // { dg-error "here" "optional<T&> is a C++26 feature" { target c++23_down } }
+std::optional<std::in_place_t &> o10; // { dg-error "here" }
+std::optional<const std::in_place_t &> o11; // { dg-error "here" }
+std::optional<std::nullopt_t &> o12; // { dg-error "here" }
+std::optional<const std::nullopt_t &> o13; // { dg-error "here" }
+std::optional<int &&> o14; // { dg-error "here" }
+std::optional<const int &&> o15; // { dg-error "here" }
// { dg-error "static assertion failed" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/20_util/optional/version.cc b/libstdc++-v3/testsuite/20_util/optional/version.cc
index 657a399..ae9339a 100644
--- a/libstdc++-v3/testsuite/20_util/optional/version.cc
+++ b/libstdc++-v3/testsuite/20_util/optional/version.cc
@@ -9,8 +9,10 @@
# error "Feature test macro for optional has wrong value for C++17 in <version>"
#elif __cplusplus == 202002L && __cpp_lib_optional != 202106L
# error "Feature test macro for optional has wrong value for C++20 in <version>"
-#elif __cplusplus > 202002L && __cpp_lib_optional != 202110L
+#elif __cplusplus == 202302L && __cpp_lib_optional != 202110L
# error "Feature test macro for optional has wrong value for C++23 in <version>"
+#elif __cplusplus > 202302L && __cpp_lib_optional != 202506L
+# error "Feature test macro for optional has wrong value for C++26 in <version>"
#endif
#if __cplusplus >= 202302L
@@ -21,8 +23,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 +43,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/owner_equal/cmp.cc b/libstdc++-v3/testsuite/20_util/owner_equal/cmp.cc
new file mode 100644
index 0000000..311ddf2
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/owner_equal/cmp.cc
@@ -0,0 +1,105 @@
+// { dg-do run { target c++26 } }
+// { dg-require-effective-target hosted }
+
+// N5008 20.3.2.6 Struct owner_equal [util.smartptr.owner.equal]
+
+#include <memory>
+#include <algorithm>
+#include <testsuite_hooks.h>
+
+struct A { };
+
+struct B { A a[2]; };
+
+int
+test01()
+{
+ // test empty shared_ptr owners compare equivalent
+ std::owner_equal eq;
+ std::shared_ptr<A> p1;
+ std::shared_ptr<A> p2;
+ VERIFY( eq(p1, p2) && eq(p2, p1) );
+ std::weak_ptr<A> p3;
+ VERIFY( eq(p1, p3) && eq(p3, p1) );
+ VERIFY( eq(p1, p3) && eq(p3, p1) );
+ return 0;
+}
+
+
+// Construction from pointer
+int
+test02()
+{
+ std::owner_equal eq;
+
+ std::shared_ptr<A> empty;
+
+ std::shared_ptr<A> a1(new A);
+ VERIFY( !eq(empty, a1) && !eq(a1, empty) );
+
+ std::shared_ptr<A> a2(new A);
+ VERIFY( !eq(a1, a2) && !eq(a2, a1) );
+
+ std::weak_ptr<A> w1(a1);
+ VERIFY( eq(a1, w1) && eq(w1, a1) );
+
+ std::weak_ptr<A> w2(a2);
+ VERIFY( !eq(w1, w2) && !eq(w2, w1) );
+
+ a1.reset();
+ VERIFY( eq(empty, a1) && eq(a1, empty) );
+ VERIFY( !eq(a1, w1) && !eq(w1, a1) );
+
+ a2.reset();
+ VERIFY( eq(a2, a1) && eq(a1, a2) );
+
+ return 0;
+}
+
+// aliasing
+int
+test03()
+{
+ std::owner_equal eq;
+
+ std::shared_ptr<B> b(new B);
+ std::shared_ptr<A> a0(b, &b->a[0]);
+ std::shared_ptr<A> a1(b, &b->a[1]);
+ // values are different but owners are equivalent:
+ VERIFY( a0 < a1 && eq(a0, a1) && eq(b, a0) && eq(b, a1) );
+
+ std::weak_ptr<A> w0(a0);
+ std::weak_ptr<A> w1(a1);
+ VERIFY( eq(w0, w1) && eq(w1, w0) );
+ VERIFY( eq(a0, w1) && eq(w1, a0) );
+ VERIFY( eq(w0, a1) && eq(a1, w0) );
+
+ return 0;
+}
+
+// as binary predicate
+int
+test04()
+{
+ std::owner_equal eq;
+
+ std::shared_ptr<B> b(new B);
+ std::shared_ptr<A> a0(b, &b->a[0]);
+ std::shared_ptr<A> a1(b, &b->a[1]);
+ std::shared_ptr<A> c(new A);
+ std::weak_ptr<A> a[3]{a0, a1, c};
+ std::weak_ptr<A>* p = std::unique(a, a+3, eq);
+ VERIFY( p == &a[2] );
+
+ return 0;
+}
+
+int
+main()
+{
+ test01();
+ test02();
+ test03();
+ test04();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/20_util/owner_equal/noexcept.cc b/libstdc++-v3/testsuite/20_util/owner_equal/noexcept.cc
new file mode 100644
index 0000000..fb479f6
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/owner_equal/noexcept.cc
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++26 } }
+// { dg-require-effective-target hosted }
+
+// N5008 20.3.2.6 Struct owner_equal [util.smartptr.owner.equal]
+
+#include <memory>
+
+#ifndef __cpp_lib_smart_ptr_owner_equality
+# error "Feature-test macro for smart ptr owner equality missing in <memory>"
+#elif __cpp_lib_smart_ptr_owner_equality != 202306L
+# error "Feature-test macro for smart ptr owner equality has wrong value in <memory>"
+#endif
+
+const std::owner_equal eq;
+const std::shared_ptr<int> si;
+const std::weak_ptr<int> wi;
+static_assert( noexcept(!eq(si, si)) );
+static_assert( noexcept(!eq(si, wi)) );
+static_assert( noexcept(!eq(wi, si)) );
+static_assert( noexcept(!eq(wi, wi)) );
+static_assert( noexcept(!eq(si, wi)) );
+static_assert( noexcept(!eq(wi, si)) );
+const std::shared_ptr<long> sl;
+const std::weak_ptr<char> wc;
+static_assert( noexcept(!eq(si, si)) );
+static_assert( noexcept(!eq(si, sl)) );
+static_assert( noexcept(!eq(sl, si)) );
+static_assert( noexcept(!eq(si, wc)) );
+static_assert( noexcept(!eq(wc, si)) );
+static_assert( noexcept(!eq(wc, wi)) );
diff --git a/libstdc++-v3/testsuite/20_util/owner_equal/version.cc b/libstdc++-v3/testsuite/20_util/owner_equal/version.cc
new file mode 100644
index 0000000..db29154
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/owner_equal/version.cc
@@ -0,0 +1,13 @@
+// { dg-do compile { target c++26 } }
+// { dg-require-effective-target hosted }
+
+// N5008 17.3.2 Header <version> synopsis [version.syn]
+
+#include <version>
+
+#ifndef __cpp_lib_smart_ptr_owner_equality
+# error "Feature-test macro for smart ptr owner equality missing in <version>"
+#elif __cpp_lib_smart_ptr_owner_equality != 202306L
+# error "Feature-test macro for smart ptr owner equality has wrong value in <version>"
+#endif
+
diff --git a/libstdc++-v3/testsuite/20_util/owner_hash/cmp.cc b/libstdc++-v3/testsuite/20_util/owner_hash/cmp.cc
new file mode 100644
index 0000000..c03a926
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/owner_hash/cmp.cc
@@ -0,0 +1,87 @@
+// { dg-do run { target c++26 } }
+// { dg-require-effective-target hosted }
+
+// N5008 20.3.2.5 Struct owner_hash [util.smartptr.owner.hash]
+
+#include <memory>
+#include <algorithm>
+#include <testsuite_hooks.h>
+
+struct A { };
+
+struct B { A a[2]; };
+
+int
+test01()
+{
+ // test empty shared_ptr hashes compare equivalent
+ std::owner_hash oh;
+ std::shared_ptr<A> p1;
+ std::shared_ptr<A> p2;
+ VERIFY( oh(p1) == oh(p2) );
+ std::weak_ptr<A> p3;
+ VERIFY( oh(p1) == oh(p3) );
+ VERIFY( oh(p1) == oh(p3) );
+ return 0;
+}
+
+
+// Construction from pointer
+int
+test02()
+{
+ std::owner_hash oh;
+
+ std::shared_ptr<A> empty;
+
+ std::shared_ptr<A> a1(new A);
+ VERIFY( oh(empty) != oh(a1) );
+
+ std::shared_ptr<A> a2(new A);
+ VERIFY( oh(a1) != oh(a2) );
+
+ std::weak_ptr<A> w1(a1);
+ VERIFY( oh(a1) == oh(w1) );
+
+ std::weak_ptr<A> w2(a2);
+ VERIFY( oh(w1) != oh(w2) );
+
+ a1.reset();
+ VERIFY( oh(empty) == oh(a1) );
+ VERIFY( oh(a1) != oh(w1) );
+
+ a2.reset();
+ VERIFY( oh(a2) == oh(a1) );
+
+ return 0;
+}
+
+// aliasing
+int
+test03()
+{
+ std::owner_hash oh;
+
+ std::shared_ptr<B> b(new B);
+ std::shared_ptr<A> a0(b, &b->a[0]);
+ std::shared_ptr<A> a1(b, &b->a[1]);
+ // values are different but owners are ohuivalent:
+ VERIFY( a0 < a1 && oh(a0) == oh(a1) && oh(b) == oh(a0) && oh(b) == oh(a1) );
+
+ std::weak_ptr<A> w0(a0);
+ std::weak_ptr<A> w1(a1);
+ VERIFY( oh(w0) == oh(w1) );
+ VERIFY( oh(a0) == oh(w1) );
+ VERIFY( oh(w0) == oh(a1) );
+
+ return 0;
+}
+
+int
+main()
+{
+ test01();
+ test02();
+ test03();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/20_util/owner_hash/noexcept.cc b/libstdc++-v3/testsuite/20_util/owner_hash/noexcept.cc
new file mode 100644
index 0000000..12b2f2f
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/owner_hash/noexcept.cc
@@ -0,0 +1,16 @@
+// { dg-do compile { target c++26 } }
+// { dg-require-effective-target hosted }
+
+// N5008 20.3.2.5 Struct owner_hash [util.smartptr.owner.hash]
+
+#include <memory>
+
+const std::owner_hash oh;
+const std::shared_ptr<int> si;
+const std::weak_ptr<int> wi;
+static_assert( noexcept(!oh(si)) );
+static_assert( noexcept(!oh(wi)) );
+const std::shared_ptr<long> sl;
+const std::weak_ptr<char> wc;
+static_assert( noexcept(!oh(sl)) );
+static_assert( noexcept(!oh(wc)) );
diff --git a/libstdc++-v3/testsuite/20_util/pair/astuple/get_by_type.cc b/libstdc++-v3/testsuite/20_util/pair/astuple/get_by_type.cc
index 33ebf7a..05a61c3 100644
--- a/libstdc++-v3/testsuite/20_util/pair/astuple/get_by_type.cc
+++ b/libstdc++-v3/testsuite/20_util/pair/astuple/get_by_type.cc
@@ -33,3 +33,55 @@ void test01()
const int&& cpsecond __attribute__((unused)) =
std::get<int>(std::move(cp));
}
+
+// PR libstdc++/121745 return of get(pair<_Up, _Tp>&& __p) may be ill-formed
+void
+test_pr121745(std::pair<float&, int&> p)
+{
+ float& pfirst = std::get<float&>(std::move(p));
+ int& psecond = std::get<int&>(std::move(p));
+
+ const auto& p2 = p;
+ float& p2first = std::get<float&>(std::move(p2));
+ int& p2second = std::get<int&>(std::move(p2));
+}
+
+template<typename T, typename Pair>
+using get_t = decltype(std::get<T>(std::declval<Pair>()));
+
+// Check that get<T>(Pair) returns Ret
+template<typename T, typename Pair, typename Ret>
+constexpr bool verify = std::is_same<get_t<T, Pair>, Ret>::value;
+
+template<typename T1, typename T2>
+void
+check()
+{
+ // Overloads for accessing first member
+ static_assert( verify<T1, std::pair<T1, T2>&, T1&>,
+ "T1& get(pair<T1, T2>&)" );
+ static_assert( verify<T1, const std::pair<T1, T2>&, const T1&>,
+ "const T1& get(const pair<T1, T2>&)" );
+ static_assert( verify<T1, std::pair<T1, T2>&&, T1&&>,
+ "T1&& get(pair<T1, T2>&&)" );
+ static_assert( verify<T1, const std::pair<T1, T2>&&, const T1&&>,
+ "const T1&& get(const pair<T1, T2>&&)" );
+
+ // Overloads for accessing second member
+ static_assert( verify<T2, std::pair<T1, T2>&, T2&>,
+ "T2& get(pair<T1, T2>&)" );
+ static_assert( verify<T2, const std::pair<T1, T2>&, const T2&>,
+ "const T2& get(const pair<T1, T2>&)" );
+ static_assert( verify<T2, std::pair<T1, T2>&&, T2&&>,
+ "T2&& get(pair<T1, T2>&&)" );
+ static_assert( verify<T2, const std::pair<T1, T2>&&, const T2&&>,
+ "const T2&& get(const pair<T1, T2>&&)" );
+}
+
+void
+test_all()
+{
+ check<float, int>();
+ check<float&, int&>();
+ check<float&&, int&&>();
+}
diff --git a/libstdc++-v3/testsuite/20_util/pair/cons/110853.cc b/libstdc++-v3/testsuite/20_util/pair/cons/110853.cc
new file mode 100644
index 0000000..57ebfb8
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/pair/cons/110853.cc
@@ -0,0 +1,10 @@
+// { dg-do compile { target c++17 } }
+// PR libstdc++/110853
+// Bad interaction between deduction guide with decay and constraints
+// (CTAD, std::pair and function lvalue)
+
+#include <utility>
+
+void func() {}
+std::pair p(1, func);
+std::pair<int, void (*)()>& r = p;
diff --git a/libstdc++-v3/testsuite/20_util/ratio/operations/ops_overflow_neg.cc b/libstdc++-v3/testsuite/20_util/ratio/operations/ops_overflow_neg.cc
index 5eff8e3..368866a 100644
--- a/libstdc++-v3/testsuite/20_util/ratio/operations/ops_overflow_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/ratio/operations/ops_overflow_neg.cc
@@ -1,6 +1,6 @@
// { dg-do compile { target c++11 } }
// { dg-require-cstdint "" }
-
+// { dg-additional-options "-Wsystem-headers" }
// 2008-07-03 Chris Fairles <chris.fairles@gmail.com>
// Copyright (C) 2008-2025 Free Software Foundation, Inc.
diff --git a/libstdc++-v3/testsuite/20_util/reference_wrapper/p2655r3.cc b/libstdc++-v3/testsuite/20_util/reference_wrapper/p2655r3.cc
new file mode 100644
index 0000000..f2fafec
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/reference_wrapper/p2655r3.cc
@@ -0,0 +1,75 @@
+// P2655R3 - common_reference_t of reference_wrapper Should Be a Reference Type
+// Implemented as a DR against C++20
+// { dg-do compile { target c++20 } }
+
+#include <functional>
+
+#if __cpp_lib_common_reference_wrapper != 202302L
+# error "Feature-test macro __cpp_lib_common_reference_wrapper has wrong value in <functional>"
+#endif
+
+using std::is_same_v;
+using std::common_reference_t;
+using std::reference_wrapper;
+
+static_assert( is_same_v<common_reference_t<const reference_wrapper<int>&, int&>, int&> );
+static_assert( is_same_v<common_reference_t<int&, const reference_wrapper<int>&>, int&> );
+
+static_assert( is_same_v<common_reference_t<reference_wrapper<int>, int&>,
+ common_reference_t<int&, int&>> );
+static_assert( is_same_v<common_reference_t<reference_wrapper<int>, const int&>,
+ common_reference_t<int&, const int&>> );
+static_assert( is_same_v<common_reference_t<reference_wrapper<const int>, int&>,
+ common_reference_t<const int&, int&>> );
+
+static_assert( is_same_v<common_reference_t<int&, reference_wrapper<int>>,
+ common_reference_t<int&, int&>> );
+static_assert( is_same_v<common_reference_t<const int&, reference_wrapper<int>>,
+ common_reference_t<int&, const int&>> );
+static_assert( is_same_v<common_reference_t<int&, reference_wrapper<const int>>,
+ common_reference_t<const int&, int&>> );
+
+static_assert( is_same_v<common_reference_t<reference_wrapper<int>&, reference_wrapper<int>&>,
+ reference_wrapper<int>&> );
+
+static_assert( is_same_v<common_reference_t<reference_wrapper<char>,
+ reference_wrapper<int>>,
+ int> );
+static_assert( is_same_v<common_reference_t<reference_wrapper<reference_wrapper<int>>,
+ reference_wrapper<int>>,
+ reference_wrapper<int>> );
+static_assert( is_same_v<common_reference_t<reference_wrapper<int>,
+ reference_wrapper<reference_wrapper<int>>>,
+ reference_wrapper<int>> );
+
+struct A { };
+struct B { operator A&() const; };
+
+template<typename T, typename U>
+concept has_common_reference = requires {
+ typename std::common_reference_t<T, U>;
+};
+
+static_assert( is_same_v<common_reference_t<reference_wrapper<A>, const B&>, A&> );
+// reference_wrapper<const B> is not convertible to A&, as it would require two user
+// defined conversions.
+static_assert( !has_common_reference<A, reference_wrapper<const B>> );
+static_assert( !has_common_reference<reference_wrapper<A>, reference_wrapper<const B>> );
+
+struct D1 : A {};
+struct D2 : A {};
+
+template<template<class> typename Qual1, template<class> typename Qual2>
+struct std::basic_common_reference<D1, D2, Qual1, Qual2>
+ : std::common_reference<Qual1<A>, Qual2<A>>
+{ };
+
+template<template<class> typename Qual1, template<class> typename Qual2>
+struct std::basic_common_reference<D2, D1, Qual1, Qual2>
+ : std::common_reference<Qual1<A>, Qual2<A>>
+{ };
+
+static_assert( is_same_v<common_reference_t<D1&, D2&>, A&> );
+static_assert( is_same_v<common_reference_t<reference_wrapper<D1>, D2&>, A&> );
+static_assert( is_same_v<common_reference_t<D1&, reference_wrapper<D2>>, A&> );
+static_assert( !has_common_reference<reference_wrapper<D1>, reference_wrapper<D2>> );
diff --git a/libstdc++-v3/testsuite/20_util/scoped_allocator/69293_neg.cc b/libstdc++-v3/testsuite/20_util/scoped_allocator/69293_neg.cc
index d4be086..a3fbeba 100644
--- a/libstdc++-v3/testsuite/20_util/scoped_allocator/69293_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/scoped_allocator/69293_neg.cc
@@ -42,6 +42,8 @@ static_assert(uses_allocator<X, inner_alloc_type>{}, "");
static_assert(!is_constructible<X, allocator_arg_t, inner_alloc_type>{}, "");
static_assert(!is_constructible<X, inner_alloc_type>{}, "");
+// { dg-error "too many initializers" "" { target c++20 } 0 }
+
void
test01()
{
diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/assign/auto_ptr.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/assign/auto_ptr.cc
index 96678d2..d4096ce 100644
--- a/libstdc++-v3/testsuite/20_util/shared_ptr/assign/auto_ptr.cc
+++ b/libstdc++-v3/testsuite/20_util/shared_ptr/assign/auto_ptr.cc
@@ -1,4 +1,4 @@
-// { dg-options "-Wno-deprecated" }
+// { dg-options "-Wno-deprecated-declarations" }
// { dg-add-options using-deprecated }
// { dg-do run { target c++11 } }
// { dg-require-effective-target hosted }
diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/assign/auto_ptr_neg.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/assign/auto_ptr_neg.cc
index d7dfcf1..09f7ff4 100644
--- a/libstdc++-v3/testsuite/20_util/shared_ptr/assign/auto_ptr_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/shared_ptr/assign/auto_ptr_neg.cc
@@ -1,4 +1,4 @@
-// { dg-options "-Wno-deprecated" }
+// { dg-options "-Wno-deprecated-declarations" }
// { dg-add-options using-deprecated }
// { dg-do compile { target c++11 } }
// { dg-require-effective-target hosted }
diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/assign/auto_ptr_rvalue.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/assign/auto_ptr_rvalue.cc
index 8c98f7e..c94fcdd 100644
--- a/libstdc++-v3/testsuite/20_util/shared_ptr/assign/auto_ptr_rvalue.cc
+++ b/libstdc++-v3/testsuite/20_util/shared_ptr/assign/auto_ptr_rvalue.cc
@@ -1,4 +1,4 @@
-// { dg-options "-Wno-deprecated" }
+// { dg-options "-Wno-deprecated -Wno-deprecated-declarations" }
// { dg-add-options using-deprecated }
// { dg-do compile { target c++11 } }
// { dg-require-effective-target hosted }
diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/atomic/1.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/atomic/1.cc
index b3d2cde..2be9f30 100644
--- a/libstdc++-v3/testsuite/20_util/shared_ptr/atomic/1.cc
+++ b/libstdc++-v3/testsuite/20_util/shared_ptr/atomic/1.cc
@@ -18,7 +18,7 @@
// { dg-do run { target c++11 } }
// { dg-require-gthreads "" }
// { dg-require-effective-target hosted }
-// { dg-additional-options "-Wno-deprecated" { target c++20 } }
+// { dg-additional-options "-Wno-deprecated-declarations" { target c++20 } }
#include <memory>
diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/atomic/2.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/atomic/2.cc
index 9c75922..95baedd 100644
--- a/libstdc++-v3/testsuite/20_util/shared_ptr/atomic/2.cc
+++ b/libstdc++-v3/testsuite/20_util/shared_ptr/atomic/2.cc
@@ -18,7 +18,7 @@
// { dg-do run { target c++11 } }
// { dg-require-gthreads "" }
// { dg-require-effective-target hosted }
-// { dg-additional-options "-Wno-deprecated" { target c++20 } }
+// { dg-additional-options "-Wno-deprecated-declarations" { target c++20 } }
#include <memory>
diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/atomic/3.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/atomic/3.cc
index a722792..3cbe08b 100644
--- a/libstdc++-v3/testsuite/20_util/shared_ptr/atomic/3.cc
+++ b/libstdc++-v3/testsuite/20_util/shared_ptr/atomic/3.cc
@@ -1,7 +1,7 @@
// { dg-do run { target c++11 } }
// { dg-additional-options "-pthread" { target pthread } }
// { dg-require-gthreads "" }
-// { dg-additional-options "-Wno-deprecated" { target c++20 } }
+// { dg-additional-options "-Wno-deprecated-declarations" { target c++20 } }
// Copyright (C) 2014-2025 Free Software Foundation, Inc.
//
diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/atomic/pr118757.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/atomic/pr118757.cc
new file mode 100644
index 0000000..f49ae38
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/shared_ptr/atomic/pr118757.cc
@@ -0,0 +1,30 @@
+// { dg-do run { target c++20 } }
+// { dg-additional-options "-pthread" { target pthread } }
+// { dg-require-gthreads "" }
+// { dg-require-effective-target hosted }
+
+#include <memory>
+#include <chrono>
+#include <thread>
+#include <barrier>
+
+std::shared_ptr<int> q = std::make_shared<int>(42);
+std::atomic<std::shared_ptr<int>> p = q;
+
+std::barrier bar(2);
+
+void signaller()
+{
+ std::this_thread::sleep_for(std::chrono::seconds(1));
+ p.store(std::shared_ptr<int>(q, nullptr));
+ p.notify_one();
+ bar.arrive_and_wait();
+}
+
+int main(int, char**)
+{
+ std::thread thr(signaller);
+ p.wait(q);
+ bar.arrive_and_wait();
+ thr.join();
+}
diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/cons/43820_neg.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/43820_neg.cc
index 544cc01..12639fa 100644
--- a/libstdc++-v3/testsuite/20_util/shared_ptr/cons/43820_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/43820_neg.cc
@@ -1,4 +1,4 @@
-// { dg-options "-Wno-deprecated" }
+// { dg-options "-Wno-deprecated-declarations" }
// { dg-add-options using-deprecated }
// { dg-do compile { target c++11 } }
// { dg-require-effective-target hosted }
diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/cons/auto_ptr.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/auto_ptr.cc
index 2e4f0ba..847210b 100644
--- a/libstdc++-v3/testsuite/20_util/shared_ptr/cons/auto_ptr.cc
+++ b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/auto_ptr.cc
@@ -1,4 +1,4 @@
-// { dg-options "-Wno-deprecated" }
+// { dg-options "-Wno-deprecated-declarations" }
// { dg-add-options using-deprecated }
// { dg-do run { target c++11 } }
// { dg-require-effective-target hosted }
diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/cons/auto_ptr_neg.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/auto_ptr_neg.cc
index 11b62d4..5779f85 100644
--- a/libstdc++-v3/testsuite/20_util/shared_ptr/cons/auto_ptr_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/auto_ptr_neg.cc
@@ -1,4 +1,4 @@
-// { dg-options "-Wno-deprecated" }
+// { dg-options "-Wno-deprecated-declarations" }
// { dg-add-options using-deprecated }
// { dg-do compile { target c++11 } }
// { dg-require-effective-target hosted }
diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/cons/move.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/move.cc
index 2dc161d..e380d76 100644
--- a/libstdc++-v3/testsuite/20_util/shared_ptr/cons/move.cc
+++ b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/move.cc
@@ -140,6 +140,8 @@ test05()
{
reset_count_struct __attribute__((unused)) reset;
+ // The std::move here prevents copy elision, so we construct from a prvalue.
+ // { dg-prune-output "-Wpessimizing-move" }
std::shared_ptr<A> a(std::move(std::shared_ptr<A>(new A)));
VERIFY( a.use_count() == 1 );
VERIFY( A::ctor_count == 1 );
diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/creation/dr925.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/creation/dr925.cc
index 162f92d..4743387 100644
--- a/libstdc++-v3/testsuite/20_util/shared_ptr/creation/dr925.cc
+++ b/libstdc++-v3/testsuite/20_util/shared_ptr/creation/dr925.cc
@@ -1,4 +1,4 @@
-// { dg-options "-Wno-deprecated" }
+// { dg-options "-Wno-deprecated-declarations" }
// { dg-add-options using-deprecated }
// { dg-do run { target c++11 } }
// { dg-require-effective-target hosted }
diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/observers/owner_equal.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/observers/owner_equal.cc
new file mode 100644
index 0000000..7ec8691
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/shared_ptr/observers/owner_equal.cc
@@ -0,0 +1,74 @@
+// { dg-do run { target c++26 } }
+// { dg-require-effective-target hosted }
+
+// N5008 20.3.2.2.6 shared_ptr observers [util.smartptr.shared.obs]
+
+#include <memory>
+#include <testsuite_hooks.h>
+
+struct A
+{
+ int i;
+ virtual ~A() { }
+};
+
+struct B : A
+{
+};
+
+void
+test01()
+{
+ // test empty shared_ptr owners compare equivalent
+ std::shared_ptr<A> p1;
+ std::shared_ptr<B> p2;
+ VERIFY( p1.owner_equal(p2) && p2.owner_equal(p1) );
+}
+
+
+// Construction from pointer
+void
+test02()
+{
+ std::shared_ptr<A> a0;
+
+ std::shared_ptr<A> a1(new A);
+ VERIFY( !a1.owner_equal(a0) && !a0.owner_equal(a1) );
+
+ std::shared_ptr<B> b1(new B);
+ VERIFY( !a1.owner_equal(b1) && !b1.owner_equal(a1) );
+
+ std::shared_ptr<A> a2(a1);
+ VERIFY( a1.owner_equal(a2) && a2.owner_equal(a1) );
+ a2 = b1;
+ VERIFY( b1.owner_equal(a2) && a2.owner_equal(b1) );
+
+ std::weak_ptr<A> w1(a1);
+ VERIFY( a1.owner_equal(w1) && w1.owner_equal(a1) );
+ std::weak_ptr<A> w2(a2);
+ VERIFY( b1.owner_equal(w2) && w2.owner_equal(b1) );
+
+ static_assert( noexcept(a1.owner_equal(a0)) );
+ static_assert( noexcept(a1.owner_equal(b1)) );
+ static_assert( noexcept(b1.owner_equal(a1)) );
+ static_assert( noexcept(a1.owner_equal(w1)) );
+ static_assert( noexcept(b1.owner_equal(w1)) );
+}
+
+// Aliasing
+void
+test03()
+{
+ std::shared_ptr<A> p1(new A());
+ std::shared_ptr<int> p2(p1, &p1->i);
+ VERIFY( p1.owner_equal(p2) && p2.owner_equal(p1) );
+}
+
+int
+main()
+{
+ test01();
+ test02();
+ test03();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/observers/owner_hash.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/observers/owner_hash.cc
new file mode 100644
index 0000000..8e6c02c
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/shared_ptr/observers/owner_hash.cc
@@ -0,0 +1,71 @@
+// { dg-do run { target c++26 } }
+// { dg-require-effective-target hosted }
+
+// N5008 20.3.2.2.6 shared_ptr observers [util.smartptr.shared.obs]
+
+#include <memory>
+#include <testsuite_hooks.h>
+
+struct A
+{
+ int i;
+ virtual ~A() { }
+};
+
+struct B : A
+{
+};
+
+void
+test01()
+{
+ // test empty shared_ptr hashes compare equivalent
+ std::shared_ptr<A> p1;
+ std::shared_ptr<B> p2;
+ VERIFY( p1.owner_hash() == p2.owner_hash() );
+}
+
+
+// Construction from pointer
+void
+test02()
+{
+ std::shared_ptr<A> a0;
+
+ std::shared_ptr<A> a1(new A);
+ VERIFY( a1.owner_hash() != a0.owner_hash() );
+
+ std::shared_ptr<B> b1(new B);
+ VERIFY( a1.owner_hash() != b1.owner_hash() );
+
+ std::shared_ptr<A> a2(a1);
+ VERIFY( a1.owner_hash() == a2.owner_hash() );
+ a2 = b1;
+ VERIFY( b1.owner_hash() == a2.owner_hash() );
+
+ std::weak_ptr<A> w1(a1);
+ VERIFY( a1.owner_hash() == w1.owner_hash() );
+ std::weak_ptr<A> w2(a2);
+ VERIFY( b1.owner_hash() == w2.owner_hash() );
+
+ static_assert( noexcept(a1.owner_hash()) );
+ static_assert( noexcept(b1.owner_hash()) );
+}
+
+// Aliasing
+void
+test03()
+{
+ std::shared_ptr<A> p1(new A());
+ std::shared_ptr<int> p2(p1, &p1->i);
+ VERIFY( p1.owner_hash() == p2.owner_hash() );
+}
+
+int
+main()
+{
+ test01();
+ test02();
+ test03();
+ return 0;
+}
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/destroy/121024.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/destroy/121024.cc
new file mode 100644
index 0000000..781dd40
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/destroy/121024.cc
@@ -0,0 +1,77 @@
+// { dg-do compile { target c++26 } }
+
+// Bug 121024
+// ranges::destroy and ranges::destroy_n do not end lifetime of trivial types
+
+#include <memory>
+
+consteval bool is_within_lifetime(const auto* p) noexcept
+{
+ return __builtin_constant_p(*p);
+}
+
+template<typename T>
+struct Buf
+{
+ constexpr Buf() : p(std::allocator<T>().allocate(2)) { }
+ constexpr ~Buf() { std::allocator<T>().deallocate(p, 2); }
+ T* p;
+};
+
+template<typename T>
+consteval bool
+test_destroy()
+{
+ Buf<T> buf;
+ std::uninitialized_value_construct(buf.p, buf.p + 2);
+ std::destroy(buf.p, buf.p + 2);
+ return not is_within_lifetime(buf.p) && not is_within_lifetime(buf.p + 1);
+}
+
+template<typename T>
+consteval bool
+test_destroy_n()
+{
+ Buf<T> buf;
+ std::uninitialized_value_construct_n(buf.p, 2);
+ std::destroy_n(buf.p, 2);
+ return not is_within_lifetime(buf.p) && not is_within_lifetime(buf.p + 1);
+}
+
+template<typename T>
+consteval bool
+test_ranges_destroy()
+{
+ Buf<T> buf;
+ std::uninitialized_value_construct(buf.p, buf.p + 2);
+ std::ranges::destroy(buf.p, buf.p + 2);
+ return not is_within_lifetime(buf.p) && not is_within_lifetime(buf.p + 1);
+}
+
+template<typename T>
+consteval bool
+test_ranges_destroy_n()
+{
+ Buf<T> buf;
+ std::uninitialized_value_construct_n(buf.p, 2);
+ std::ranges::destroy_n(buf.p, 2);
+ return not is_within_lifetime(buf.p) && not is_within_lifetime(buf.p + 1);
+}
+
+struct O
+{
+ constexpr O() { }
+ constexpr ~O() { }
+};
+
+// These all fail for GCC because is_within_lifetime still returns true
+// after the lifetime has been ended.
+// { dg-xfail-if "PR c++/102284" { *-*-* } }
+static_assert( test_destroy<int>() );
+static_assert( test_destroy<O>() );
+static_assert( test_destroy_n<int>() );
+static_assert( test_destroy_n<O>() );
+static_assert( test_ranges_destroy<int>() );
+static_assert( test_ranges_destroy<O>() );
+static_assert( test_ranges_destroy_n<int>() );
+static_assert( test_ranges_destroy_n<O>() );
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_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_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/synchronized_pool_resource/118681.cc b/libstdc++-v3/testsuite/20_util/synchronized_pool_resource/118681.cc
new file mode 100644
index 0000000..facbf00
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/synchronized_pool_resource/118681.cc
@@ -0,0 +1,6 @@
+// { dg-do run { target c++17 } }
+// { dg-require-gthreads "" }
+// Bug 118681 - unsynchronized_pool_resource may fail to respect alignment
+
+#define RESOURCE std::pmr::synchronized_pool_resource
+#include "../unsynchronized_pool_resource/118681.cc"
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/requirements/empty_trivial.cc b/libstdc++-v3/testsuite/20_util/tuple/requirements/empty_trivial.cc
new file mode 100644
index 0000000..ee18bb3
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/tuple/requirements/empty_trivial.cc
@@ -0,0 +1,17 @@
+// { dg-do compile { target c++11 } }
+
+#include <tuple>
+#include <type_traits>
+
+// Check that tuple<> has the expected trivial properties
+static_assert(std::is_trivially_copyable<std::tuple<>>::value,
+ "tuple<> should be trivially copyable");
+static_assert(std::is_trivially_copy_constructible<std::tuple<>>::value,
+ "tuple<> should be trivially copy constructible");
+static_assert(std::is_trivially_move_constructible<std::tuple<>>::value,
+ "tuple<> should be trivially move constructible");
+static_assert(std::is_trivially_copy_assignable<std::tuple<>>::value,
+ "tuple<> should be trivially copy assignable");
+static_assert(std::is_trivially_move_assignable<std::tuple<>>::value,
+ "tuple<> should be trivially move assignable");
+
diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/cons/auto_ptr.cc b/libstdc++-v3/testsuite/20_util/unique_ptr/cons/auto_ptr.cc
index c9ac7f9..b49171d 100644
--- a/libstdc++-v3/testsuite/20_util/unique_ptr/cons/auto_ptr.cc
+++ b/libstdc++-v3/testsuite/20_util/unique_ptr/cons/auto_ptr.cc
@@ -1,4 +1,4 @@
-// { dg-options "-Wno-deprecated" }
+// { dg-options "-Wno-deprecated-declarations" }
// { dg-add-options using-deprecated }
// { dg-do run { target c++11 } }
diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/cons/auto_ptr_neg.cc b/libstdc++-v3/testsuite/20_util/unique_ptr/cons/auto_ptr_neg.cc
index 7b9758f..6440dd7 100644
--- a/libstdc++-v3/testsuite/20_util/unique_ptr/cons/auto_ptr_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/unique_ptr/cons/auto_ptr_neg.cc
@@ -1,4 +1,4 @@
-// { dg-options "-Wno-deprecated" }
+// { dg-options "-Wno-deprecated-declarations" }
// { dg-add-options using-deprecated }
// { dg-do compile { target c++11 } }
diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/lwg4148.cc b/libstdc++-v3/testsuite/20_util/unique_ptr/lwg4148.cc
index c70d7a6..f5697e4 100644
--- a/libstdc++-v3/testsuite/20_util/unique_ptr/lwg4148.cc
+++ b/libstdc++-v3/testsuite/20_util/unique_ptr/lwg4148.cc
@@ -1,4 +1,5 @@
// { dg-do compile { target c++11 } }
+// { dg-additional-options "-Wsystem-headers" }
// LWG 4148. unique_ptr::operator* should not allow dangling references
diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/modifiers/93562.cc b/libstdc++-v3/testsuite/20_util/unique_ptr/modifiers/93562.cc
index 95df7af..0443578 100644
--- a/libstdc++-v3/testsuite/20_util/unique_ptr/modifiers/93562.cc
+++ b/libstdc++-v3/testsuite/20_util/unique_ptr/modifiers/93562.cc
@@ -76,11 +76,32 @@ test03()
VERIFY(p2.get_deleter().id == -1);
}
+namespace B
+{
+ struct Deleter
+ {
+ Deleter& operator=(const Deleter&) = delete;
+
+ void operator()(int* p) const noexcept { delete[] p; }
+
+ // found by ADL
+ friend void swap(Deleter& lhs, Deleter& rhs) noexcept
+ { std::swap(lhs.id, rhs.id); }
+
+ int id;
+ };
+
+ static_assert(!std::is_move_assignable<Deleter>::value, "not assignable");
+#if __cplusplus >= 201703L
+ static_assert(std::is_swappable_v<Deleter>, "but swappable");
+#endif
+} // namespace B
+
void
test04()
{
- std::unique_ptr<int[], A::Deleter> p1(new int[1]{1}, { -1 });
- std::unique_ptr<int[], A::Deleter> p2(new int[2]{2, 2}, { -2 });
+ std::unique_ptr<int[], B::Deleter> p1(new int[1]{1}, { -1 });
+ std::unique_ptr<int[], B::Deleter> p2(new int[2]{2, 2}, { -2 });
int* const pi1 = p1.get();
int* const pi2 = p2.get();
// This type must swappable even though the deleter is not move-assignable:
diff --git a/libstdc++-v3/testsuite/20_util/unsynchronized_pool_resource/118681.cc b/libstdc++-v3/testsuite/20_util/unsynchronized_pool_resource/118681.cc
new file mode 100644
index 0000000..9935f79
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/unsynchronized_pool_resource/118681.cc
@@ -0,0 +1,58 @@
+// { dg-do run { target c++17 } }
+// Bug 118681 - unsynchronized_pool_resource may fail to respect alignment
+
+#include <memory_resource>
+#include <cstdio>
+#include <testsuite_hooks.h>
+
+#ifndef RESOURCE
+# define RESOURCE std::pmr::unsynchronized_pool_resource
+#endif
+
+bool any_misaligned = false;
+
+bool
+is_aligned(void* p, [[maybe_unused]] std::size_t size, std::size_t alignment)
+{
+ const bool misaligned = reinterpret_cast<std::uintptr_t>(p) % alignment;
+#ifdef DEBUG
+ std::printf("allocate(%2zu, %2zu): %p is aligned %scorrectly\n",
+ size, alignment, p, misaligned ? "in" : "");
+ any_misaligned |= misaligned;
+ return true;
+#endif
+ return ! misaligned;
+}
+
+void
+test_alignment(std::pmr::memory_resource& res, bool dealloc)
+{
+ for (std::size_t alignment : { 8, 16, 32, 64 })
+ {
+ for (std::size_t size : { 9, 12, 24, 40, 48, 56, 72 })
+ {
+ void* p1 = res.allocate(size, alignment);
+ void* p2 = res.allocate(size, alignment);
+
+ VERIFY( is_aligned(p1, size, alignment) );
+ VERIFY( is_aligned(p2, size, alignment) );
+
+ if (dealloc)
+ {
+ res.deallocate(p1, size, alignment);
+ res.deallocate(p2, size, alignment);
+ }
+ }
+ }
+}
+
+int main()
+{
+ RESOURCE res;
+ test_alignment(res, true);
+ res.release();
+ test_alignment(res, false);
+ res.release();
+
+ VERIFY( ! any_misaligned );
+}
diff --git a/libstdc++-v3/testsuite/20_util/variable_templates_for_traits.cc b/libstdc++-v3/testsuite/20_util/variable_templates_for_traits.cc
index 253886b..b489587 100644
--- a/libstdc++-v3/testsuite/20_util/variable_templates_for_traits.cc
+++ b/libstdc++-v3/testsuite/20_util/variable_templates_for_traits.cc
@@ -1,4 +1,4 @@
-// { dg-additional-options "-Wno-deprecated" { target c++2a } }
+// { dg-additional-options "-Wno-deprecated-declarations" { target c++2a } }
// { dg-do compile { target c++17 } }
// Copyright (C) 2014-2025 Free Software Foundation, Inc.
diff --git a/libstdc++-v3/testsuite/20_util/variant/112591.cc b/libstdc++-v3/testsuite/20_util/variant/112591.cc
new file mode 100644
index 0000000..b1b07c4
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/variant/112591.cc
@@ -0,0 +1,32 @@
+// { dg-do run { target c++17 } }
+
+#include <variant>
+#include <testsuite_hooks.h>
+
+struct NonEmpty { int x; };
+struct TrivialEmpty {};
+struct NonTrivialEmpty { ~NonTrivialEmpty() {} };
+
+template<typename T>
+struct Compose : T
+{
+ std::variant<T, int> v;
+};
+
+template<typename T>
+bool testAlias()
+{
+ Compose<T> c;
+ return static_cast<T*>(&c) == &std::get<T>(c.v);
+}
+
+int main()
+{
+ VERIFY( !testAlias<NonEmpty>() );
+ VERIFY( !testAlias<TrivialEmpty>() );
+#if __cplusplus >= 202002L
+ VERIFY( !testAlias<NonTrivialEmpty>() );
+#else
+ VERIFY( testAlias<NonTrivialEmpty>() );
+#endif
+}
diff --git a/libstdc++-v3/testsuite/20_util/variant/87619.cc b/libstdc++-v3/testsuite/20_util/variant/87619.cc
index d988925..ac7dd46 100644
--- a/libstdc++-v3/testsuite/20_util/variant/87619.cc
+++ b/libstdc++-v3/testsuite/20_util/variant/87619.cc
@@ -16,6 +16,7 @@
// <http://www.gnu.org/licenses/>.
// { dg-do compile { target c++17 } }
+// { dg-options "-ftemplate-depth=270" }
#include <variant>
#include <utility>
@@ -23,6 +24,7 @@
template<std::size_t I>
struct S {
+ ~S() {}
};
template <std::size_t... Is>
diff --git a/libstdc++-v3/testsuite/20_util/weak_ptr/cons/virtual_bases.cc b/libstdc++-v3/testsuite/20_util/weak_ptr/cons/virtual_bases.cc
new file mode 100644
index 0000000..ac3e4bc
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/weak_ptr/cons/virtual_bases.cc
@@ -0,0 +1,80 @@
+// { dg-do run { target c++11 } }
+
+#include <memory>
+#include <testsuite_hooks.h>
+
+struct BaseBase { virtual ~BaseBase() = default; };
+struct Base : BaseBase { virtual ~Base() = default; };
+struct Derived1 : Base { virtual ~Derived1() = default; };
+struct Derived2 : virtual Base { virtual ~Derived2() = default; };
+struct Derived3 : virtual Base { virtual ~Derived3() = default; };
+struct Derived4 : Derived2, Derived3 { virtual ~Derived4() = default; };
+struct Derived5 : Derived4 { virtual ~Derived5() = default; };
+
+template<typename T>
+void test01()
+{
+ std::shared_ptr<T> ptr(new T);
+ VERIFY(ptr);
+
+ std::weak_ptr<T> wptr1 = ptr;
+ VERIFY(wptr1.lock());
+
+ std::weak_ptr<Base> wptr2 = ptr;
+ VERIFY(wptr2.lock());
+
+ std::weak_ptr<Base> wptr3 = wptr1;
+ VERIFY(wptr3.lock());
+
+ std::weak_ptr<BaseBase> wptr4 = ptr;
+ VERIFY(wptr4.lock());
+
+ std::weak_ptr<BaseBase> wptr5 = std::move(wptr1);
+ VERIFY(wptr5.lock());
+
+ ptr.reset();
+
+ VERIFY(!wptr1.lock());
+ VERIFY(!wptr2.lock());
+ VERIFY(!wptr3.lock());
+ VERIFY(!wptr4.lock());
+ VERIFY(!wptr5.lock());
+}
+
+template<typename T>
+void test02()
+{
+ std::shared_ptr<T> ptr(new T);
+ VERIFY(ptr);
+
+ std::weak_ptr<T> wptr1 = ptr;
+ VERIFY(wptr1.lock());
+
+ std::weak_ptr<Base> wptr2 = ptr;
+ VERIFY(wptr2.lock());
+
+ ptr.reset();
+
+ std::weak_ptr<Base> wptr3 = wptr1;
+ std::weak_ptr<BaseBase> wptr4 = wptr1;
+ std::weak_ptr<BaseBase> wptr5 = std::move(wptr1);
+
+ VERIFY(!wptr1.lock());
+ VERIFY(!wptr2.lock());
+ VERIFY(!wptr3.lock());
+ VERIFY(!wptr4.lock());
+ VERIFY(!wptr5.lock());
+}
+
+int main()
+{
+ test01<Derived1>();
+ test01<Derived2>();
+ test01<Derived4>();
+ test01<Derived5>();
+
+ test02<Derived1>();
+ test02<Derived2>();
+ test02<Derived4>();
+ test02<Derived5>();
+}
diff --git a/libstdc++-v3/testsuite/20_util/weak_ptr/observers/owner_equal.cc b/libstdc++-v3/testsuite/20_util/weak_ptr/observers/owner_equal.cc
new file mode 100644
index 0000000..0217a6e
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/weak_ptr/observers/owner_equal.cc
@@ -0,0 +1,52 @@
+// { dg-do run { target c++26 } }
+// { dg-require-effective-target hosted }
+
+// N5008 20.3.2.3.6 weak_ptr observers [util.smartptr.weak.obs]
+
+#include <memory>
+#include <testsuite_hooks.h>
+
+struct A { };
+struct B { };
+
+void
+test01()
+{
+ // test empty weak_ptr owners compare equivalent
+ std::weak_ptr<A> p1;
+ std::weak_ptr<B> p2;
+ VERIFY( p1.owner_equal(p2) && p2.owner_equal(p1) );
+
+ std::shared_ptr<B> p3;
+ VERIFY( p1.owner_equal(p3) && p3.owner_equal(p1) );
+
+ static_assert( noexcept(p1.owner_equal(p1)) );
+ static_assert( noexcept(p1.owner_equal(p2)) );
+ static_assert( noexcept(p1.owner_equal(p3)) );
+ static_assert( noexcept(p2.owner_equal(p1)) );
+}
+
+
+void
+test02()
+{
+ std::shared_ptr<A> a0;
+ std::weak_ptr<A> w0(a0);
+
+ std::shared_ptr<A> a1(new A);
+ std::weak_ptr<A> w1(a1);
+ VERIFY( a1.owner_equal(w1) && w1.owner_equal(a1) );
+ VERIFY( !w1.owner_equal(w0) && !w0.owner_equal(w1) );
+ VERIFY( !w1.owner_equal(a0) && !a0.owner_equal(w1) );
+
+ std::shared_ptr<B> b1(new B);
+ VERIFY( !w1.owner_equal(b1) && !b1.owner_equal(w1) );
+}
+
+int
+main()
+{
+ test01();
+ test02();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/20_util/weak_ptr/observers/owner_hash.cc b/libstdc++-v3/testsuite/20_util/weak_ptr/observers/owner_hash.cc
new file mode 100644
index 0000000..148a93b
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/weak_ptr/observers/owner_hash.cc
@@ -0,0 +1,50 @@
+// { dg-do run { target c++26 } }
+// { dg-require-effective-target hosted }
+
+// N5008 20.3.2.3.6 weak_ptr observers [util.smartptr.weak.obs]
+
+#include <memory>
+#include <testsuite_hooks.h>
+
+struct A { };
+struct B { };
+
+void
+test01()
+{
+ // test empty weak_ptr hashes compare equivalent
+ std::weak_ptr<A> p1;
+ std::weak_ptr<B> p2;
+ VERIFY( p1.owner_hash() == p2.owner_hash() );
+
+ std::shared_ptr<B> p3;
+ VERIFY( p1.owner_hash() == p3.owner_hash() );
+
+ static_assert( noexcept(p1.owner_hash()) );
+ static_assert( noexcept(p2.owner_hash()) );
+}
+
+
+void
+test02()
+{
+ std::shared_ptr<A> a0;
+ std::weak_ptr<A> w0(a0);
+
+ std::shared_ptr<A> a1(new A);
+ std::weak_ptr<A> w1(a1);
+ VERIFY( a1.owner_hash() == w1.owner_hash() );
+ VERIFY( w1.owner_hash() != w0.owner_hash() );
+ VERIFY( w1.owner_hash() != a0.owner_hash() );
+
+ std::shared_ptr<B> b1(new B);
+ VERIFY( w1.owner_hash() != b1.owner_hash() );
+}
+
+int
+main()
+{
+ test01();
+ test02();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/20_util/weak_ptr/pr118757.cc b/libstdc++-v3/testsuite/20_util/weak_ptr/pr118757.cc
new file mode 100644
index 0000000..77757f3
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/weak_ptr/pr118757.cc
@@ -0,0 +1,31 @@
+// { dg-do run { target c++20 } }
+// { dg-additional-options "-pthread" { target pthread } }
+// { dg-require-gthreads "" }
+// { dg-require-effective-target hosted }
+
+#include <memory>
+#include <chrono>
+#include <thread>
+#include <barrier>
+
+std::shared_ptr<int> s = std::make_shared<int>(42);
+std::weak_ptr<int> q = s;
+std::atomic<std::weak_ptr<int>> p = q;
+
+std::barrier bar(2);
+
+void signaller()
+{
+ std::this_thread::sleep_for(std::chrono::seconds(1));
+ p.store(std::shared_ptr<int>(s, nullptr));
+ p.notify_one();
+ bar.arrive_and_wait();
+}
+
+int main(int, char**)
+{
+ std::thread thr(signaller);
+ p.wait(q);
+ bar.arrive_and_wait();
+ thr.join();
+}
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/from_range.cc b/libstdc++-v3/testsuite/21_strings/basic_string/cons/from_range.cc
index 6331050..df9e4c3 100644
--- a/libstdc++-v3/testsuite/21_strings/basic_string/cons/from_range.cc
+++ b/libstdc++-v3/testsuite/21_strings/basic_string/cons/from_range.cc
@@ -73,16 +73,19 @@ do_test(Alloc alloc)
}
template<typename Range>
-void
+constexpr 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));
+
+ if not consteval {
+ do_test<Range>(__gnu_test::uneq_allocator<char>(42));
+ do_test<Range>(__gnu_test::uneq_allocator<wchar_t>(42));
+ }
}
-bool
+constexpr bool
test_ranges()
{
using namespace __gnu_test;
@@ -101,9 +104,9 @@ test_ranges()
// Not lvalue-convertible to char
struct C {
- C(char v) : val(v) { }
- operator char() && { return val; }
- bool operator==(char b) const { return b == val; }
+ constexpr C(char v) : val(v) { }
+ constexpr operator char() && { return val; }
+ constexpr bool operator==(char b) const { return b == val; }
char val;
};
using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>;
@@ -112,18 +115,10 @@ test_ranges()
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() );
+#if _GLIBCXX_USE_CXX11_ABI
+ static_assert( test_ranges() );
+#endif // _GLIBCXX_USE_CXX11_ABI
}
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
index 6c0bc0c..984db36 100644
--- 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
@@ -49,7 +49,7 @@ do_test()
}
template<typename Range>
-void
+constexpr void
do_test_a()
{
do_test<Range, std::allocator<char>>();
@@ -58,7 +58,7 @@ do_test_a()
do_test<Range, __gnu_test::SimpleAllocator<wchar_t>>();
}
-bool
+constexpr bool
test_ranges()
{
using namespace __gnu_test;
@@ -77,9 +77,9 @@ test_ranges()
// Not lvalue-convertible to char
struct C {
- C(char v) : val(v) { }
- operator char() && { return val; }
- bool operator==(char b) const { return b == val; }
+ constexpr C(char v) : val(v) { }
+ constexpr operator char() && { return val; }
+ constexpr bool operator==(char b) const { return b == val; }
char val;
};
using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>;
@@ -107,19 +107,11 @@ test_overlapping()
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() );
+#if _GLIBCXX_USE_CXX11_ABI
+ static_assert( test_ranges() );
+#endif // _GLIBCXX_USE_CXX11_ABI
}
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
index 310c8bc..aa1b329 100644
--- 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
@@ -41,7 +41,7 @@ do_test()
}
template<typename Range>
-void
+constexpr void
do_test_a()
{
do_test<Range, std::allocator<char>>();
@@ -50,7 +50,7 @@ do_test_a()
do_test<Range, __gnu_test::SimpleAllocator<wchar_t>>();
}
-bool
+constexpr bool
test_ranges()
{
using namespace __gnu_test;
@@ -69,9 +69,9 @@ test_ranges()
// Not lvalue-convertible to char
struct C {
- C(char v) : val(v) { }
- operator char() && { return val; }
- bool operator==(char b) const { return b == val; }
+ constexpr C(char v) : val(v) { }
+ constexpr operator char() && { return val; }
+ constexpr bool operator==(char b) const { return b == val; }
char val;
};
using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>;
@@ -98,19 +98,11 @@ test_overlapping()
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() );
+#if _GLIBCXX_USE_CXX11_ABI
+ static_assert( test_ranges() );
+#endif // _GLIBCXX_USE_CXX11_ABI
}
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
index 4fead32..c026fd4 100644
--- 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
@@ -54,7 +54,7 @@ do_test()
}
template<typename Range>
-void
+constexpr void
do_test_a()
{
do_test<Range, std::allocator<char>>();
@@ -63,7 +63,7 @@ do_test_a()
do_test<Range, __gnu_test::SimpleAllocator<wchar_t>>();
}
-bool
+constexpr bool
test_ranges()
{
using namespace __gnu_test;
@@ -82,9 +82,9 @@ test_ranges()
// Not lvalue-convertible to char
struct C {
- C(char v) : val(v) { }
- operator char() && { return val; }
- bool operator==(char b) const { return b == val; }
+ constexpr C(char v) : val(v) { }
+ constexpr operator char() && { return val; }
+ constexpr bool operator==(char b) const { return b == val; }
char val;
};
using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>;
@@ -112,19 +112,11 @@ test_overlapping()
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() );
+#if _GLIBCXX_USE_CXX11_ABI
+ static_assert( test_ranges() );
+#endif // _GLIBCXX_USE_CXX11_ABI
}
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
index 9acf11a..4c6bba5 100644
--- 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
@@ -54,7 +54,7 @@ do_test()
}
template<typename Range>
-void
+constexpr void
do_test_a()
{
do_test<Range, std::allocator<char>>();
@@ -63,7 +63,7 @@ do_test_a()
do_test<Range, __gnu_test::SimpleAllocator<wchar_t>>();
}
-bool
+constexpr bool
test_ranges()
{
using namespace __gnu_test;
@@ -82,9 +82,9 @@ test_ranges()
// Not lvalue-convertible to char
struct C {
- C(char v) : val(v) { }
- operator char() && { return val; }
- bool operator==(char b) const { return b == val; }
+ constexpr C(char v) : val(v) { }
+ constexpr operator char() && { return val; }
+ constexpr bool operator==(char b) const { return b == val; }
char val;
};
using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>;
@@ -115,19 +115,11 @@ test_overlapping()
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() );
+#if _GLIBCXX_USE_CXX11_ABI
+ static_assert( test_ranges() );
+#endif // _GLIBCXX_USE_CXX11_ABI
}
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/stoi.cc b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/stoi.cc
index 9fc143c..4d2a8ba 100644
--- a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/stoi.cc
+++ b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/stoi.cc
@@ -86,7 +86,7 @@ test01()
}
VERIFY( test );
VERIFY( i1 == 7 );
- VERIFY( idx1 = 1 );
+ VERIFY( idx1 == 1 );
try
{
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/stol.cc b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/stol.cc
index 85d5e6d..55e39dd 100644
--- a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/stol.cc
+++ b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/stol.cc
@@ -86,7 +86,7 @@ test01()
}
VERIFY( test );
VERIFY( l1 == 7 );
- VERIFY( idx1 = 1 );
+ VERIFY( idx1 == 1 );
try
{
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/21_strings/basic_string/numeric_conversions/char/stoll.cc b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/stoll.cc
index a698bae..5b23d6c 100644
--- a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/stoll.cc
+++ b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/stoll.cc
@@ -87,7 +87,7 @@ test01()
}
VERIFY( test );
VERIFY( ll1 == 7 );
- VERIFY( idx1 = 1 );
+ VERIFY( idx1 == 1 );
try
{
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/stoul.cc b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/stoul.cc
index 47c20ce..00afc94 100644
--- a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/stoul.cc
+++ b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/stoul.cc
@@ -86,7 +86,7 @@ test01()
}
VERIFY( test );
VERIFY( ul1 == 7 );
- VERIFY( idx1 = 1 );
+ VERIFY( idx1 == 1 );
try
{
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/stoull.cc b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/stoull.cc
index ad81b67..f44eb1d 100644
--- a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/stoull.cc
+++ b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/stoull.cc
@@ -87,7 +87,7 @@ test01()
}
VERIFY( test );
VERIFY( ull1 == 7 );
- VERIFY( idx1 = 1 );
+ VERIFY( idx1 == 1 );
try
{
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/stoi.cc b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/stoi.cc
index 88e1da7..1aec77f 100644
--- a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/stoi.cc
+++ b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/stoi.cc
@@ -88,7 +88,7 @@ test01()
}
VERIFY( test );
VERIFY( i1 == 7 );
- VERIFY( idx1 = 1 );
+ VERIFY( idx1 == 1 );
try
{
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/stol.cc b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/stol.cc
index 98388f9..41e9d66 100644
--- a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/stol.cc
+++ b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/stol.cc
@@ -88,7 +88,7 @@ test01()
}
VERIFY( test );
VERIFY( l1 == 7 );
- VERIFY( idx1 = 1 );
+ VERIFY( idx1 == 1 );
try
{
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/stoll.cc b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/stoll.cc
index d7a49f5..5c7a25b 100644
--- a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/stoll.cc
+++ b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/stoll.cc
@@ -88,7 +88,7 @@ test01()
}
VERIFY( test );
VERIFY( ll1 == 7 );
- VERIFY( idx1 = 1 );
+ VERIFY( idx1 == 1 );
try
{
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/stoul.cc b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/stoul.cc
index b553796..d33289a 100644
--- a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/stoul.cc
+++ b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/stoul.cc
@@ -88,7 +88,7 @@ test01()
}
VERIFY( test );
VERIFY( ul1 == 7 );
- VERIFY( idx1 = 1 );
+ VERIFY( idx1 == 1 );
try
{
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/stoull.cc b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/stoull.cc
index 503101f..67c9639 100644
--- a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/stoull.cc
+++ b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/stoull.cc
@@ -88,7 +88,7 @@ test01()
}
VERIFY( test );
VERIFY( ull1 == 7 );
- VERIFY( idx1 = 1 );
+ VERIFY( idx1 == 1 );
try
{
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/operations/subview/char.cc b/libstdc++-v3/testsuite/21_strings/basic_string/operations/subview/char.cc
new file mode 100644
index 0000000..c384948
--- /dev/null
+++ b/libstdc++-v3/testsuite/21_strings/basic_string/operations/subview/char.cc
@@ -0,0 +1,46 @@
+// { dg-do run { target c++26 } }
+
+#include <stdexcept>
+#include <string>
+#include <string_view>
+#include <testsuite_hooks.h>
+
+void test01(void) {
+ typedef std::string::size_type csize_type;
+ typedef std::string::const_reference cref;
+ typedef std::string::reference ref;
+ csize_type csz01;
+
+ const char str_lit01[] = "rockaway, pacifica";
+ const std::string str01(str_lit01);
+ std::string_view str02;
+
+ csz01 = str01.size();
+ str02 = str01.subview(0, 1);
+ VERIFY(str02 == "r");
+ str02 = str01.subview(10);
+ VERIFY(str02 == "pacifica");
+
+ try {
+ str02 = str01.subview(csz01 + 1);
+ VERIFY(false);
+ } catch (std::out_of_range &fail) {
+ VERIFY(true);
+ } catch (...) {
+ VERIFY(false);
+ }
+
+ try {
+ str02 = str01.subview(csz01);
+ VERIFY(str02.size() == 0);
+ } catch (std::out_of_range &fail) {
+ VERIFY(false);
+ } catch (...) {
+ VERIFY(false);
+ }
+}
+
+int main() {
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/operations/subview/wchar_t.cc b/libstdc++-v3/testsuite/21_strings/basic_string/operations/subview/wchar_t.cc
new file mode 100644
index 0000000..3b8e6a8
--- /dev/null
+++ b/libstdc++-v3/testsuite/21_strings/basic_string/operations/subview/wchar_t.cc
@@ -0,0 +1,46 @@
+// { dg-do run { target c++26 } }
+
+#include <stdexcept>
+#include <string>
+#include <string_view>
+#include <testsuite_hooks.h>
+
+void test01(void) {
+ typedef std::wstring::size_type csize_type;
+ typedef std::wstring::const_reference cref;
+ typedef std::wstring::reference ref;
+ csize_type csz01;
+
+ const wchar_t str_lit01[] = L"rockaway, pacifica";
+ const std::wstring str01(str_lit01);
+ std::wstring_view str02;
+
+ csz01 = str01.size();
+ str02 = str01.subview(0, 1);
+ VERIFY(str02 == L"r");
+ str02 = str01.subview(10);
+ VERIFY(str02 == L"pacifica");
+
+ try {
+ str02 = str01.subview(csz01 + 1);
+ VERIFY(false);
+ } catch (std::out_of_range &fail) {
+ VERIFY(true);
+ } catch (...) {
+ VERIFY(false);
+ }
+
+ try {
+ str02 = str01.subview(csz01);
+ VERIFY(str02.size() == 0);
+ } catch (std::out_of_range &fail) {
+ VERIFY(false);
+ } catch (...) {
+ VERIFY(false);
+ }
+}
+
+int main() {
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string_view/operations/subview/char.cc b/libstdc++-v3/testsuite/21_strings/basic_string_view/operations/subview/char.cc
new file mode 100644
index 0000000..d6b66e6
--- /dev/null
+++ b/libstdc++-v3/testsuite/21_strings/basic_string_view/operations/subview/char.cc
@@ -0,0 +1,51 @@
+// { dg-do run { target c++26 } }
+
+#include <string_view>
+#include <testsuite_hooks.h>
+
+#if __STDC_HOSTED__
+#include <stdexcept>
+#endif
+
+void test01() {
+ typedef std::string_view::size_type csize_type;
+ typedef std::string_view::const_reference cref;
+ typedef std::string_view::reference ref;
+ csize_type csz01;
+
+ const char str_lit01[] = "rockaway, pacifica";
+ const std::string_view str01(str_lit01);
+ std::string_view str02;
+
+ csz01 = str01.size();
+ str02 = str01.subview(0, 1);
+ VERIFY(str02 == "r");
+ str02 = str01.subview(10);
+ VERIFY(str02 == "pacifica");
+
+#if __STDC_HOSTED__
+ try {
+ str02 = str01.subview(csz01 + 1);
+ VERIFY(false);
+ } catch (std::out_of_range &fail) {
+ VERIFY(true);
+ } catch (...) {
+ VERIFY(false);
+ }
+
+ try {
+ str02 = str01.subview(csz01);
+ VERIFY(str02.size() == 0);
+ VERIFY(str02.begin() == str01.end());
+ VERIFY(true);
+ } catch (...) {
+ VERIFY(false);
+ }
+#endif // HOSTED
+}
+
+int main() {
+ test01();
+
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string_view/operations/subview/wchar_t.cc b/libstdc++-v3/testsuite/21_strings/basic_string_view/operations/subview/wchar_t.cc
new file mode 100644
index 0000000..86b5095
--- /dev/null
+++ b/libstdc++-v3/testsuite/21_strings/basic_string_view/operations/subview/wchar_t.cc
@@ -0,0 +1,51 @@
+// { dg-do run { target c++26 } }
+
+#include <string_view>
+#include <testsuite_hooks.h>
+
+#if __STDC_HOSTED__
+#include <stdexcept>
+#endif
+
+void test01() {
+ typedef std::wstring_view::size_type csize_type;
+ typedef std::wstring_view::const_reference cref;
+ typedef std::wstring_view::reference ref;
+ csize_type csz01;
+
+ const wchar_t str_lit01[] = L"rockaway, pacifica";
+ const std::wstring_view str01(str_lit01);
+ std::wstring_view str02;
+
+ csz01 = str01.size();
+ str02 = str01.subview(0, 1);
+ VERIFY(str02 == L"r");
+ str02 = str01.subview(10);
+ VERIFY(str02 == L"pacifica");
+
+#if __STDC_HOSTED__
+ try {
+ str02 = str01.subview(csz01 + 1);
+ VERIFY(false);
+ } catch (std::out_of_range &fail) {
+ VERIFY(true);
+ } catch (...) {
+ VERIFY(false);
+ }
+
+ try {
+ str02 = str01.subview(csz01);
+ VERIFY(str02.size() == 0);
+ VERIFY(str02.begin() == str01.end());
+ VERIFY(true);
+ } catch (...) {
+ VERIFY(false);
+ }
+#endif // HOSTED
+}
+
+int main() {
+ test01();
+
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/22_locale/codecvt/codecvt_unicode.h b/libstdc++-v3/testsuite/22_locale/codecvt/codecvt_unicode.h
index 9fe9ac8..2ba23bf 100644
--- a/libstdc++-v3/testsuite/22_locale/codecvt/codecvt_unicode.h
+++ b/libstdc++-v3/testsuite/22_locale/codecvt/codecvt_unicode.h
@@ -1439,7 +1439,7 @@ ucs2_to_utf8_out_error (const std::codecvt<InternT, ExternT, mbstate_t> &cvt)
// make the trailing surrogate a BMP char
{5, 10, 3, 6, u'z', 4},
- // don't replace anything in the test cases bellow, just show the surrogate
+ // don't replace anything in the test cases below, just show the surrogate
// pair (fourth CP) fully or partially
{5, 10, 3, 6, u'b', 0},
{5, 7, 3, 6, u'b', 0}, // no space for fourth CP
@@ -2072,7 +2072,7 @@ utf16_to_ucs2_in_error (const std::codecvt<InternT, char, mbstate_t> &cvt,
// make the trailing surrogate a BMP char
{10, 5, 6, 3, u'z', 4},
- // don't replace anything in the test cases bellow, just show the surrogate
+ // don't replace anything in the test cases below, just show the surrogate
// pair (fourth CP) fully or partially (just the first surrogate)
{10, 5, 6, 3, u'b', 0},
{8, 5, 6, 3, u'b', 0},
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/22_locale/time_get/get/char/3.cc b/libstdc++-v3/testsuite/22_locale/time_get/get/char/3.cc
index 48a5f12..49bcd2a 100644
--- a/libstdc++-v3/testsuite/22_locale/time_get/get/char/3.cc
+++ b/libstdc++-v3/testsuite/22_locale/time_get/get/char/3.cc
@@ -226,7 +226,7 @@ test01()
format = "%e";
ret = tget.get(iter(iss), end, iss, err, &time,
format.data(), format.data()+format.size());
- VERIFY( err == ios_base::failbit|ios_base::eofbit );
+ VERIFY( err == (ios_base::failbit|ios_base::eofbit) );
VERIFY( ret == end );
iss.str("35");
diff --git a/libstdc++-v3/testsuite/22_locale/time_get/get/wchar_t/3.cc b/libstdc++-v3/testsuite/22_locale/time_get/get/wchar_t/3.cc
index b7eb5bc..4b1b6e4 100644
--- a/libstdc++-v3/testsuite/22_locale/time_get/get/wchar_t/3.cc
+++ b/libstdc++-v3/testsuite/22_locale/time_get/get/wchar_t/3.cc
@@ -226,7 +226,7 @@ test01()
format = L"%e";
ret = tget.get(iter(iss), end, iss, err, &time,
format.data(), format.data()+format.size());
- VERIFY( err == ios_base::failbit|ios_base::eofbit );
+ VERIFY( err == (ios_base::failbit|ios_base::eofbit) );
VERIFY( ret == end );
iss.str(L"35");
diff --git a/libstdc++-v3/testsuite/23_containers/array/creation/3_neg.cc b/libstdc++-v3/testsuite/23_containers/array/creation/3_neg.cc
index ae06302..1335228 100644
--- a/libstdc++-v3/testsuite/23_containers/array/creation/3_neg.cc
+++ b/libstdc++-v3/testsuite/23_containers/array/creation/3_neg.cc
@@ -54,3 +54,5 @@ test03()
}
// { dg-prune-output "static assertion failed" }
+// { dg-prune-output "use of deleted function" }
+// { dg-prune-output "could not convert" }
diff --git a/libstdc++-v3/testsuite/23_containers/array/tuple_interface/get_neg.cc b/libstdc++-v3/testsuite/23_containers/array/tuple_interface/get_neg.cc
index 25511e7..e1e9ce9b 100644
--- a/libstdc++-v3/testsuite/23_containers/array/tuple_interface/get_neg.cc
+++ b/libstdc++-v3/testsuite/23_containers/array/tuple_interface/get_neg.cc
@@ -26,6 +26,6 @@ int n1 = std::get<1>(a);
int n2 = std::get<1>(std::move(a));
int n3 = std::get<1>(ca);
-// { dg-error "static assertion failed" "" { target *-*-* } 394 }
-// { dg-error "static assertion failed" "" { target *-*-* } 403 }
-// { dg-error "static assertion failed" "" { target *-*-* } 412 }
+// { dg-error "static assertion failed" "" { target *-*-* } 396 }
+// { dg-error "static assertion failed" "" { target *-*-* } 405 }
+// { dg-error "static assertion failed" "" { target *-*-* } 414 }
diff --git a/libstdc++-v3/testsuite/23_containers/bitset/lwg4294.cc b/libstdc++-v3/testsuite/23_containers/bitset/lwg4294.cc
new file mode 100644
index 0000000..977555f
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/bitset/lwg4294.cc
@@ -0,0 +1,11 @@
+// { dg-do compile { target c++11 } }
+
+// Bug 121046
+// Asking is_constructible_v<std::bitset<1>, NonTrivial*> is ill-formed
+
+// LWG 4294. bitset(const CharT*) constructor needs to be constrained
+
+#include <bitset>
+struct NonTrivial { ~NonTrivial() { } };
+static_assert( ! std::is_constructible<std::bitset<1>, NonTrivial*>::value,
+ "std::bitset cannot be constructed from this pointer" );
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/debug/erase.cc b/libstdc++-v3/testsuite/23_containers/deque/debug/erase.cc
new file mode 100644
index 0000000..d8c36bb
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/deque/debug/erase.cc
@@ -0,0 +1,27 @@
+// { dg-do run { target c++20 } }
+// { dg-require-debug-mode "" }
+
+#include <deque>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+ std::deque<int> d;
+
+ for (int i = 0; i != 10; ++i)
+ d.push_back(i);
+
+ auto before = d.begin() + 4;
+ auto last = d.end() - 1;
+
+ VERIFY( std::erase(d, 6) == 1 );
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(last._M_singular());
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/deque/debug/invalidation/erase.cc b/libstdc++-v3/testsuite/23_containers/deque/debug/invalidation/erase.cc
new file mode 100644
index 0000000..c18a5ff
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/deque/debug/invalidation/erase.cc
@@ -0,0 +1,28 @@
+// { dg-do run { target c++20 } }
+
+#include <debug/deque>
+#include <testsuite_hooks.h>
+
+using __gnu_debug::deque;
+
+void test01()
+{
+ deque<int> d;
+
+ for (int i = 0; i != 10; ++i)
+ d.push_back(i);
+
+ auto before = d.begin() + 4;
+ auto last = d.end() -1;
+
+ VERIFY( std::erase(d, 6) == 1 );
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(last._M_singular());
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/deque/modifiers/emplace/118087.cc b/libstdc++-v3/testsuite/23_containers/deque/modifiers/emplace/118087.cc
new file mode 100644
index 0000000..3606e88
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/deque/modifiers/emplace/118087.cc
@@ -0,0 +1,43 @@
+// { dg-do run { target c++11 } }
+
+// PR libstdc++/118087
+// std::deque::emplace does not do uses-allocator construction
+
+#include <deque>
+#include <scoped_allocator>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+template<typename T>
+using Alloc = __gnu_test::propagating_allocator<T, true>;
+
+struct X
+{
+ using allocator_type = Alloc<int>;
+ X() { }
+ X(const X&) { }
+ X(X&&) { }
+ X(const allocator_type& a) : alloc(a) { }
+ X(const X&, const allocator_type& a) : alloc(a) { }
+ X(X&&, const allocator_type& a) : alloc(a) { }
+
+ X& operator=(const X&) = default;
+
+ allocator_type alloc{-1};
+};
+
+int main()
+{
+ std::deque<X, std::scoped_allocator_adaptor<Alloc<X>>> d(2, Alloc<X>(50));
+ VERIFY(d[0].alloc.get_personality() == 50);
+ VERIFY(d[1].alloc.get_personality() == 50);
+
+ d.emplace(d.begin() + 1);
+ VERIFY(d[1].alloc.get_personality() == 50);
+
+ d.emplace_front();
+ VERIFY(d[0].alloc.get_personality() == 50);
+
+ d.emplace_back();
+ VERIFY(d[d.size() - 1].alloc.get_personality() == 50);
+}
diff --git a/libstdc++-v3/testsuite/23_containers/flat_map/1.cc b/libstdc++-v3/testsuite/23_containers/flat_map/1.cc
index d9d88c4..5bcda34 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,37 @@ 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;
+}
+
+void
+test09()
+{
+ // PR libstdc++/122921 - The value_type of flat_map's iterator should be
+ // pair<Key, T> instead of pair<const Key, T>
+ using type = std::flat_map<int, int>;
+ using value_type = std::ranges::range_value_t<type>;
+ using value_type = type::value_type;
+ using value_type = std::pair<int, int>;
+}
+
int
main()
{
@@ -253,4 +286,7 @@ main()
test04();
test05();
test06();
+ test07();
+ test08();
+ test09();
}
diff --git a/libstdc++-v3/testsuite/23_containers/flat_multimap/1.cc b/libstdc++-v3/testsuite/23_containers/flat_multimap/1.cc
index ff180bf..f143f3a 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,28 @@ 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}}) );
+}
+
+void
+test09()
+{
+ // PR libstdc++/122921 - The value_type of flat_map's iterator should be
+ // pair<Key, T> instead of pair<const Key, T>
+ using type = std::flat_multimap<int, int>;
+ using value_type = std::ranges::range_value_t<type>;
+ using value_type = type::value_type;
+ using value_type = std::pair<int, int>;
+}
+
int
main()
{
@@ -231,4 +255,6 @@ main()
test04();
test05();
test06();
+ test07();
+ test09();
}
diff --git a/libstdc++-v3/testsuite/23_containers/flat_multiset/1.cc b/libstdc++-v3/testsuite/23_containers/flat_multiset/1.cc
index 7d9a33c..63855e0 100644
--- a/libstdc++-v3/testsuite/23_containers/flat_multiset/1.cc
+++ b/libstdc++-v3/testsuite/23_containers/flat_multiset/1.cc
@@ -235,6 +235,16 @@ test08()
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()
{
@@ -247,4 +257,5 @@ main()
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 ed24fab..b1d9002 100644
--- a/libstdc++-v3/testsuite/23_containers/flat_set/1.cc
+++ b/libstdc++-v3/testsuite/23_containers/flat_set/1.cc
@@ -248,6 +248,16 @@ test08()
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()
{
@@ -260,4 +270,5 @@ main()
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/modifiers/122661.cc b/libstdc++-v3/testsuite/23_containers/forward_list/modifiers/122661.cc
new file mode 100644
index 0000000..41ac32c
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/forward_list/modifiers/122661.cc
@@ -0,0 +1,20 @@
+// { dg-do compile { target c++11 } }
+
+// Bug 122661 - Incorrect value category handling in forward_list::assign
+
+#include <forward_list>
+
+struct S
+{
+ S();
+ S& operator=(S const&) & = delete;
+ S& operator=(S const&) &&;
+};
+
+void
+test_pr122661()
+{
+ std::forward_list<S> fl;
+ S* iter = nullptr;
+ fl.assign(iter, iter);
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/access/capacity.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/access/capacity.cc
new file mode 100644
index 0000000..2797e20
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/access/capacity.cc
@@ -0,0 +1,51 @@
+// { dg-do run { target c++26 } }
+
+#include <inplace_vector>
+
+#include <span>
+#include <testsuite_hooks.h>
+
+template<size_t N, typename T>
+constexpr void
+test_reserve()
+{
+ std::inplace_vector<T, N> v;
+
+ static_assert(v.max_size() == N);
+ static_assert(v.capacity() == N);
+
+ // static methods
+ v.shrink_to_fit();
+ v.reserve(0);
+ v.reserve(N);
+
+#ifdef __cpp_exceptions
+#ifdef __cpp_lib_constexpr_exceptions
+#error remove the consteval check
+#endif
+ if consteval {
+ return;
+ }
+
+ try
+ {
+ v.reserve(N + 2);
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+#endif
+}
+
+int main()
+{
+ auto test_all = [] {
+ test_reserve<0, int>();
+ test_reserve<4, int>();
+ return true;
+ };
+
+ test_all();
+ static_assert(test_all());;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/access/elem.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/access/elem.cc
new file mode 100644
index 0000000..bc06aa0
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/access/elem.cc
@@ -0,0 +1,115 @@
+// { dg-do run { target c++26 } }
+
+#include <inplace_vector>
+
+#include <span>
+#include <stdexcept>
+#include <testsuite_hooks.h>
+#include <utility>
+
+template<size_t N, typename T>
+constexpr void
+test_out_of_capacity()
+{
+ std::inplace_vector<T, N> v;
+
+#ifdef __cpp_exceptions
+#ifdef __cpp_lib_constexpr_exceptions
+#error remove the consteval check
+#endif
+ if consteval {
+ return;
+ }
+
+ try
+ {
+ (void)v.at(N + 2);
+ VERIFY(false);
+ }
+ catch (std::out_of_range const&)
+ {
+ }
+
+ try
+ {
+ (void)as_const(v).at(N + 2);
+ VERIFY(false);
+ }
+ catch (std::out_of_range const&)
+ {
+ }
+#endif
+}
+
+
+template<bool Const, typename T, size_t N>
+using InplaceVector = std::conditional_t<Const,
+ const std::inplace_vector<T, N>,
+ std::inplace_vector<T, N>>;
+
+template<bool Const, typename T>
+constexpr void
+test_access()
+{
+ InplaceVector<Const, T, 10> v{1, 2, 3, 4, 5};
+
+ auto& e0a = v[0];
+ auto& e0b = v.at(0);
+ auto& e0c = v.front();
+ VERIFY( &e0a == &e0b );
+ VERIFY( &e0a == &e0c );
+ VERIFY( &e0a == &v.begin()[0] );
+ VERIFY( &e0a == &v.cbegin()[0] );
+ VERIFY( &e0a == v.data() );
+ VERIFY( e0a == T(1) );
+
+ auto& e3a = v[2];
+ auto& e3b = v.at(2);
+ VERIFY( &e3a == &e3b );
+ VERIFY( &e3a == &v.begin()[2] );
+ VERIFY( &e3a == &v.cbegin()[2] );
+ VERIFY( &e3a == v.data() + 2 );
+ VERIFY( e3a == T(3) );
+
+ auto& e4a = v[4];
+ auto& e4b = v.at(4);
+ auto& e4c = v.back();
+ VERIFY( &e4a == &e4b );
+ VERIFY( &e4a == &e4c );
+ VERIFY( &e4a == &v.begin()[4] );
+ VERIFY( &e4a == &v.cbegin()[4] );
+ VERIFY( &e4a == v.data() + 4 );
+ VERIFY( e4a == T(5) );
+
+#ifdef __cpp_exceptions
+#ifdef __cpp_lib_constexpr_exceptions
+#error remove the consteval check
+#endif
+ if consteval {
+ return;
+ }
+
+ try
+ {
+ (void)v.at(7);
+ VERIFY(false);
+ }
+ catch (std::out_of_range const&)
+ {
+ }
+#endif
+}
+
+int main()
+{
+ auto test_all = [] {
+ test_out_of_capacity<0, int>();
+ test_out_of_capacity<4, int>();
+ test_access<true, int>();
+ test_access<false, int>();
+ return true;
+ };
+
+ test_all();
+ static_assert(test_all());;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/access/elem_neg.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/access/elem_neg.cc
new file mode 100644
index 0000000..b2bff0d
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/access/elem_neg.cc
@@ -0,0 +1,65 @@
+// { dg-do compile { target c++26 } }
+
+#include <inplace_vector>
+
+template<bool Const, typename T, size_t N>
+using InplaceVector
+ = std::conditional_t<Const,
+ const std::inplace_vector<T, N>,
+ std::inplace_vector<T, N>>;
+
+template<bool Const, size_t N, typename T>
+constexpr bool
+test_front_on_empty()
+{
+ InplaceVector<Const, T, N> v;
+ (void)v.front(); // { dg-error "in 'constexpr' expansion of" }
+ return true;
+}
+
+template<bool Const, size_t N, typename T>
+constexpr bool
+test_back_on_empty()
+{
+ InplaceVector<Const, T, N> v;
+ (void)v.back(); // { dg-error "in 'constexpr' expansion of" }
+ return true;
+}
+
+template<bool Const, size_t N, typename T>
+constexpr bool
+test_out_of_capacity()
+{
+ InplaceVector<Const, T, N> v;
+ (void)v[N+2]; // { dg-error "in 'constexpr' expansion of" }
+ return true;
+}
+
+template<bool Const, typename T>
+constexpr bool
+test_out_of_size()
+{
+ InplaceVector<Const, T, 10> v{1, 2, 3, 4, 5};
+ (void)v[7]; // { dg-error "in 'constexpr' expansion of" }
+ return true;
+}
+
+static_assert(test_front_on_empty<false, 0, int>()); // { dg-error "in 'constexpr' expansion of" }
+static_assert(test_front_on_empty<false, 4, int>()); // { dg-error "in 'constexpr' expansion of" }
+static_assert(test_back_on_empty<false, 0, int>()); // { dg-error "in 'constexpr' expansion of" }
+static_assert(test_back_on_empty<false, 4, int>()); // { dg-error "in 'constexpr' expansion of" }
+static_assert(test_out_of_capacity<false, 0, int>()); // { dg-error "in 'constexpr' expansion of" }
+static_assert(test_out_of_capacity<false, 4, int>()); // { dg-error "in 'constexpr' expansion of" }
+static_assert(test_out_of_size<false, int>()); // { dg-error "in 'constexpr' expansion of" }
+
+static_assert(test_front_on_empty<true, 0, int>()); // { dg-error "in 'constexpr' expansion of" }
+static_assert(test_front_on_empty<true, 4, int>()); // { dg-error "in 'constexpr' expansion of" }
+static_assert(test_back_on_empty<true, 0, int>()); // { dg-error "in 'constexpr' expansion of" }
+static_assert(test_back_on_empty<true, 4, int>()); // { dg-error "in 'constexpr' expansion of" }
+static_assert(test_out_of_capacity<true, 0, int>()); // { dg-error "in 'constexpr' expansion of" }
+static_assert(test_out_of_capacity<true, 4, int>()); // { dg-error "in 'constexpr' expansion of" }
+static_assert(test_out_of_size<true, int>()); // { dg-error "in 'constexpr' expansion of" }
+
+// { dg-prune-output "non-constant condition for static assertion" }
+// { dg-prune-output "is not a constant expression" }
+// { dg-prune-output "call to non-'constexpr' function" }
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/cons/1.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/cons/1.cc
new file mode 100644
index 0000000..45685c2
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/cons/1.cc
@@ -0,0 +1,387 @@
+// { dg-do run { target c++26 } }
+
+#include <inplace_vector>
+#include <testsuite_hooks.h>
+
+struct X
+{
+ constexpr X() { } // not trivially default constructible
+};
+
+struct N
+{
+ constexpr N() noexcept { } // not trivially default constructible
+};
+
+struct D
+{
+ ~D() {} // not trivially destructible
+};
+
+struct U
+{
+ U() noexcept(false) = default; // lies about noexcept
+};
+
+// n5008 inplace.vector.overview says for inplace_vector<T, 0>
+// provides trivial copy/move/default constructor regardless of T
+struct Z
+{
+ constexpr Z(int) {}
+ Z() = delete;
+};
+
+static_assert(std::is_default_constructible_v<std::inplace_vector<int, 2>>);
+static_assert(std::is_default_constructible_v<std::inplace_vector<X, 2>>);
+static_assert(std::is_default_constructible_v<std::inplace_vector<N, 2>>);
+static_assert(std::is_default_constructible_v<std::inplace_vector<D, 2>>);
+static_assert(std::is_default_constructible_v<std::inplace_vector<U, 2>>);
+// The operators are not constrained, as for any other container
+static_assert(std::is_default_constructible_v<std::inplace_vector<Z, 2>>);
+
+static_assert(std::is_nothrow_default_constructible_v<std::inplace_vector<int, 2>>);
+static_assert(std::is_nothrow_default_constructible_v<std::inplace_vector<X, 2>>);
+static_assert(std::is_nothrow_default_constructible_v<std::inplace_vector<N, 2>>);
+static_assert(std::is_nothrow_default_constructible_v<std::inplace_vector<D, 2>>);
+static_assert(std::is_nothrow_default_constructible_v<std::inplace_vector<U, 2>>);
+
+// Needs to set size to zero, not trivial
+static_assert(!std::is_trivially_default_constructible_v<std::inplace_vector<int, 2>>);
+static_assert(!std::is_trivially_default_constructible_v<std::inplace_vector<X, 2>>);
+static_assert(!std::is_trivially_default_constructible_v<std::inplace_vector<N, 2>>);
+static_assert(!std::is_trivially_default_constructible_v<std::inplace_vector<D, 2>>);
+static_assert(!std::is_trivially_default_constructible_v<std::inplace_vector<U, 2>>);
+
+#if !_GLIBCXX_DEBUG
+static_assert(std::is_trivially_destructible_v<std::inplace_vector<int, 2>>);
+static_assert(std::is_trivially_destructible_v<std::inplace_vector<X, 2>>);
+static_assert(std::is_trivially_destructible_v<std::inplace_vector<N, 2>>);
+static_assert(!std::is_trivially_destructible_v<std::inplace_vector<D, 2>>);
+static_assert(std::is_trivially_destructible_v<std::inplace_vector<U, 2>>);
+#endif
+
+static_assert(std::is_nothrow_default_constructible_v<std::inplace_vector<int, 0>>);
+static_assert(std::is_nothrow_default_constructible_v<std::inplace_vector<X, 0>>);
+static_assert(std::is_nothrow_default_constructible_v<std::inplace_vector<N, 0>>);
+static_assert(std::is_nothrow_default_constructible_v<std::inplace_vector<D, 0>>);
+static_assert(std::is_nothrow_default_constructible_v<std::inplace_vector<U, 0>>);
+
+// Size is always zero, so trivial
+static_assert(std::is_trivially_default_constructible_v<std::inplace_vector<int, 0>>);
+static_assert(std::is_trivially_default_constructible_v<std::inplace_vector<X, 0>>);
+static_assert(std::is_trivially_default_constructible_v<std::inplace_vector<N, 0>>);
+static_assert(std::is_trivially_default_constructible_v<std::inplace_vector<D, 0>>);
+static_assert(std::is_trivially_default_constructible_v<std::inplace_vector<U, 0>>);
+static_assert(std::is_trivially_default_constructible_v<std::inplace_vector<Z, 0>>);
+
+static_assert(std::is_trivially_destructible_v<std::inplace_vector<int, 0>>);
+static_assert(std::is_trivially_destructible_v<std::inplace_vector<X, 0>>);
+static_assert(std::is_trivially_destructible_v<std::inplace_vector<N, 0>>);
+static_assert(std::is_trivially_destructible_v<std::inplace_vector<D, 0>>);
+static_assert(std::is_trivially_destructible_v<std::inplace_vector<U, 0>>);
+
+static_assert(std::is_empty_v<std::inplace_vector<int, 0>>);
+static_assert(std::is_empty_v<std::inplace_vector<X, 0>>);
+static_assert(std::is_empty_v<std::inplace_vector<N, 0>>);
+static_assert(std::is_empty_v<std::inplace_vector<D, 0>>);
+static_assert(std::is_empty_v<std::inplace_vector<U, 0>>);
+static_assert(std::is_empty_v<std::inplace_vector<Z, 0>>);
+
+constexpr void
+test_default()
+{
+ std::inplace_vector<int, 5> c;
+ VERIFY( c.size() == 0 );
+ VERIFY( c.capacity() == 5 );
+ VERIFY( c.empty() );
+ VERIFY( c.begin() == c.end() );
+
+ std::inplace_vector<int, 0> c0;
+ VERIFY( c0.size() == 0 );
+ VERIFY( c0.capacity() == 0 );
+ VERIFY( c0.empty() );
+ VERIFY( c0.begin() == c0.end() );
+
+ std::inplace_vector<Z, 0> z0;
+ VERIFY( z0.size() == 0 );
+ VERIFY( z0.capacity() == 0 );
+ VERIFY( z0.empty() );
+ VERIFY( z0.begin() == z0.end() );
+
+#ifdef __cpp_lib_constexpr_inplace_vector
+#error remove the consteval check
+#endif
+ if consteval {
+ return;
+ }
+
+ std::inplace_vector<X, 5> cx;
+ VERIFY( cx.size() == 0 );
+ VERIFY( cx.capacity() == 5 );
+ VERIFY( cx.empty() );
+ VERIFY( cx.begin() == cx.end() );
+
+ std::inplace_vector<X, 0> cx0;
+ VERIFY( cx0.size() == 0 );
+ VERIFY( cx0.capacity() == 0 );
+ VERIFY( cx0.empty() );
+ VERIFY( cx0.begin() == cx0.end() );
+}
+
+constexpr void
+test_n()
+{
+ std::inplace_vector<int, 5> c(2);
+ VERIFY( c.size() == 2 );
+ VERIFY( c.capacity() == 5 );
+ VERIFY( not c.empty() );
+ VERIFY( c.begin() + 2 == c.end() );
+ VERIFY( c[0] == 0 );
+ VERIFY( c[1] == 0 );
+
+ std::inplace_vector<int, 2> c2(2);
+ VERIFY( c2.size() == 2 );
+ VERIFY( c2.capacity() == 2 );
+ VERIFY( not c2.empty() );
+ VERIFY( c2.begin() + 2 == c2.end() );
+ VERIFY( c2[0] == 0 );
+ VERIFY( c2[1] == 0 );
+
+ std::inplace_vector<int, 0> c0(0);
+ VERIFY( c0.size() == 0 );
+ VERIFY( c0.capacity() == 0 );
+ VERIFY( c0.empty() );
+ VERIFY( c0.begin() == c0.end() );
+
+ std::inplace_vector<int, 2> c20(0);
+ VERIFY( c20.size() == 0 );
+ VERIFY( c20.capacity() == 2 );
+ VERIFY( c20.empty() );
+ VERIFY( c20.begin() == c20.end() );
+
+ std::inplace_vector<Z, 0> z0(0);
+ VERIFY( z0.size() == 0 );
+ VERIFY( z0.capacity() == 0 );
+ VERIFY( z0.empty() );
+ VERIFY( z0.begin() == z0.end() );
+
+#ifdef __cpp_exceptions
+#ifdef __cpp_lib_constexpr_exceptions
+#error remove the consteval check
+#endif
+ if not consteval {
+ try
+ {
+ std::inplace_vector<int, 2> ct(3);
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+
+ try
+ {
+ std::inplace_vector<int, 0> ct(1);
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+
+ }
+#endif
+
+#ifdef __cpp_lib_constexpr_inplace_vector
+#error remove the consteval check
+#endif
+ if consteval {
+ return;
+ }
+
+ std::inplace_vector<X, 5> cx(3);
+ VERIFY( cx.size() == 3 );
+ VERIFY( cx.capacity() == 5 );
+ VERIFY( not cx.empty() );
+ VERIFY( cx.begin() + 3 == cx.end() );
+ (void) cx[2];
+}
+
+constexpr void
+test_n_val()
+{
+ std::inplace_vector<int, 5> c(2, 99);
+ VERIFY( c.size() == 2 );
+ VERIFY( c.capacity() == 5 );
+ VERIFY( not c.empty() );
+ VERIFY( c.begin() + 2 == c.end() );
+ VERIFY( c[0] == 99 );
+ VERIFY( c[1] == 99 );
+
+ std::inplace_vector<int, 1> c1(1, 44);
+ VERIFY( c1.size() == 1 );
+ VERIFY( c1.capacity() == 1 );
+ VERIFY( not c1.empty() );
+ VERIFY( c1.begin() + 1 == c1.end() );
+ VERIFY( c1[0] == 44 );
+
+ std::inplace_vector<int, 0> c0(0, 33);
+ VERIFY( c0.size() == 0 );
+ VERIFY( c0.capacity() == 0 );
+ VERIFY( c0.empty() );
+ VERIFY( c0.begin() == c0.end() );
+
+ std::inplace_vector<int, 2> c20(0, 22);
+ VERIFY( c20.size() == 0 );
+ VERIFY( c20.capacity() == 2 );
+ VERIFY( c20.empty() );
+ VERIFY( c20.begin() == c20.end() );
+
+ std::inplace_vector<Z, 0> z0(0, 33);
+ VERIFY( z0.size() == 0 );
+ VERIFY( z0.capacity() == 0 );
+ VERIFY( z0.empty() );
+ VERIFY( z0.begin() == z0.end() );
+
+#ifdef __cpp_exceptions
+#ifdef __cpp_lib_constexpr_exceptions
+#error remove the consteval check
+#endif
+ if not consteval {
+ try
+ {
+ std::inplace_vector<int, 2> ct(3, 11);
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+
+ try
+ {
+ std::inplace_vector<int, 0> ct(2, 11);
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ }
+#endif
+
+#ifdef __cpp_lib_constexpr_inplace_vector
+#error remove the consteval check
+#endif
+ if consteval {
+ return;
+ }
+
+ std::inplace_vector<X, 5> cx(4);
+ VERIFY( cx.size() == 4 );
+ VERIFY( cx.capacity() == 5 );
+ VERIFY( not cx.empty() );
+ VERIFY( cx.begin() + 4 == cx.end() );
+ (void) cx[3];
+}
+
+constexpr void
+test_initializer_list()
+{
+ std::inplace_vector<int, 5> c{22, 33};
+ VERIFY( c.size() == 2 );
+ VERIFY( c.capacity() == 5 );
+ VERIFY( not c.empty() );
+ VERIFY( c.begin() + 2 == c.end() );
+ VERIFY( c[0] == 22 );
+ VERIFY( c[1] == 33 );
+
+ std::inplace_vector<int, 1> c1{44};
+ VERIFY( c1.size() == 1 );
+ VERIFY( c1.capacity() == 1 );
+ VERIFY( not c1.empty() );
+ VERIFY( c1.begin() + 1 == c1.end() );
+ VERIFY( c1[0] == 44 );
+
+ std::inplace_vector<int, 0> c0({});
+ VERIFY( c0.size() == 0 );
+ VERIFY( c0.capacity() == 0 );
+ VERIFY( c0.empty() );
+ VERIFY( c0.begin() == c0.end() );
+
+ std::inplace_vector<int, 2> c20({});
+ VERIFY( c20.size() == 0 );
+ VERIFY( c20.capacity() == 2 );
+ VERIFY( c20.empty() );
+ VERIFY( c20.begin() == c20.end() );
+
+ std::inplace_vector<Z, 0> z0({});
+ VERIFY( z0.size() == 0 );
+ VERIFY( z0.capacity() == 0 );
+ VERIFY( z0.empty() );
+ VERIFY( z0.begin() == z0.end() );
+
+#ifdef __cpp_exceptions
+#ifdef __cpp_lib_constexpr_exceptions
+#error remove the consteval check
+#endif
+ if not consteval {
+ try
+ {
+ std::inplace_vector<int, 2> ct{11, 22, 33};
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+
+ try
+ {
+ std::inplace_vector<int, 0> ct{11, 22};
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ }
+#endif
+
+#ifdef __cpp_lib_constexpr_inplace_vector
+#error remove the consteval check
+#endif
+ if consteval {
+ return;
+ }
+
+ std::inplace_vector<X, 5> cx{X(), X(), X(), X()};
+ VERIFY( cx.size() == 4 );
+ VERIFY( cx.capacity() == 5 );
+ VERIFY( not cx.empty() );
+ VERIFY( cx.begin() + 4 == cx.end() );
+ (void) cx[3];
+}
+
+constexpr std::inplace_vector<int, 0> e0;
+constexpr std::inplace_vector<X, 0> e1;
+constexpr std::inplace_vector<Z, 0> e2;
+
+constexpr std::inplace_vector<int, 5> g1;
+constexpr std::inplace_vector<int, 5> g2(2, 100);
+constexpr std::inplace_vector<int, 5> g3 = g2;
+constexpr std::inplace_vector<int, 5> g4{1, 2, 3};
+constexpr std::inplace_vector<int, 5> g5 = [] {
+ std::inplace_vector<int, 5> res;
+ res = g3;
+ return res;
+}();
+
+int main()
+{
+ auto tests = [] {
+ test_default();
+ test_n();
+ test_n_val();
+ test_initializer_list();
+ return true;
+ };
+
+ tests();
+ constexpr bool _ = tests();
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/cons/from_range.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/cons/from_range.cc
new file mode 100644
index 0000000..4a2f193
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/cons/from_range.cc
@@ -0,0 +1,177 @@
+// { dg-do run { target c++26 } }
+
+#include <inplace_vector>
+
+#include <span>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+#include <testsuite_allocator.h>
+
+template<typename T, typename V, size_t N>
+constexpr bool
+eq(const std::inplace_vector<V, N>& l, std::span<const 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;
+};
+
+template<typename T, template<class TT> class ItType>
+constexpr void
+do_test_it()
+{
+ // The vector's value_type.
+ using V = int;
+
+ T a[]{1,2,3,4,5,6,7,8,9};
+ using It = ItType<T>;
+
+ auto bounds = typename It::ContainerType(a, a+9);
+ std::inplace_vector<V, 0> e0(It(a, &bounds), It(a, &bounds));
+ VERIFY( e0.empty() );
+
+ bounds = typename It::ContainerType(a, a+9);
+ std::inplace_vector<V, 10> v0(It(a, &bounds), It(a, &bounds));
+ VERIFY( v0.empty() );
+
+ bounds = typename It::ContainerType(a, a+9);
+ std::inplace_vector<V, 10> v4(It(a, &bounds), It(a+4, &bounds));
+ VERIFY( eq<T>(v4, {a, 4}) );
+
+#ifdef __cpp_exceptions
+#ifdef __cpp_lib_constexpr_exceptions
+#error remove the consteval check
+#endif
+ if consteval {
+ return;
+ }
+
+ bounds = typename It::ContainerType(a, a+9);
+ try
+ {
+ std::inplace_vector<int, 5> v9(It(a, &bounds), It(a+9, &bounds));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+
+ bounds = typename It::ContainerType(a, a+9);
+ try
+ {
+ std::inplace_vector<int, 0> v2(It(a, &bounds), It(a+2, &bounds));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+#endif
+}
+
+constexpr bool
+test_iterators()
+{
+ using namespace __gnu_test;
+
+ do_test_it<int, input_iterator_wrapper>();
+ do_test_it<int, forward_iterator_wrapper>();
+ do_test_it<int, random_access_iterator_wrapper>();
+
+ do_test_it<short, forward_iterator_wrapper>();
+ return true;
+}
+
+template<typename Range>
+constexpr void
+do_test_r()
+{
+ // The vector's value_type.
+ using V = int;
+
+ // The range's value_type.
+ using T = std::ranges::range_value_t<Range>;
+ T a[]{1,2,3,4,5,6,7,8,9};
+
+ std::inplace_vector<V, 0> e0(std::from_range, Range(a, a+0));
+ VERIFY( e0.empty() );
+
+ std::inplace_vector<V, 10> v0(std::from_range, Range(a, a+0));
+ VERIFY( v0.empty() );
+
+ std::inplace_vector<V, 10> v4(std::from_range, Range(a, a+4));
+ VERIFY( eq<T>(v4, {a, 4}) );
+
+#ifdef __cpp_exceptions
+#ifdef __cpp_lib_constexpr_exceptions
+#error remove the consteval check
+#endif
+ if consteval {
+ return;
+ }
+
+ try
+ {
+ std::inplace_vector<V, 5> v9(std::from_range, Range(a, a+9));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+
+ try
+ {
+ std::inplace_vector<V, 0> v3(std::from_range, Range(a, a+3));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+#endif
+}
+
+constexpr bool
+test_ranges()
+{
+ using namespace __gnu_test;
+
+ do_test_r<test_forward_range<int>>();
+ do_test_r<test_sized_range_sized_sent<int, forward_iterator_wrapper>>();
+
+ do_test_r<test_input_range<int>>();
+ do_test_r<test_input_sized_range<int>>();
+ do_test_r<test_sized_range_sized_sent<int, input_iterator_wrapper>>();
+
+ do_test_r<test_range<int, input_iterator_wrapper_nocopy>>();
+ do_test_r<test_sized_range<int, input_iterator_wrapper_nocopy>>();
+ do_test_r<test_sized_range_sized_sent<int, input_iterator_wrapper_nocopy>>();
+
+ do_test_r<test_forward_range<short>>();
+ do_test_r<test_input_range<short>>();
+
+ // Not lvalue-convertible to int
+ struct C {
+ constexpr C(int v) : val(v) { }
+ constexpr operator int() && { return val; }
+ constexpr bool operator==(int b) const { return b == val; }
+ int val;
+ };
+ using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>;
+ do_test_r<rvalue_input_range>();
+
+ return true;
+}
+
+int main()
+{
+ auto test_all = [] {
+ test_iterators();
+ test_ranges();
+ return true;
+ };
+
+ test_all();
+ static_assert( test_all() );
+}
+
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/cons/throws.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/cons/throws.cc
new file mode 100644
index 0000000..4ce39d1
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/cons/throws.cc
@@ -0,0 +1,129 @@
+// { dg-do run { target c++26 } }
+
+#include <inplace_vector>
+
+#include <span>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+#include <testsuite_allocator.h>
+
+struct CopyFailed {};
+
+struct Thrower
+{
+ static inline size_t throw_after = 0;
+ static inline size_t incontainer = 0;
+
+ Thrower() {}
+ Thrower(int x) {}
+ Thrower(const Thrower&)
+ {
+ if (incontainer >= throw_after)
+ throw CopyFailed();
+ ++incontainer;
+ }
+
+ ~Thrower()
+ { --incontainer; }
+};
+
+template<template<class TT> class ItType>
+void
+do_test_it()
+{
+ // The vector's value_type.
+ using V = Thrower;
+
+ V a[]{1,2,3,4,5,6,7,8,9};
+ using It = ItType<V>;
+
+ auto bounds = typename It::ContainerType(a, a+9);
+ Thrower::throw_after = 100;
+ Thrower::incontainer = 0;
+ try
+ {
+ std::inplace_vector<V, 5> v9(It(a, &bounds), It(a+9, &bounds));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( Thrower::incontainer == 0 );
+
+ bounds = typename It::ContainerType(a, a+9);
+ Thrower::throw_after = 2;
+ Thrower::incontainer = 0;
+ try
+ {
+ std::inplace_vector<V, 5> v2(It(a, &bounds), It(a+3, &bounds));
+ VERIFY(false);
+ }
+ catch (CopyFailed const&)
+ {
+ }
+ VERIFY( Thrower::incontainer == 0 );
+}
+
+bool
+test_iterators()
+{
+ using namespace __gnu_test;
+ do_test_it<input_iterator_wrapper>();
+ do_test_it<forward_iterator_wrapper>();
+ do_test_it<random_access_iterator_wrapper>();
+ return true;
+}
+
+template<typename Range>
+void
+do_test_r()
+{
+ // The vector's value_type.
+ using V = Thrower;
+
+ V a[]{1,2,3,4,5,6,7,8,9};
+
+ Thrower::throw_after = 100;
+ Thrower::incontainer = 0;
+ try
+ {
+ std::inplace_vector<V, 5> v9(std::from_range, Range(a, a+9));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( Thrower::incontainer == 0 );
+
+ Thrower::throw_after = 2;
+ Thrower::incontainer = 0;
+ try
+ {
+ std::inplace_vector<V, 5> v9(std::from_range, Range(a, a+3));
+ VERIFY(false);
+ }
+ catch (CopyFailed const&)
+ {
+ }
+ VERIFY( Thrower::incontainer == 0 );
+}
+
+bool
+test_ranges()
+{
+ using namespace __gnu_test;
+ do_test_r<test_forward_range<Thrower>>();
+ do_test_r<test_sized_range_sized_sent<Thrower, forward_iterator_wrapper>>();
+
+ do_test_r<test_input_range<Thrower>>();
+ do_test_r<test_input_sized_range<Thrower>>();
+ do_test_r<test_sized_range_sized_sent<Thrower, input_iterator_wrapper>>();
+ return true;
+}
+
+int main()
+{
+ test_iterators();
+ test_ranges();
+}
+
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/copy.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/copy.cc
new file mode 100644
index 0000000..917eebd
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/copy.cc
@@ -0,0 +1,251 @@
+// { dg-do run { target c++26 } }
+
+#include <inplace_vector>
+#include <ranges>
+#include <testsuite_hooks.h>
+
+struct X
+{
+ X() = default;
+ constexpr X(int p) : v(p) {}
+ constexpr X(const X& o) : v(o.v) { } // not trivial
+ constexpr X& operator=(const X& o) // not trivial
+ { v = o.v; return *this; }
+
+ int v;
+
+ friend auto operator<=>(const X&, const X&) = default;
+};
+
+template<bool CNoex, bool ANoex>
+struct N
+{
+ N() = default;
+ constexpr N(const N&) noexcept(CNoex) { } // not trivial
+ constexpr N& operator=(const N& o) noexcept(ANoex) // not trivial
+ { return *this; }
+};
+
+struct D
+{
+ D() = default;
+ D(const D&) = default;
+ D& operator=(const D&) = default;
+ ~D() {} // not trivially destructible
+};
+
+struct U
+{
+ U() = default;
+ U(const U&) noexcept(false) = default; // lies about noexcept, is trivial but throwing
+ U& operator=(const U&) noexcept(false) = default; // lies about noexcept, is trivial but throwing
+};
+
+// n5008 inplace.vector.overview p5 says for inplace_vector<T, 0>
+// provides trivial copy/move/default cosntructpr regardless of T
+struct Z
+{
+ Z(Z&&) = delete;
+ Z& operator=(Z&&) = delete;
+};
+
+template<size_t N, typename T>
+ constexpr std::inplace_vector<T, N> const&
+ materialize(std::inplace_vector<T, N> const& r)
+ { return r; }
+
+static_assert(std::is_copy_constructible_v<std::inplace_vector<int, 2>>);
+static_assert(std::is_copy_constructible_v<std::inplace_vector<X, 2>>);
+static_assert(std::is_copy_constructible_v<std::inplace_vector<N<false, false>, 2>>);
+static_assert(std::is_copy_constructible_v<std::inplace_vector<D, 2>>);
+static_assert(std::is_copy_constructible_v<std::inplace_vector<U, 2>>);
+// The operators are not constrained, as for any other container
+static_assert(std::is_copy_constructible_v<std::inplace_vector<Z, 2>>);
+
+// conditional noexcept here is libstdc++ extension,
+static_assert(std::is_nothrow_copy_constructible_v<std::inplace_vector<int, 2>>);
+static_assert(!std::is_nothrow_copy_constructible_v<std::inplace_vector<X, 2>>);
+static_assert(std::is_nothrow_copy_constructible_v<std::inplace_vector<N<true, true>, 2>>);
+static_assert(std::is_nothrow_copy_constructible_v<std::inplace_vector<N<true, false>, 2>>);
+static_assert(!std::is_nothrow_copy_constructible_v<std::inplace_vector<N<false, true>, 2>>);
+static_assert(!std::is_nothrow_copy_constructible_v<std::inplace_vector<N<false, false>, 2>>);
+static_assert(std::is_nothrow_copy_constructible_v<std::inplace_vector<D, 2>>);
+static_assert(!std::is_nothrow_copy_constructible_v<std::inplace_vector<U, 2>>);
+
+#if !_GLIBCXX_DEBUG
+static_assert(std::is_trivially_copy_constructible_v<std::inplace_vector<int, 2>>);
+static_assert(!std::is_trivially_copy_constructible_v<std::inplace_vector<X, 2>>);
+static_assert(!std::is_trivially_copy_constructible_v<std::inplace_vector<N<true, true>, 2>>);
+// is_trivially_copy_constructible_v checks destructor
+static_assert(!std::is_trivially_copy_constructible_v<std::inplace_vector<D, 2>>);
+static_assert(std::is_trivially_copy_constructible_v<std::inplace_vector<U, 2>>);
+#endif
+
+static_assert(std::is_copy_assignable_v<std::inplace_vector<int, 2>>);
+static_assert(std::is_copy_assignable_v<std::inplace_vector<X, 2>>);
+static_assert(std::is_copy_assignable_v<std::inplace_vector<N<false, false>, 2>>);
+static_assert(std::is_copy_assignable_v<std::inplace_vector<D, 2>>);
+static_assert(std::is_copy_assignable_v<std::inplace_vector<U, 2>>);
+// The operators are not constrained, as for any other container
+static_assert(std::is_copy_assignable_v<std::inplace_vector<Z, 2>>);
+
+static_assert(std::is_nothrow_copy_assignable_v<std::inplace_vector<int, 2>>);
+static_assert(!std::is_nothrow_copy_assignable_v<std::inplace_vector<X, 2>>);
+static_assert(std::is_nothrow_copy_assignable_v<std::inplace_vector<N<true, true>, 2>>);
+static_assert(!std::is_nothrow_copy_assignable_v<std::inplace_vector<N<true, false>, 2>>);
+static_assert(!std::is_nothrow_copy_assignable_v<std::inplace_vector<N<false, true>, 2>>);
+static_assert(!std::is_nothrow_copy_assignable_v<std::inplace_vector<N<false, false>, 2>>);
+static_assert(std::is_nothrow_copy_assignable_v<std::inplace_vector<D, 2>>);
+static_assert(!std::is_nothrow_copy_assignable_v<std::inplace_vector<U, 2>>);
+
+#if !_GLIBCXX_DEBUG
+// conditional noexcept here is libstdc++ extension,
+static_assert(std::is_trivially_copy_assignable_v<std::inplace_vector<int, 2>>);
+static_assert(!std::is_trivially_copy_assignable_v<std::inplace_vector<X, 2>>);
+static_assert(!std::is_trivially_copy_assignable_v<std::inplace_vector<N<true, true>, 2>>);
+// destructor is not trivial
+static_assert(!std::is_trivially_copy_assignable_v<std::inplace_vector<D, 2>>);
+static_assert(std::is_trivially_copy_assignable_v<std::inplace_vector<U, 2>>);
+#endif
+
+static_assert(std::is_nothrow_copy_constructible_v<std::inplace_vector<int, 0>>);
+static_assert(std::is_nothrow_copy_constructible_v<std::inplace_vector<X, 0>>);
+static_assert(std::is_nothrow_copy_constructible_v<std::inplace_vector<N<false, false>, 0>>);
+static_assert(std::is_nothrow_copy_constructible_v<std::inplace_vector<D, 0>>);
+static_assert(std::is_nothrow_copy_constructible_v<std::inplace_vector<U, 0>>);
+static_assert(std::is_nothrow_copy_constructible_v<std::inplace_vector<Z, 0>>);
+
+static_assert(std::is_trivially_copy_constructible_v<std::inplace_vector<int, 0>>);
+static_assert(std::is_trivially_copy_constructible_v<std::inplace_vector<X, 0>>);
+static_assert(std::is_trivially_copy_constructible_v<std::inplace_vector<D, 0>>);
+static_assert(std::is_trivially_copy_constructible_v<std::inplace_vector<U, 0>>);
+static_assert(std::is_trivially_copy_constructible_v<std::inplace_vector<Z, 0>>);
+
+static_assert(std::is_nothrow_copy_assignable_v<std::inplace_vector<int, 0>>);
+static_assert(std::is_nothrow_copy_assignable_v<std::inplace_vector<X, 0>>);
+static_assert(std::is_nothrow_copy_assignable_v<std::inplace_vector<N<false, false>, 0>>);
+static_assert(std::is_nothrow_copy_assignable_v<std::inplace_vector<D, 0>>);
+static_assert(std::is_nothrow_copy_assignable_v<std::inplace_vector<U, 0>>);
+static_assert(std::is_nothrow_copy_assignable_v<std::inplace_vector<Z, 0>>);
+
+static_assert(std::is_trivially_copy_assignable_v<std::inplace_vector<int, 0>>);
+static_assert(std::is_trivially_copy_assignable_v<std::inplace_vector<X, 0>>);
+static_assert(std::is_trivially_copy_assignable_v<std::inplace_vector<N<false, false>, 0>>);
+static_assert(std::is_trivially_copy_assignable_v<std::inplace_vector<D, 0>>);
+static_assert(std::is_trivially_copy_assignable_v<std::inplace_vector<U, 0>>);
+static_assert(std::is_trivially_copy_assignable_v<std::inplace_vector<Z, 0>>);
+
+
+template<typename T, size_t N>
+constexpr bool
+eq(const std::inplace_vector<T, N>& s, std::span<const T> o)
+{ return std::ranges::equal(s, o); }
+
+constexpr void
+test_ctor()
+{
+ auto e0 = materialize<0, int>({});
+ VERIFY( e0.empty() );
+ auto e1 = materialize<0, X>({});
+ VERIFY( e1.empty() );
+ auto e2 = materialize<0, Z>({});
+ VERIFY( e2.empty() );
+
+ auto c0 = materialize<5, int>({});
+ VERIFY( c0.empty() );
+
+ auto c3 = materialize<5, int>({1, 2, 3});
+ VERIFY( eq(c3, {1, 2, 3}) );
+
+ auto c5 = materialize<5, int>({1, 2, 3, 4, 5});
+ VERIFY( eq(c5, {1, 2, 3, 4, 5}) );
+
+#ifdef __cpp_lib_constexpr_inplace_vector
+#error remove the consteval check
+#endif
+ if consteval {
+ return;
+ }
+
+ auto x0 = materialize<3, X>({});
+ VERIFY( x0.empty() );
+
+ auto x2 = materialize<3, X>({1, 2});
+ VERIFY( eq(x2, {1, 2}) );
+
+ auto x3 = materialize<3, X>({1, 2, 3});
+ VERIFY( eq(x3, {1, 2, 3}) );
+}
+
+constexpr void
+test_assign()
+{
+ std::inplace_vector<int, 0> e0;
+ e0 = materialize<0, int>({});
+ VERIFY( e0.empty() );
+ std::inplace_vector<X, 0> e1;
+ e1 = materialize<0, X>({});
+ VERIFY( e1.empty() );
+ std::inplace_vector<Z, 0> e2;
+ e2 = materialize<0, Z>({});
+ VERIFY( e2.empty() );
+
+ std::inplace_vector<int, 5> c;
+ c = materialize<5, int>({});
+ VERIFY( c.empty() );
+
+ c = materialize<5, int>({1, 2, 3});
+ VERIFY( eq(c, {1, 2, 3}) );
+
+ c = materialize<5, int>({1, 2, 3, 4, 5});
+ VERIFY( eq(c, {1, 2, 3, 4, 5}) );
+
+ c = materialize<5, int>({4, 5});
+ VERIFY( eq(c, {4, 5}) );
+
+ c = materialize<5, int>({});
+ VERIFY( c.empty() );
+
+#ifdef __cpp_lib_constexpr_inplace_vector
+#error remove the consteval check
+#endif
+ if consteval {
+ return;
+ }
+
+ std::inplace_vector<X, 5> x;
+ x = materialize<5, X>({});
+ VERIFY( x.empty() );
+
+ x = materialize<5, X>({1, 2, 3});
+ VERIFY( eq(x, {1, 2, 3}) );
+
+ x = materialize<5, X>({1, 2, 3, 4, 5});
+ VERIFY( eq(x, {1, 2, 3, 4, 5}) );
+
+ x = materialize<5, X>({4, 5});
+ VERIFY( eq(x, {4, 5}) );
+
+ x = materialize<5, X>({});
+ VERIFY( x.empty() );
+}
+
+constexpr auto e0 = materialize<0, int>({});
+constexpr auto e1 = materialize<0, X>({});
+constexpr auto e2 = materialize<0, Z>({});
+
+constexpr auto t1 = materialize<3, int>({});
+constexpr auto t2 = materialize<3, int>({1, 2});
+constexpr auto t3 = materialize<3, int>({11, 22, 33});
+
+int main()
+{
+ auto tests = [] {
+ test_ctor();
+ test_assign();
+ return true;
+ };
+
+ tests();
+ constexpr bool _ = tests();
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/assign1_neg.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/assign1_neg.cc
new file mode 100644
index 0000000..37c80c3
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/assign1_neg.cc
@@ -0,0 +1,16 @@
+// { dg-do run { target c++26 xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <inplace_vector>
+#include <debug/checks.h>
+
+void test01()
+{
+ __gnu_test::check_assign1<std::inplace_vector<int, 10> >();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/assign2_neg.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/assign2_neg.cc
new file mode 100644
index 0000000..ff6c9a7
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/assign2_neg.cc
@@ -0,0 +1,16 @@
+// { dg-do run { target c++26 xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <inplace_vector>
+#include <debug/checks.h>
+
+void test01()
+{
+ __gnu_test::check_assign2<std::inplace_vector<int, 10>>();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/assign3_neg.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/assign3_neg.cc
new file mode 100644
index 0000000..42f811d
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/assign3_neg.cc
@@ -0,0 +1,16 @@
+// { dg-do run { target c++26 xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <inplace_vector>
+#include <debug/checks.h>
+
+void test01()
+{
+ __gnu_test::check_assign3<std::inplace_vector<int, 10>>();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/assign4_backtrace_neg.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/assign4_backtrace_neg.cc
new file mode 100644
index 0000000..dec7228
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/assign4_backtrace_neg.cc
@@ -0,0 +1,17 @@
+// { dg-do run { target c++26 xfail *-*-* } }
+// { dg-options "-D_GLIBCXX_DEBUG_BACKTRACE -lstdc++exp" }
+// { dg-require-cpp-feature-test __cpp_lib_stacktrace }
+
+#include <debug/inplace_vector>
+#include <debug/checks.h>
+
+void test01()
+{
+ __gnu_test::check_assign1<__gnu_debug::inplace_vector<int, 10>>();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/assign4_neg.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/assign4_neg.cc
new file mode 100644
index 0000000..4bed345
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/assign4_neg.cc
@@ -0,0 +1,15 @@
+// { dg-do run { target c++26 xfail *-*-* } }
+
+#include <debug/inplace_vector>
+#include <debug/checks.h>
+
+void test01()
+{
+ __gnu_test::check_assign1<__gnu_debug::inplace_vector<int, 10>>();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/construct1_neg.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/construct1_neg.cc
new file mode 100644
index 0000000..28ede4c
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/construct1_neg.cc
@@ -0,0 +1,16 @@
+// { dg-do run { target c++26 xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <inplace_vector>
+#include <debug/checks.h>
+
+void test01()
+{
+ __gnu_test::check_construct1<std::inplace_vector<int, 10> >();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/construct2_neg.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/construct2_neg.cc
new file mode 100644
index 0000000..be37dde
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/construct2_neg.cc
@@ -0,0 +1,16 @@
+// { dg-do run { target c++26 xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <inplace_vector>
+#include <debug/checks.h>
+
+void test01()
+{
+ __gnu_test::check_construct2<std::inplace_vector<int, 10> >();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/construct3_neg.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/construct3_neg.cc
new file mode 100644
index 0000000..8086183
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/construct3_neg.cc
@@ -0,0 +1,16 @@
+// { dg-do run { target c++26 xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <inplace_vector>
+#include <debug/checks.h>
+
+void test01()
+{
+ __gnu_test::check_construct3<std::inplace_vector<int, 10> >();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/construct4_neg.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/construct4_neg.cc
new file mode 100644
index 0000000..099b357
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/construct4_neg.cc
@@ -0,0 +1,15 @@
+// { dg-do run { target c++26 xfail *-*-* } }
+
+#include <debug/inplace_vector>
+#include <debug/checks.h>
+
+void test01()
+{
+ __gnu_test::check_construct1<__gnu_debug::inplace_vector<int, 10> >();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/debug_functions.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/debug_functions.cc
new file mode 100644
index 0000000..bc5ed50
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/debug_functions.cc
@@ -0,0 +1,34 @@
+// { dg-do run { target c++26 } }
+// { dg-require-debug-mode "" }
+
+#include <inplace_vector>
+#include <testsuite_hooks.h>
+
+void test02()
+{
+ using namespace __gnu_debug;
+
+ std::inplace_vector<int, 10> v1(3, 1);
+ VERIFY( !__check_singular(v1.begin()) );
+ auto it = v1.begin();
+ VERIFY( !__check_singular(it) );
+
+ VERIFY( !__check_singular(v1.end()) );
+ it = v1.end();
+ VERIFY( !__check_singular(it) );
+
+ v1.clear();
+
+ VERIFY( it._M_singular() );
+ VERIFY( __check_singular(it) );
+
+ it = v1.end();
+ VERIFY( !it._M_singular() );
+ VERIFY( !__check_singular(it) );
+}
+
+int main()
+{
+ test02();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/erase.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/erase.cc
new file mode 100644
index 0000000..94da946
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/erase.cc
@@ -0,0 +1,35 @@
+// { dg-do run { target c++26 } }
+// { dg-require-debug-mode "" }
+
+#include <inplace_vector>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+ std::inplace_vector<int, 10> v;
+
+ for (int i = 0; i != 10; ++i)
+ v.push_back(i);
+
+ auto before = v.begin() + 4;
+ auto last = v.end() - 1;
+
+ VERIFY( std::erase(v, 6) == 1 );
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(last._M_singular());
+}
+
+void test02()
+{
+ std::inplace_vector<int, 0> v;
+
+ VERIFY( std::erase(v, 6) == 0 );
+}
+
+int main()
+{
+ test01();
+ test02();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/insert1_neg.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/insert1_neg.cc
new file mode 100644
index 0000000..f85cfaa
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/insert1_neg.cc
@@ -0,0 +1,16 @@
+// { dg-do run { target c++26 xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <inplace_vector>
+#include <debug/checks.h>
+
+void test01()
+{
+ __gnu_test::check_insert1<std::inplace_vector<int, 10>>();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/insert2_neg.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/insert2_neg.cc
new file mode 100644
index 0000000..6a20369
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/insert2_neg.cc
@@ -0,0 +1,16 @@
+// { dg-do run { target c++26 xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <inplace_vector>
+#include <debug/checks.h>
+
+void test01()
+{
+ __gnu_test::check_insert2<std::inplace_vector<int, 10>>();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/insert3_neg.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/insert3_neg.cc
new file mode 100644
index 0000000..63f6e05
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/insert3_neg.cc
@@ -0,0 +1,16 @@
+// { dg-do run { target c++26 xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <inplace_vector>
+#include <debug/checks.h>
+
+void test01()
+{
+ __gnu_test::check_insert3<std::inplace_vector<int, 10>>();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/insert4_neg.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/insert4_neg.cc
new file mode 100644
index 0000000..59e9f4b
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/insert4_neg.cc
@@ -0,0 +1,15 @@
+// { dg-do run { target c++26 xfail *-*-* } }
+
+#include <debug/inplace_vector>
+#include <debug/checks.h>
+
+void test01()
+{
+ __gnu_test::check_insert1<__gnu_debug::inplace_vector<int, 10>>();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/insert5_neg.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/insert5_neg.cc
new file mode 100644
index 0000000..e1fbd65
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/insert5_neg.cc
@@ -0,0 +1,16 @@
+// { dg-do run { target c++26 xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <inplace_vector>
+#include <debug/checks.h>
+
+void test01()
+{
+ __gnu_test::check_insert4<std::inplace_vector<int, 10>>();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/insert7_neg.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/insert7_neg.cc
new file mode 100644
index 0000000..c59453c
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/insert7_neg.cc
@@ -0,0 +1,24 @@
+// { dg-do run { target c++26 xfail *-*-* } }
+
+#include <memory>
+#include <iterator>
+#include <debug/inplace_vector>
+
+void
+test01()
+{
+ __gnu_debug::inplace_vector<std::unique_ptr<int>, 10> v;
+
+ v.emplace_back(new int(0));
+ v.emplace_back(new int(1));
+
+ v.insert(begin(v) + 1,
+ make_move_iterator(begin(v)),
+ make_move_iterator(end(v)));
+}
+
+int
+main()
+{
+ test01();
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/1.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/1.cc
new file mode 100644
index 0000000..1a85273
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/1.cc
@@ -0,0 +1,33 @@
+// { dg-do run { target c++26 } }
+
+#include <debug/inplace_vector>
+#include <testsuite_hooks.h>
+
+using __gnu_debug::inplace_vector;
+
+// Assignment
+void test01()
+{
+ inplace_vector<int, 30> v1;
+ inplace_vector<int, 30> v2;
+
+ auto i = v1.end();
+ VERIFY(!i._M_dereferenceable() && !i._M_singular());
+
+ v1 = v2;
+ VERIFY(i._M_singular());
+
+ i = v1.end();
+ v1.assign(v2.begin(), v2.end());
+ VERIFY( !i._M_singular() );
+
+ i = v1.end();
+ v1.assign(17, 42);
+ VERIFY(i._M_singular());
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/2.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/2.cc
new file mode 100644
index 0000000..22d512c
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/2.cc
@@ -0,0 +1,34 @@
+// { dg-do run { target c++26 } }
+
+#include <debug/inplace_vector>
+#include <testsuite_hooks.h>
+
+using __gnu_debug::inplace_vector;
+
+// Resize
+void test01()
+{
+ inplace_vector<int, 50> v(10, 17);
+ v.reserve(20);
+
+ auto before = v.begin() + 6;
+ auto at = before + 1;
+ auto after = at + 1;
+
+ // Shrink.
+ v.resize(7);
+ VERIFY(before._M_dereferenceable());
+ VERIFY(at._M_singular());
+ VERIFY(after._M_singular());
+
+ // Grow.
+ before = v.begin() + 6;
+ v.resize(17);
+ VERIFY(before._M_dereferenceable());
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/3.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/3.cc
new file mode 100644
index 0000000..7b74213
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/3.cc
@@ -0,0 +1,43 @@
+// { dg-do run { target c++26 } }
+
+#include <debug/inplace_vector>
+#include <testsuite_hooks.h>
+
+using __gnu_debug::inplace_vector;
+
+// Insert
+void test01()
+{
+ inplace_vector<int, 100> v(10, 17);
+ v.reserve(30);
+
+ // Insert a single element
+ auto before = v.begin() + 6;
+ auto at = before + 1;
+ auto after = at;
+ at = v.insert(at, 42);
+ VERIFY(before._M_dereferenceable());
+ VERIFY(at._M_dereferenceable());
+ VERIFY(after._M_singular());
+
+ // Insert multiple copies
+ before = v.begin() + 6;
+ at = before + 1;
+ v.insert(at, 3, 42);
+ VERIFY(before._M_dereferenceable());
+ VERIFY(at._M_singular());
+
+ // Insert iterator range
+ static int data[] = { 2, 3, 5, 7 };
+ before = v.begin() + 6;
+ at = before + 1;
+ v.insert(at, &data[0], &data[0] + 4);
+ VERIFY(before._M_dereferenceable());
+ VERIFY(at._M_singular());
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/4.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/4.cc
new file mode 100644
index 0000000..7393f1b
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/4.cc
@@ -0,0 +1,40 @@
+// { dg-do run { target c++26 } }
+
+#include <debug/inplace_vector>
+#include <testsuite_hooks.h>
+
+using __gnu_debug::inplace_vector;
+
+// Erase
+void test04()
+{
+ inplace_vector<int, 30> v(20, 42);
+
+ // Single element erase
+ auto before = v.begin();
+ auto at = before + 3;
+ auto after = at;
+ at = v.erase(at);
+ VERIFY(before._M_dereferenceable());
+ VERIFY(at._M_dereferenceable());
+ VERIFY(after._M_singular());
+
+ // Multiple element erase
+ before = v.begin();
+ at = before + 3;
+ v.erase(at, at + 3);
+ VERIFY(before._M_dereferenceable());
+ VERIFY(at._M_singular());
+
+ // clear()
+ before = v.begin();
+ VERIFY(before._M_dereferenceable());
+ v.clear();
+ VERIFY(before._M_singular());
+}
+
+int main()
+{
+ test04();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/append_range.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/append_range.cc
new file mode 100644
index 0000000..8a793ec
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/append_range.cc
@@ -0,0 +1,45 @@
+// { dg-do run { target c++26 } }
+
+#include <debug/inplace_vector>
+#include <testsuite_hooks.h>
+
+using __gnu_debug::inplace_vector;
+
+void test01()
+{
+ inplace_vector<int, 100> v(10, 17);
+ inplace_vector<int, 10> v1(10, 19);
+
+ auto before = v.begin() + 6;
+ auto last = v.end();
+ auto end = last--;
+
+ v.append_range(v1);
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(last._M_dereferenceable());
+ VERIFY(end._M_singular());
+}
+
+void test02()
+{
+ inplace_vector<int, 100> v(10, 17);
+ inplace_vector<int, 0> v1;
+
+ auto before = v.begin() + 6;
+ auto last = v.end();
+ auto end = last--;
+
+ v.append_range(v1);
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(last._M_dereferenceable());
+ VERIFY(!end._M_singular());
+}
+
+int main()
+{
+ test01();
+ test02();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/erase.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/erase.cc
new file mode 100644
index 0000000..6e899d7
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/erase.cc
@@ -0,0 +1,36 @@
+// { dg-do run { target c++26 } }
+
+#include <debug/inplace_vector>
+#include <testsuite_hooks.h>
+
+using __gnu_debug::inplace_vector;
+
+void test01()
+{
+ inplace_vector<int, 10> v;
+
+ for (int i = 0; i != 10; ++i)
+ v.push_back(i);
+
+ auto before = v.begin() + 4;
+ auto last = v.end() - 1;
+
+ VERIFY( std::erase(v, 6) == 1 );
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(last._M_singular());
+}
+
+void test02()
+{
+ inplace_vector<int, 0> v;
+
+ VERIFY( std::erase(v, 6) == 0 );
+}
+
+int main()
+{
+ test01();
+ test02();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/pop_back.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/pop_back.cc
new file mode 100644
index 0000000..4c1a043
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/pop_back.cc
@@ -0,0 +1,27 @@
+// { dg-do run { target c++26 } }
+
+#include <debug/inplace_vector>
+#include <testsuite_hooks.h>
+
+using __gnu_debug::inplace_vector;
+
+void test01()
+{
+ inplace_vector<int, 100> v(10, 17);
+
+ auto before = v.begin() + 6;
+ auto last = v.end();
+ auto end = last--;
+
+ v.pop_back();
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(last._M_singular());
+ VERIFY(end._M_singular());
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/push_back.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/push_back.cc
new file mode 100644
index 0000000..f269364
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/push_back.cc
@@ -0,0 +1,53 @@
+// { dg-do run { target c++26 } }
+
+#include <debug/inplace_vector>
+#include <testsuite_hooks.h>
+
+using __gnu_debug::inplace_vector;
+
+void test01()
+{
+ inplace_vector<int, 100> v(10, 17);
+
+ auto before = v.begin() + 6;
+ auto last = v.end();
+ auto end = last--;
+
+ v.push_back(42);
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(last._M_dereferenceable());
+ VERIFY(end._M_singular());
+}
+
+#if __cpp_exceptions
+void test02()
+{
+ inplace_vector<int, 10> v(10, 17);
+
+ auto before = v.begin() + 6;
+ auto last = v.end();
+ auto end = last--;
+ try
+ {
+ v.push_back(42);
+ VERIFY( false );
+ }
+ catch (std::bad_alloc&)
+ {
+ }
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(last._M_dereferenceable());
+ VERIFY(!end._M_singular());
+}
+#endif
+
+int main()
+{
+ test01();
+#if __cpp_exceptions
+ test02();
+#endif
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/swap.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/swap.cc
new file mode 100644
index 0000000..3e5ab74
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/swap.cc
@@ -0,0 +1,53 @@
+// { dg-do run { target c++26 } }
+
+#include <debug/inplace_vector>
+#include <testsuite_hooks.h>
+
+using __gnu_debug::inplace_vector;
+
+void test01()
+{
+ inplace_vector<int, 10> v1;
+ inplace_vector<int, 10> v2;
+
+ for (int i = 0; i != 10; ++i)
+ {
+ v1.push_back(i);
+ v2.push_back(i);
+ }
+
+ auto it1 = v1.begin();
+ auto it2 = v2.begin();
+
+ std::swap(v1, v2);
+
+ VERIFY(it1._M_singular());
+ VERIFY(it2._M_singular());
+}
+
+void test02()
+{
+ inplace_vector<int, 10> v1;
+ inplace_vector<int, 10> v2;
+
+ for (int i = 0; i != 10; ++i)
+ {
+ v1.push_back(i);
+ v2.push_back(i);
+ }
+
+ auto it1 = v1.begin();
+ auto it2 = v2.begin();
+
+ swap(v1, v2);
+
+ VERIFY(it1._M_singular());
+ VERIFY(it2._M_singular());
+}
+
+int main()
+{
+ test01();
+ test02();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/try_append_range.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/try_append_range.cc
new file mode 100644
index 0000000..ae4ac41
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/try_append_range.cc
@@ -0,0 +1,45 @@
+// { dg-do run { target c++26 } }
+
+#include <debug/inplace_vector>
+#include <testsuite_hooks.h>
+
+using __gnu_debug::inplace_vector;
+
+void test01()
+{
+ inplace_vector<int, 100> v(10, 17);
+ inplace_vector<int, 10> v1(10, 19);
+
+ auto before = v.begin() + 6;
+ auto last = v.end();
+ auto end = last--;
+
+ v.try_append_range(v1);
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(last._M_dereferenceable());
+ VERIFY(end._M_singular());
+}
+
+void test02()
+{
+ inplace_vector<int, 100> v(10, 17);
+ inplace_vector<int, 0> v1;
+
+ auto before = v.begin() + 6;
+ auto last = v.end();
+ auto end = last--;
+
+ v.try_append_range(v1);
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(last._M_dereferenceable());
+ VERIFY(!end._M_singular());
+}
+
+int main()
+{
+ test01();
+ test02();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/try_emplace_back.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/try_emplace_back.cc
new file mode 100644
index 0000000..f7c8c7a
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/try_emplace_back.cc
@@ -0,0 +1,27 @@
+// { dg-do run { target c++26 } }
+
+#include <debug/inplace_vector>
+#include <testsuite_hooks.h>
+
+using __gnu_debug::inplace_vector;
+
+void test01()
+{
+ inplace_vector<int, 100> v(10, 17);
+
+ auto before = v.begin() + 6;
+ auto last = v.end();
+ auto end = last--;
+
+ VERIFY( v.try_emplace_back(42) != nullptr );
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(last._M_dereferenceable());
+ VERIFY(end._M_singular());
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/try_push_back.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/try_push_back.cc
new file mode 100644
index 0000000..04fc010
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/try_push_back.cc
@@ -0,0 +1,45 @@
+// { dg-do run { target c++26 } }
+
+#include <debug/inplace_vector>
+#include <vector>
+#include <testsuite_hooks.h>
+
+using __gnu_debug::inplace_vector;
+
+void test01()
+{
+ inplace_vector<int, 100> v(10, 17);
+
+ auto before = v.begin() + 6;
+ auto last = v.end();
+ auto end = last--;
+
+ VERIFY( v.try_push_back(42) != nullptr );
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(last._M_dereferenceable());
+ VERIFY(end._M_singular());
+}
+
+void test02()
+{
+ std::vector<int> vv { 0, 1, 2, 3, 4, 5 };
+ inplace_vector<std::vector<int>, 100> v(10, vv);
+
+ auto before = v.begin() + 6;
+ auto last = v.end();
+ auto end = last--;
+
+ VERIFY( v.try_push_back(std::move(vv)) != nullptr );
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(last._M_dereferenceable());
+ VERIFY(end._M_singular());
+}
+
+int main()
+{
+ test01();
+ test02();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/unchecked_emplace_back.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/unchecked_emplace_back.cc
new file mode 100644
index 0000000..0d173d5
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/unchecked_emplace_back.cc
@@ -0,0 +1,27 @@
+// { dg-do run { target c++26 } }
+
+#include <debug/inplace_vector>
+#include <testsuite_hooks.h>
+
+using __gnu_debug::inplace_vector;
+
+void test01()
+{
+ inplace_vector<int, 100> v(10, 17);
+
+ auto before = v.begin() + 6;
+ auto last = v.end();
+ auto end = last--;
+
+ v.unchecked_emplace_back(42);
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(last._M_dereferenceable());
+ VERIFY(end._M_singular());
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/erasure.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/erasure.cc
new file mode 100644
index 0000000..8fb56e9
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/erasure.cc
@@ -0,0 +1,69 @@
+// { dg-do run { target c++26 } }
+
+#include <inplace_vector>
+#include <testsuite_hooks.h>
+#include <span>
+
+template<typename T, size_t N>
+constexpr bool
+eq(const std::inplace_vector<T, N>& l, std::span<const 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;
+};
+
+constexpr void
+test_erase()
+{
+ std::inplace_vector<int, 15> c{1, 0, 3, 4, 5, 6, 5, 4, 3, 0, 1, 4, 4, 9};
+ std::erase(c, 4);
+ VERIFY( c.size() == 10 );
+ std::erase(c, 1);
+ VERIFY( c.size() == 8 );
+ std::erase(c, 9);
+ VERIFY( c.size() == 7 );
+ VERIFY( eq(c, {0, 3, 5, 6, 5, 3, 0}) );
+
+ std::erase(c, {});
+ VERIFY( c.size() == 5 );
+ VERIFY( eq(c, {3, 5, 6, 5, 3}) );
+
+ std::erase(c, {5});
+ VERIFY( c.size() == 3 );
+ VERIFY( eq(c, {3, 6, 3}) );
+
+ std::inplace_vector<int, 0> e;
+ std::erase(e, 10);
+ VERIFY( e.empty() );
+}
+
+constexpr void
+test_erase_if()
+{
+ std::inplace_vector<int, 15> c{1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1, 4, 4, 9};
+ std::erase_if(c, [](int i) { return i > 5; });
+ VERIFY( c.size() == 12 );
+ std::erase_if(c, [](int i) { return i == 4; });
+ VERIFY( c.size() == 8 );
+ std::erase_if(c, [](int i) { return i & 1; });
+ VERIFY( eq(c, {2, 2}) );
+
+ std::inplace_vector<int, 0> e;
+ std::erase_if(e, [](int i) { return i > 5; });
+ VERIFY( e.empty() );
+}
+
+int main()
+{
+ test_erase();
+ test_erase_if();
+
+ constexpr bool _ = [] {
+ test_erase();
+ test_erase_if();
+ return true;
+ }();
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/assign.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/assign.cc
new file mode 100644
index 0000000..65b505e
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/assign.cc
@@ -0,0 +1,379 @@
+// { dg-do run { target c++26 } }
+
+#include <inplace_vector>
+
+#include <span>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+struct X
+{
+ X() = default;
+ constexpr X(int p) : v(p) {}
+ constexpr X(const X& o) : v(o.v) { } // not trivial
+ constexpr X& operator=(const X& o) // not trivial
+ { v = o.v; return *this; }
+
+ int v;
+
+ friend auto operator<=>(const X&, const X&) = default;
+};
+
+template<typename T, typename V, size_t N>
+constexpr bool
+eq(const std::inplace_vector<V, N>& l, std::span<const 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;
+};
+
+template<size_t N, typename T, template<class TT> class ItType>
+constexpr void
+test_assign_empty_it()
+{
+ using namespace __gnu_test;
+
+ T a[]{1,2,3,4,5,6,7,8,9,10};
+ using It = ItType<T>;
+ using Range = test_range<T, ItType>;
+ using SizedRange = test_sized_range<T, ItType>;
+
+ const std::inplace_vector<T, N> src(std::from_range, std::span(a, N));
+ std::inplace_vector<T, N> v;
+
+ v = src;
+ v.assign_range(Range(a, a));
+ VERIFY( v.empty() );
+ v.assign_range(Range(a, a));
+ VERIFY( v.empty() );
+
+ v = src;
+ v.assign_range(SizedRange(a, a));
+ VERIFY( v.empty() );
+
+ v = src;
+ auto bounds = typename It::ContainerType(a, a+9);
+ v.assign(It(a, &bounds), It(a, &bounds));
+ VERIFY( v.empty() );
+
+#ifdef __cpp_exceptions
+#ifdef __cpp_lib_constexpr_exceptions
+#error remove the consteval check
+#endif
+ if consteval {
+ return;
+ }
+
+ static_assert(N < 9);
+
+ v = src;
+ try
+ {
+ v.assign_range(Range(a, a+9));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ if constexpr (std::ranges::sized_range<Range> || std::ranges::forward_range<Range>)
+ VERIFY( eq<T>(v, {a, N}) );
+
+ v = src;
+ try
+ {
+ v.assign_range(SizedRange(a, a+9));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( eq<T>(v, {a, N}) );
+
+ v = src;
+ bounds = typename It::ContainerType(a, a+9);
+ try
+ {
+ v.assign(It(a, &bounds), It(a+9, &bounds));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ if constexpr(std::forward_iterator<It>)
+ VERIFY( eq<T>(v, {a, N}) );
+#endif
+}
+
+template<size_t N, typename T>
+constexpr void
+test_assign_empty_other()
+{
+ T a[]{1,2,3,4,5,6,7,8,9,10};
+ const std::inplace_vector<T, N> src(std::from_range, std::span(a, N));
+ std::inplace_vector<T, N> v;
+
+ v = src;
+ v.assign(0, T(4));
+ VERIFY( v.empty() );
+
+ v = src;
+ v.assign({});
+ VERIFY( v.empty() );
+
+ v = src;
+ v = {};
+ VERIFY( v.empty() );
+
+ v = src;
+ v.resize(0, T(3));
+ VERIFY( v.empty() );
+
+ v = src;
+ v.resize(0);
+ VERIFY( v.empty() );
+
+#ifdef __cpp_exceptions
+#ifdef __cpp_lib_constexpr_exceptions
+#error remove the consteval check
+#endif
+ if consteval {
+ return;
+ }
+
+ static_assert(N < 9);
+
+ v = src;
+ try
+ {
+ v.assign(9, T(4));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( eq<T>(v, {a, N}) );
+
+ std::initializer_list<T> il =
+ {T(0), T(1), T(2), T(3), T(4), T(5), T(6), T(7), T(8), T(9), T(10)};
+ try
+ {
+ v.assign(il);
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( eq<T>(v, {a, N}) );
+
+ try
+ {
+ v = il;
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( eq<T>(v, {a, N}) );
+
+ try
+ {
+ v.resize(9, T(3));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( eq<T>(v, {a, N}) );
+
+ try
+ {
+ v.resize(9);
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( eq<T>(v, {a, N}) );
+#endif
+}
+
+template<size_t N, typename T>
+constexpr void
+test_assign_empty()
+{
+ using namespace __gnu_test;
+ test_assign_empty_it<N, T, input_iterator_wrapper>();
+ test_assign_empty_it<N, T, forward_iterator_wrapper>();
+ test_assign_empty_it<N, T, random_access_iterator_wrapper>();
+
+ test_assign_empty_other<N, T>;
+}
+
+template<typename Range>
+constexpr void
+test_assign_range()
+{
+ using T = std::ranges::range_value_t<Range>;
+ T a[]{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
+
+ std::inplace_vector<T, 10> v;
+ v.assign_range(Range(a,a+5));
+ VERIFY( eq<T>(v, {a, 5}) );
+
+ v.assign_range(Range(a,a+7));
+ VERIFY( eq<T>(v, {a, 7}) );
+
+ v.assign_range(Range(a,a+3));
+ VERIFY( eq<T>(v, {a, 3}) );
+
+ v.assign_range(Range(a,a+10));
+ VERIFY( eq<T>(v, {a, 10}) );
+}
+
+template<typename T, template<class TT> class ItType>
+constexpr void
+test_assign_iterators()
+{
+ T a[]{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
+ using It = ItType<T>;
+
+ std::inplace_vector<T, 10> v;
+
+ auto bounds = typename It::ContainerType(a, a+15);
+ v.assign(It(a, &bounds), It(a+5, &bounds));
+ VERIFY( eq<T>(v, {a, 5}) );
+
+ bounds = typename It::ContainerType(a, a+15);
+ v.assign(It(a, &bounds), It(a+7, &bounds));
+ VERIFY( eq<T>(v, {a, 7}) );
+
+ bounds = typename It::ContainerType(a, a+15);
+ v.assign(It(a, &bounds), It(a+3, &bounds));
+ VERIFY( eq<T>(v, {a, 3}) );
+
+ bounds = typename It::ContainerType(a, a+15);
+ v.assign(It(a, &bounds), It(a+10, &bounds));
+ VERIFY( eq<T>(v, {a, 10}) );
+}
+
+template<typename T>
+constexpr void
+test_assign_initializer_list()
+{
+ T a[]{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
+
+ std::inplace_vector<T, 10> v;
+
+ v.assign({T(1), T(2), T(3), T(4), T(5)});
+ VERIFY( eq<T>(v, {a, 5}) );
+
+ v = {T(1), T(2), T(3), T(4), T(5), T(6), T(7)};
+ VERIFY( eq<T>(v, {a, 7}) );
+
+ v.assign({T(1), T(2), T(3)});
+ VERIFY( eq<T>(v, {a, 3}) );
+
+ v = {T(1), T(2), T(3), T(4), T(5), T(6), T(7), T(8), T(9), T(10)};
+ VERIFY( eq<T>(v, {a, 10}) );
+}
+
+template<typename T>
+constexpr void
+test_assign_repeated()
+{
+ auto rep = [](const std::inplace_vector<T, 10>& v, size_t c, const T& t)
+ {
+ if (v.size() != c)
+ return false;
+ for (const T& o : v)
+ if (o != t)
+ return false;
+ return true;
+ };
+
+ std::inplace_vector<T, 10> v;
+
+ v.assign(5, T(1));
+ VERIFY( rep(v, 5, T(1)) );
+
+ v.assign(7, T(2));
+ VERIFY( rep(v, 7, T(2)) );
+
+ v.assign(3, T(4));
+ VERIFY( rep(v, 3, T(4)) );
+
+ v.assign(10, T(8));
+ VERIFY( rep(v, 10, T(8)) );
+}
+
+template<typename T>
+constexpr void
+test_resize()
+{
+ T a[]{1,1,1,1,2,2,2,0,0,0};
+
+ std::inplace_vector<T, 10> v;
+
+ v.resize(4, T(1));
+ VERIFY( eq<T>(v, {a, 4}) );
+
+ v.resize(7, T(2));
+ VERIFY( eq<T>(v, {a, 7}) );
+
+ v.resize(10);
+ VERIFY( eq<T>(v, {a, 10}) );
+
+ v.resize(6, T(1));
+ VERIFY( eq<T>(v, {a, 6}) );
+}
+
+template<typename T>
+constexpr void
+test_assigns()
+{
+ using namespace __gnu_test;
+ test_assign_range<test_forward_range<int>>();
+ test_assign_range<test_sized_range_sized_sent<int, forward_iterator_wrapper>>();
+
+ test_assign_range<test_input_range<int>>();
+ test_assign_range<test_input_sized_range<int>>();
+ test_assign_range<test_sized_range_sized_sent<int, input_iterator_wrapper>>();
+
+ test_assign_range<test_range<int, input_iterator_wrapper_nocopy>>();
+ test_assign_range<test_sized_range<int, input_iterator_wrapper_nocopy>>();
+ test_assign_range<test_sized_range_sized_sent<int, input_iterator_wrapper_nocopy>>();
+
+ test_assign_iterators<T, input_iterator_wrapper>();
+ test_assign_iterators<T, forward_iterator_wrapper>();
+ test_assign_iterators<T, random_access_iterator_wrapper>();
+
+ test_assign_initializer_list<T>();
+ test_assign_repeated<T>();
+ test_resize<T>();
+}
+
+int main()
+{
+ auto test_all = [] {
+ test_assign_empty<0, int>();
+ test_assign_empty<0, X>();
+ test_assign_empty<2, int>();
+
+ test_assigns<int>();
+#ifdef __cpp_lib_constexpr_inplace_vector
+#error uncomemnt test_inserts<X>()
+#endif
+ if !consteval {
+ test_assign_empty<2, X>();
+ test_assigns<X>();
+ }
+ return true;
+ };
+
+
+ test_all();
+ static_assert(test_all());
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/erase.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/erase.cc
new file mode 100644
index 0000000..8b82ab4
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/erase.cc
@@ -0,0 +1,117 @@
+// { dg-do run { target c++26 } }
+
+#include <inplace_vector>
+
+#include <span>
+#include <testsuite_hooks.h>
+
+struct X
+{
+ X() = default;
+ constexpr X(int p) : v(p) {}
+ constexpr X(const X& o) : v(o.v) { } // not trivial
+ constexpr X& operator=(const X& o) // not trivial
+ { v = o.v; return *this; }
+
+ int v;
+
+ friend auto operator<=>(const X&, const X&) = default;
+};
+
+template<typename T, typename V, size_t N>
+constexpr bool
+eq(const std::inplace_vector<V, N>& l, std::span<const 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;
+};
+
+template<typename T, typename V, size_t N>
+constexpr bool
+eq(const std::inplace_vector<V, N>& l, std::initializer_list<T> r)
+{ return eq<T>(l, std::span<const T>(r)); }
+
+template<size_t N, typename T>
+constexpr void
+test_erase_all_or_none()
+{
+ using namespace __gnu_test;
+
+ T a[]{1,2,3,4,5,6,7,8,9};
+ const T c(10);
+
+ std::inplace_vector<T, N> src(std::from_range, std::span(a, a+N));
+ std::inplace_vector<T, N> v;
+
+ v = src;
+ auto it = v.erase(v.begin(), v.begin());
+ VERIFY( it == v.begin() );
+ VERIFY( eq<T>(v, {a, N}) );
+
+ it = v.erase(v.end(), v.end());
+ VERIFY( it == v.end() );
+ VERIFY( eq<T>(v, {a, N}) );
+
+ it = v.erase(v.begin(), v.end());
+ VERIFY( it == v.begin() );
+ VERIFY( v.empty() );
+
+ v = src;
+ v.clear();
+ VERIFY( v.empty() );
+}
+
+template<typename T>
+constexpr void
+test_erase()
+{
+ std::inplace_vector<T, 10> v{T(1), T(2), T(3), T(4), T(5), T(6), T(7)};
+
+ auto it = v.erase(v.begin());
+ VERIFY( eq<T>(v, {T(2), T(3), T(4), T(5), T(6), T(7)}) );
+ VERIFY( it == v.begin() );
+
+ it = v.erase(v.end()-1);
+ VERIFY( eq<T>(v, {T(2), T(3), T(4), T(5), T(6)}) );
+ VERIFY( it == v.end() );
+
+ it = v.erase(v.begin()+2, v.begin()+4);
+ VERIFY( eq<T>(v, {T(2), T(3), T(6)}) );
+ VERIFY( it == v.begin()+2 );
+
+ it = v.erase(v.end()-1, v.end());
+ VERIFY( eq<T>(v, {T(2), T(3)}) );
+ VERIFY( it == v.end() );
+
+ it = v.erase(v.begin(), v.begin()+1);
+ VERIFY( eq<T>(v, {T(3)}) );
+ VERIFY( it == v.begin() );
+
+ v.pop_back();
+ VERIFY( v.empty() );
+}
+
+int main()
+{
+ auto test_all = [] {
+ test_erase_all_or_none<0, int>();
+ test_erase_all_or_none<0, X>();
+
+ test_erase_all_or_none<4, int>();
+
+ test_erase<int>();
+#ifdef __cpp_lib_constexpr_inplace_vector
+#error uncomemnt test_inserts<X>()
+#endif
+ if ! consteval {
+ test_erase_all_or_none<4, X>();
+ }
+ return true;
+ };
+
+ test_all();
+ static_assert(test_all());;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/erase_neg.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/erase_neg.cc
new file mode 100644
index 0000000..a1f43b3
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/erase_neg.cc
@@ -0,0 +1,43 @@
+// { dg-do compile { target c++26 } }
+
+#include <inplace_vector>
+
+template<size_t N, typename T>
+constexpr bool
+test_pop_back_on_empty()
+{
+ std::inplace_vector<T, N> v;
+ v.pop_back(); // { dg-error "in 'constexpr' expansion of" }
+ return true;
+}
+
+template<size_t N, typename T>
+constexpr bool
+test_erase_begin_on_empty()
+{
+ std::inplace_vector<T, N> v;
+ v.erase(v.begin()); // { dg-error "in 'constexpr' expansion of" }
+ return true;
+}
+
+template<size_t N, typename T>
+constexpr bool
+test_erase_end(size_t size = 0)
+{
+ std::inplace_vector<T, N> v(size, T());
+ v.erase(v.end()); // { dg-error "in 'constexpr' expansion of" }
+ return true;
+}
+
+static_assert(test_pop_back_on_empty<0, int>()); // { dg-error "in 'constexpr' expansion of" }
+static_assert(test_pop_back_on_empty<4, int>()); // { dg-error "in 'constexpr' expansion of" }
+static_assert(test_erase_begin_on_empty<0, int>()); // { dg-error "in 'constexpr' expansion of" }
+static_assert(test_erase_begin_on_empty<4, int>()); // { dg-error "in 'constexpr' expansion of" }
+static_assert(test_erase_end<0, int>()); // { dg-error "in 'constexpr' expansion of" }
+static_assert(test_erase_end<4, int>()); // { dg-error "in 'constexpr' expansion of" }
+static_assert(test_erase_end<4, int>(2)); // { dg-error "in 'constexpr' expansion of" }
+static_assert(test_erase_end<4, int>(4)); // { dg-error "in 'constexpr' expansion of" }
+
+// { dg-prune-output "non-constant condition for static assertion" }
+// { dg-prune-output "is not a constant expression" }
+// { dg-prune-output "call to non-'constexpr' function" }
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/multi_insert.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/multi_insert.cc
new file mode 100644
index 0000000..6a5b62f
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/multi_insert.cc
@@ -0,0 +1,606 @@
+// { dg-do run { target c++26 } }
+
+#include <inplace_vector>
+
+#include <span>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+struct X
+{
+ X() = default;
+ constexpr X(int p) : v(p) {}
+ constexpr X(const X& o) : v(o.v) { } // not trivial
+ constexpr X& operator=(const X& o) // not trivial
+ { v = o.v; return *this; }
+
+ int v;
+
+ friend auto operator<=>(const X&, const X&) = default;
+};
+
+template<typename T, typename V, size_t N>
+constexpr bool
+eq(const std::inplace_vector<V, N>& l, std::span<const 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;
+};
+
+template<typename T, typename V, size_t N>
+constexpr bool
+prefix(const std::inplace_vector<V, N>& l, std::span<const T> r) {
+ if (l.size() < r.size())
+ return false;
+ for (auto i = 0u; i < r.size(); ++i)
+ if (l[i] != r[i])
+ return false;
+ return true;
+};
+
+template<size_t N, typename T, template<class TT> class ItType>
+constexpr void
+test_add_to_full_it()
+{
+ using namespace __gnu_test;
+
+ T a[]{1,2,3,4,5,6,7,8,9};
+ using It = ItType<T>;
+ using Range = test_range<T, ItType>;
+ using SizedRange = test_sized_range<T, ItType>;
+
+ std::inplace_vector<T, N> v(std::from_range, std::span(a, a+N));
+
+ Range r1(a, a);
+ auto rit1 = v.try_append_range(r1);
+ VERIFY( eq<T>(v, {a, N}) );
+ VERIFY( rit1.base() == a );
+
+ SizedRange r2(a, a);
+ auto rit2 = v.try_append_range(r2);
+ VERIFY( eq<T>(v, {a, N}) );
+ VERIFY( rit2.base() == a );
+
+ v.append_range(Range(a, a));
+ VERIFY( eq<T>(v, {a, N}) );
+ v.append_range(SizedRange(a, a));
+ VERIFY( eq<T>(v, {a, N}) );
+
+ auto it = v.insert_range(v.end(), Range(a, a));
+ VERIFY( eq<T>(v, {a, N}) );
+ VERIFY( it == v.end() );
+ it = v.insert_range(v.end(), SizedRange(a, a));
+ VERIFY( eq<T>(v, {a, N}) );
+ VERIFY( it == v.end() );
+
+ auto bounds = typename It::ContainerType(a, a+9);
+ it = v.insert(v.end(), It(a, &bounds), It(a, &bounds));
+ VERIFY( eq<T>(v, {a, N}) );
+ VERIFY( it == v.end() );
+
+ it = v.insert_range(v.begin(), SizedRange(a, a));
+ VERIFY( eq<T>(v, {a, N}) );
+ VERIFY( it == v.begin() );
+ it = v.insert_range(v.begin(), Range(a, a));
+ VERIFY( eq<T>(v, {a, N}) );
+ VERIFY( it == v.begin() );
+
+ bounds = typename It::ContainerType(a, a+9);
+ it = v.insert(v.begin(), It(a, &bounds), It(a, &bounds));
+ VERIFY( eq<T>(v, {a, N}) );
+ VERIFY( it == v.begin() );
+
+ // Inserting non-empty range
+ Range r3(a+3, a+5);
+ auto rit3 = v.try_append_range(r3);
+ VERIFY( eq<T>(v, {a, N}) );
+ VERIFY( rit3.base() == a+3 );
+
+ SizedRange r4(a+2, a+5);
+ auto rit4 = v.try_append_range(r4);
+ VERIFY( eq<T>(v, {a, N}) );
+ VERIFY( rit4.base() == a+2 );
+
+#ifdef __cpp_exceptions
+#ifdef __cpp_lib_constexpr_exceptions
+#error remove the consteval check
+#endif
+ if consteval {
+ return;
+ }
+
+ try
+ {
+ v.append_range(Range(a, a + 5));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( eq<T>(v, {a, N}) );
+
+ try
+ {
+ v.append_range(SizedRange(a, a + 5));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( eq<T>(v, {a, N}) );
+
+ try
+ {
+ v.insert_range(v.begin(), SizedRange(a, a+5));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( eq<T>(v, {a, N}) );
+
+ try
+ {
+ v.insert_range(v.begin(), Range(a, a+5));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ auto gn = std::ranges::sized_range<Range> || std::ranges::forward_range<Range> ? N : 0;
+ VERIFY( prefix<T>(v, {a, gn}) );
+
+ v = std::inplace_vector<T, N>(std::from_range, std::span(a, a+N));
+ try
+ {
+ v.insert_range(v.begin(), Range(a, a+5));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ gn = std::forward_iterator<It> ? N : 0;
+ VERIFY( prefix<T>(v, {a, gn}) );
+#endif
+}
+
+template<size_t N, typename T>
+constexpr void
+test_add_to_full_other()
+{
+ using namespace __gnu_test;
+
+ T a[]{1,2,3,4,5,6,7,8,9};
+ std::inplace_vector<T, N> v(std::from_range, std::span(a, a+N));
+
+ auto it = v.insert(v.end(), {});
+ VERIFY( eq<T>(v, {a, N}) );
+ VERIFY( it == v.end() );
+ it = v.insert(v.end(), 0u, T(2));
+ VERIFY( eq<T>(v, {a, N}) );
+ VERIFY( it == v.end() );
+
+ it = v.insert(v.begin(), {});
+ VERIFY( eq<T>(v, {a, N}) );
+ VERIFY( it == v.begin() );
+ it = v.insert(v.begin(), 0u, T(2));
+ VERIFY( eq<T>(v, {a, N}) );
+ VERIFY( it == v.begin() );
+
+#ifdef __cpp_exceptions
+#ifdef __cpp_lib_constexpr_exceptions
+#error remove the consteval check
+#endif
+ if consteval {
+ return;
+ }
+
+ v = std::inplace_vector<T, N>(std::from_range, std::span(a, a+N));
+ try
+ {
+ v.insert(v.begin(), {T(1), T(2), T(3)});
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( eq<T>(v, {a, N}) );
+
+ try
+ {
+ v.insert(v.begin(), 4u, T(3));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( eq<T>(v, {a, N}) );
+#endif
+}
+
+
+template<size_t N, typename T>
+constexpr void
+test_add_to_full()
+{
+ using namespace __gnu_test;
+ test_add_to_full_it<N, T, input_iterator_wrapper>();
+ test_add_to_full_it<N, T, forward_iterator_wrapper>();
+ test_add_to_full_it<N, T, random_access_iterator_wrapper>();
+
+ test_add_to_full_other<N, T>();
+}
+
+template<typename Range>
+constexpr void
+test_append_range()
+{
+ using T = std::ranges::range_value_t<Range>;
+ T a[]{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
+
+ std::inplace_vector<T, 20> v;
+ v.append_range(Range(a,a+10));
+ VERIFY( eq<T>(v, {a, 10}) );
+
+ v.append_range(Range(a+10, a+15));
+ VERIFY( eq<T>(v, {a, 15}) );
+
+#ifdef __cpp_exceptions
+#ifdef __cpp_lib_constexpr_exceptions
+#error remove the consteval check
+#endif
+ if consteval {
+ return;
+ }
+
+ try
+ {
+ v.append_range(Range(a, a+10));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( prefix<T>(v, {a, 15}) );
+#endif
+}
+
+template<typename Range>
+constexpr void
+test_try_append_range()
+{
+ using T = std::ranges::range_value_t<Range>;
+ T a[]{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25};
+
+ std::inplace_vector<T, 20> v;
+ Range r1 = Range(a, a+10);
+ auto it1 = v.try_append_range(r1);
+ VERIFY( eq<T>(v, {a, 10}) );
+ VERIFY( it1.base() == a+10 );
+
+ Range r2 = Range(a+10, a+15);
+ auto it2 = v.try_append_range(r2);
+ VERIFY( eq<T>(v, {a, 15}) );
+ VERIFY( it2.base() == a+15 );
+
+ Range r3 = Range(a+15, a+25);
+ auto it3 = v.try_append_range(r3);
+ VERIFY( eq<T>(v, {a, 20}) );
+ VERIFY( it3.base() == a+20 );
+}
+
+template<typename Range>
+constexpr void
+test_insert_range()
+{
+ using T = std::ranges::range_value_t<Range>;
+ T a[]{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
+
+ std::inplace_vector<T, 20> v;
+ auto it = v.insert_range(v.begin(), Range(a+10,a+15));
+ VERIFY( eq<T>(v, {a+10, 5}) );
+ VERIFY( it == v.begin() );
+
+ it = v.insert_range(v.begin(), Range(a, a+5));
+ VERIFY( prefix<T>(v, {a, 5}) );
+ VERIFY( it == v.begin() );
+
+ it = v.insert_range(v.begin() + 5, Range(a+5, a+10));
+ VERIFY( eq<T>(v, {a, 15}) );
+ VERIFY( it == v.begin() + 5 );
+
+#ifdef __cpp_exceptions
+#ifdef __cpp_lib_constexpr_exceptions
+#error remove the consteval check
+#endif
+ if consteval {
+ return;
+ }
+
+ const bool seg = std::ranges::sized_range<Range> || std::ranges::forward_range<Range>;
+ auto vc = v;
+ try
+ {
+ vc.insert_range(vc.begin(), Range(a, a+10));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( prefix<T>(vc, {a, seg ? 15 : 0}) );
+
+ vc = v;
+ try
+ {
+ vc.insert_range(vc.begin()+5, Range(a, a+10));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( prefix<T>(vc, {a, seg ? 15 : 5}) );
+
+ vc = v;
+ try
+ {
+ vc.insert_range(vc.end(), Range(a, a+10));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( prefix<T>(vc, {a, 15}) );
+#endif
+}
+
+template<typename Range>
+constexpr void
+do_test_ranges()
+{
+ test_append_range<Range>();
+ test_try_append_range<Range>();
+ test_insert_range<Range>();
+}
+
+template<typename T, template<class TT> class ItType>
+constexpr void
+test_insert_iterators()
+{
+ T a[]{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
+ using It = ItType<T>;
+
+ std::inplace_vector<T, 20> v;
+
+ auto bounds = typename It::ContainerType(a, a+15);
+ auto it = v.insert(v.begin(), It(a+10, &bounds), It(a+15, &bounds));
+ VERIFY( eq<T>(v, {a+10, 5}) );
+ VERIFY( it == v.begin() );
+
+ bounds = typename It::ContainerType(a, a+15);
+ it = v.insert(v.begin(), It(a, &bounds), It(a+5, &bounds));
+ VERIFY( prefix<T>(v, {a, 5}) );
+ VERIFY( it == v.begin() );
+
+ bounds = typename It::ContainerType(a, a+15);
+ it = v.insert(v.begin() + 5, It(a+5, &bounds), It(a+10, &bounds));
+ VERIFY( eq<T>(v, {a, 15}) );
+ VERIFY( it == v.begin() + 5 );
+
+#ifdef __cpp_exceptions
+#ifdef __cpp_lib_constexpr_exceptions
+#error remove the consteval check
+#endif
+ if consteval {
+ return;
+ }
+
+ const bool seg = std::forward_iterator<It>;
+ auto vc = v;
+ bounds = typename It::ContainerType(a, a+15);
+ try
+ {
+ vc.insert(vc.begin(), It(a, &bounds), It(a+10, &bounds));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( prefix<T>(vc, {a, seg ? 15 : 0}) );
+
+ vc = v;
+ bounds = typename It::ContainerType(a, a+15);
+ try
+ {
+ vc.insert(vc.begin()+5, It(a, &bounds), It(a+10, &bounds));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( prefix<T>(vc, {a, seg ? 15 : 5}) );
+
+ vc = v;
+ bounds = typename It::ContainerType(a, a+15);
+ try
+ {
+ vc.insert(vc.end(), It(a, &bounds), It(a+10, &bounds));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( prefix<T>(vc, {a, 15}) );
+#endif
+}
+
+template<typename T>
+constexpr void
+test_insert_initializer_list()
+{
+ T a[]{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
+
+ std::inplace_vector<T, 20> v;
+
+ auto it = v.insert(v.begin(), {T(11), T(12), T(13), T(14), T(15)});
+ VERIFY( eq<T>(v, {a+10, 5}) );
+ VERIFY( it == v.begin() );
+
+ it = v.insert(v.begin(), {T(1), T(2), T(3), T(4), T(5)});
+ VERIFY( prefix<T>(v, {a, 5}) );
+ VERIFY( it == v.begin() );
+
+ it = v.insert(v.begin() + 5, {T(6), T(7), T(8), T(9), T(10)});
+ VERIFY( eq<T>(v, {a, 15}) );
+ VERIFY( it == v.begin() + 5 );
+
+#ifdef __cpp_exceptions
+#ifdef __cpp_lib_constexpr_exceptions
+#error remove the consteval check
+#endif
+ if consteval {
+ return;
+ }
+
+ std::initializer_list<T> il
+ = {T(0), T(1), T(2), T(3), T(4), T(5), T(6), T(7), T(8), T(9)};
+
+ try
+ {
+ v.insert(v.begin(), il);
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( eq<T>(v, {a, 15}) );
+
+ try
+ {
+ v.insert(v.begin()+5, il);
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( eq<T>(v, {a, 15}) );
+
+ try
+ {
+ v.insert(v.end(), il);
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( eq<T>(v, {a, 15}) );
+#endif
+}
+
+template<typename T>
+constexpr void
+test_insert_repeated()
+{
+ T a[]{5,5,5,5,5,6,6,6,6,6,7,7,7,7,7};
+
+ std::inplace_vector<T, 20> v;
+
+ auto it = v.insert(v.begin(), 5, T(7));
+ VERIFY( eq<T>(v, {a+10, 5}) );
+ VERIFY( it == v.begin() );
+
+ it = v.insert(v.begin(), 5, T(5));
+ VERIFY( prefix<T>(v, {a, 5}) );
+ VERIFY( it == v.begin() );
+
+ it = v.insert(v.begin() + 5, 5, T(6));
+ VERIFY( eq<T>(v, {a, 15}) );
+ VERIFY( it == v.begin() + 5 );
+
+#ifdef __cpp_exceptions
+#ifdef __cpp_lib_constexpr_exceptions
+#error remove the consteval check
+#endif
+ if consteval {
+ return;
+ }
+
+ try
+ {
+ v.insert(v.begin(), 10u, T(6));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( eq<T>(v, {a, 15}) );
+
+ try
+ {
+ v.insert(v.begin()+5, 10u, T(6));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( eq<T>(v, {a, 15}) );
+
+ try
+ {
+ v.insert(v.end(), 10u, T(6));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( eq<T>(v, {a, 15}) );
+#endif
+}
+
+template<typename T>
+constexpr void
+test_inserts()
+{
+ using namespace __gnu_test;
+ do_test_ranges<test_forward_range<int>>();
+ do_test_ranges<test_sized_range_sized_sent<int, forward_iterator_wrapper>>();
+
+ do_test_ranges<test_input_range<int>>();
+ do_test_ranges<test_input_sized_range<int>>();
+ do_test_ranges<test_sized_range_sized_sent<int, input_iterator_wrapper>>();
+
+ do_test_ranges<test_range<int, input_iterator_wrapper_nocopy>>();
+ do_test_ranges<test_sized_range<int, input_iterator_wrapper_nocopy>>();
+ do_test_ranges<test_sized_range_sized_sent<int, input_iterator_wrapper_nocopy>>();
+
+ test_insert_iterators<T, input_iterator_wrapper>();
+ test_insert_iterators<T, forward_iterator_wrapper>();
+ test_insert_iterators<T, random_access_iterator_wrapper>();
+
+test_insert_initializer_list<T>();
+test_insert_repeated<T>();
+}
+
+int main()
+{
+auto test_all = []{
+ test_add_to_full<0, int>();
+ test_add_to_full<0, X>();
+ test_add_to_full<4, int>();
+
+ test_inserts<int>();
+#ifdef __cpp_lib_constexpr_inplace_vector
+#error uncomemnt test_inserts<X>()
+#endif
+ if !consteval {
+ test_add_to_full<4, X>();
+ test_inserts<X>();
+ }
+ return true;
+ };
+
+ test_all();
+ static_assert(test_all());
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/single_insert.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/single_insert.cc
new file mode 100644
index 0000000..d5e893c
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/single_insert.cc
@@ -0,0 +1,215 @@
+// { dg-do run { target c++26 } }
+
+#include <inplace_vector>
+
+#include <span>
+#include <testsuite_hooks.h>
+
+struct X
+{
+ X() = default;
+ constexpr X(int p) : v(p) {}
+ constexpr X(const X& o) : v(o.v) { } // not trivial
+ constexpr X& operator=(const X& o) // not trivial
+ { v = o.v; return *this; }
+
+ int v;
+
+ friend auto operator<=>(const X&, const X&) = default;
+};
+
+template<typename T, typename V, size_t N>
+constexpr bool
+eq(const std::inplace_vector<V, N>& l, std::span<const 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;
+};
+
+template<size_t N, typename T>
+constexpr void
+test_add_to_full()
+{
+ using namespace __gnu_test;
+
+ T a[]{1,2,3,4,5,6,7,8,9};
+ const T c(10);
+
+ std::inplace_vector<T, N> v(std::from_range, std::span(a, a+N));
+
+ VERIFY( v.try_emplace_back(1) == nullptr );
+ VERIFY( eq<T>(v, {a, N}) );
+ VERIFY( v.try_push_back(T(1)) == nullptr );
+ VERIFY( eq<T>(v, {a, N}) );
+ VERIFY( v.try_push_back(c) == nullptr );
+ VERIFY( eq<T>(v, {a, N}) );
+
+#ifdef __cpp_exceptions
+#ifdef __cpp_lib_constexpr_exceptions
+#error remove the consteval check
+#endif
+ if consteval {
+ return;
+ }
+
+ try
+ {
+ v.emplace_back(1);
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( eq<T>(v, {a, N}) );
+
+ try
+ {
+ v.push_back(T(1));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( eq<T>(v, {a, N}) );
+
+ try
+ {
+ v.push_back(c);
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( eq<T>(v, {a, N}) );
+
+ try
+ {
+ v.insert(v.end(), T(1));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( eq<T>(v, {a, N}) );
+
+ try
+ {
+ v.insert(v.begin(), c);
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( eq<T>(v, {a, N}) );
+
+ try
+ {
+ v.emplace(v.end(), c);
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( eq<T>(v, {a, N}) );
+
+ try
+ {
+ v.emplace(v.begin(), T(2));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( eq<T>(v, {a, N}) );
+#endif
+}
+
+template<typename T>
+constexpr void
+test_inserts()
+{
+ T a[]{3,14,13,1,2,3,4,5,3,7,8,3,10,11,3};
+ const T c(3);
+
+ std::inplace_vector<T, 20> v;
+
+ v.emplace_back(1);
+ VERIFY( eq<T>(v, {a+3, 1}) );
+ v.push_back(T(2));
+ VERIFY( eq<T>(v, {a+3, 2}) );
+ v.push_back(c);
+ VERIFY( eq<T>(v, {a+3, 3}) );
+
+ v.unchecked_emplace_back(4);
+ VERIFY( eq<T>(v, {a+3, 4}) );
+ v.unchecked_push_back(T(5));
+ VERIFY( eq<T>(v, {a+3, 5}) );
+ v.unchecked_push_back(c);
+ VERIFY( eq<T>(v, {a+3, 6}) );
+
+ T* ptr = v.try_emplace_back(7);
+ VERIFY( eq<T>(v, {a+3, 7}) );
+ VERIFY( ptr = &v.back() );
+ ptr = v.try_push_back(T(8));
+ VERIFY( eq<T>(v, {a+3, 8}) );
+ VERIFY( ptr = &v.back() );
+ ptr = v.try_push_back(c);
+ VERIFY( eq<T>(v, {a+3, 9}) );
+ VERIFY( ptr = &v.back() );
+
+ auto it = v.emplace(v.end(), 10);
+ VERIFY( eq<T>(v, {a+3, 10}) );
+ VERIFY( it == v.end()-1 );
+ it = v.insert(v.end(), T(11));
+ VERIFY( eq<T>(v, {a+3, 11}) );
+ VERIFY( it == v.end()-1 );
+ it = v.insert(v.end(), c);
+ VERIFY( eq<T>(v, {a+3, 12}) );
+ VERIFY( it == v.end()-1 );
+
+ it = v.emplace(v.begin(), 13);
+ VERIFY( eq<T>(v, {a+2, 13}) );
+ VERIFY( it == v.begin() );
+ it = v.insert(v.begin(), T(14));
+ VERIFY( eq<T>(v, {a+1, 14}) );
+ VERIFY( it == v.begin() );
+ it = v.insert(v.begin(), c);
+ VERIFY( eq<T>(v, {a+0, 15}) );
+ VERIFY( it == v.begin() );
+
+ it = v.emplace(v.begin()+2, 22);
+ VERIFY( *it == 22 );
+ VERIFY( it == v.begin()+2 );
+ it = v.insert(v.begin()+6, T(24));
+ VERIFY( *it == 24 );
+ VERIFY( it == v.begin()+6 );
+ it = v.insert(v.begin()+13, c);
+ VERIFY( *it == 3 );
+ VERIFY( it == v.begin()+13 );
+}
+
+int main()
+{
+ auto test_all = [] {
+ test_add_to_full<0, int>();
+ test_add_to_full<0, X>();
+
+ test_add_to_full<4, int>();
+
+ test_inserts<int>();
+#ifdef __cpp_lib_constexpr_inplace_vector
+#error uncomemnt test_inserts<X>()
+#endif
+ if ! consteval {
+ test_add_to_full<4, X>();
+ test_inserts<X>();
+ }
+ return true;
+ };
+
+ test_all();
+ static_assert(test_all());;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/single_insert_neg.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/single_insert_neg.cc
new file mode 100644
index 0000000..0552b8c
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/single_insert_neg.cc
@@ -0,0 +1,42 @@
+// { dg-do compile { target c++26 } }
+
+#include <inplace_vector>
+
+template<size_t N, typename T>
+constexpr bool
+test_unchecked_emplace_back()
+{
+ std::inplace_vector<T, N> v(N, T(1));
+ v.unchecked_emplace_back(); // { dg-error "in 'constexpr' expansion of" }
+ return true;
+}
+
+template<size_t N, typename T>
+constexpr bool
+test_push_back_lvalue()
+{
+ auto val = T();;
+ std::inplace_vector<T, N> v(N, T(1));
+ v.unchecked_push_back(val); // { dg-error "in 'constexpr' expansion of" }
+ return true;
+}
+
+template<size_t N, typename T>
+constexpr bool
+test_push_back_rvalue()
+{
+ std::inplace_vector<T, N> v(N, T(1));
+ v.unchecked_push_back(T()); // { dg-error "in 'constexpr' expansion of" }
+ return true;
+}
+
+static_assert(test_unchecked_emplace_back<0, int>()); // { dg-error "in 'constexpr' expansion of" }
+static_assert(test_unchecked_emplace_back<4, int>()); // { dg-error "in 'constexpr' expansion of" }
+static_assert(test_push_back_lvalue<0, int>()); // { dg-error "in 'constexpr' expansion of" }
+static_assert(test_push_back_lvalue<4, int>()); // { dg-error "in 'constexpr' expansion of" }
+static_assert(test_push_back_rvalue<0, int>()); // { dg-error "in 'constexpr' expansion of" }
+static_assert(test_push_back_rvalue<4, int>()); // { dg-error "in 'constexpr' expansion of" }
+
+// { dg-prune-output "non-constant condition for static assertion" }
+// { dg-prune-output "is not a constant expression" }
+// { dg-prune-output "call to non-'constexpr' function" }
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/move.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/move.cc
new file mode 100644
index 0000000..e8703e0
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/move.cc
@@ -0,0 +1,362 @@
+// { dg-do run { target c++26 } }
+
+#include <inplace_vector>
+#include <ranges>
+#include <testsuite_hooks.h>
+
+struct X
+{
+ X() = default;
+ constexpr X(int p) : v(p) {}
+ constexpr X(const X& o) : v(o.v) { } // not trivial
+ constexpr X(X&& o) : v(o.v) { } // not trivial
+
+ constexpr X& operator=(const X& o) // not trivial
+ { v = o.v; return *this; }
+ constexpr X& operator=(X&& o) // not trivial
+ { v = o.v; return *this; }
+
+ int v;
+
+ friend auto operator<=>(const X&, const X&) = default;
+};
+
+template<bool CNoex, bool ANoex>
+struct N
+{
+ N() = default;
+ constexpr N(N&&) noexcept(CNoex) { } // not trivial
+ constexpr N& operator=(N&& o) noexcept(ANoex) // not trivial
+ { return *this; }
+};
+
+struct D
+{
+ D() = default;
+ D(D&&) = default;
+ D& operator=(D&&) = default;
+ ~D() {} // not trivially destructible
+};
+
+struct U
+{
+ U() = default;
+ U(U&&) noexcept(false) = default; // lies about noexcept, is trivial but throwing
+ U& operator=(U&&) noexcept(false) = default; // lies about noexcept, is trivial but throwing
+};
+
+template<bool SNoex, bool CNoex, bool ANoex>
+struct S {
+ S() = default;
+ constexpr S(S&&) noexcept(CNoex) { } // not trivial
+ constexpr S& operator=(S&& o) noexcept(ANoex) // not trivial
+ { return *this; }
+
+ friend constexpr
+ void swap(S&, S&) noexcept(SNoex) {}
+};
+
+// n5008 inplace.vector.overview says for inplace_vector<T, 0>
+// provides trivial copy/move/default cosntructpr regardless of T
+struct Z
+{
+ Z(const Z&) = delete;
+ Z& operator=(const Z&) = delete;
+};
+
+template<size_t N, typename T>
+ constexpr std::inplace_vector<T, N>
+ materialize(std::initializer_list<int> il)
+ {
+ std::inplace_vector<T, N> res;
+ for (int x : il)
+ res.emplace_back(x);
+ return res;
+ }
+
+static_assert(std::is_move_constructible_v<std::inplace_vector<int, 2>>);
+static_assert(std::is_move_constructible_v<std::inplace_vector<X, 2>>);
+static_assert(std::is_move_constructible_v<std::inplace_vector<N<false, false>, 2>>);
+static_assert(std::is_move_constructible_v<std::inplace_vector<D, 2>>);
+static_assert(std::is_move_constructible_v<std::inplace_vector<U, 2>>);
+// The operators are not constrained, as for any other container
+static_assert(std::is_move_constructible_v<std::inplace_vector<Z, 2>>);
+
+static_assert(std::is_nothrow_move_constructible_v<std::inplace_vector<int, 2>>);
+static_assert(!std::is_nothrow_move_constructible_v<std::inplace_vector<X, 2>>);
+static_assert(std::is_nothrow_move_constructible_v<std::inplace_vector<N<true, true>, 2>>);
+static_assert(std::is_nothrow_move_constructible_v<std::inplace_vector<N<true, false>, 2>>);
+static_assert(!std::is_nothrow_move_constructible_v<std::inplace_vector<N<false, true>, 2>>);
+static_assert(!std::is_nothrow_move_constructible_v<std::inplace_vector<N<false, false>, 2>>);
+static_assert(std::is_nothrow_move_constructible_v<std::inplace_vector<D, 2>>);
+static_assert(!std::is_nothrow_move_constructible_v<std::inplace_vector<U, 2>>);
+
+#if !_GLIBCXX_DEBUG
+static_assert(std::is_trivially_move_constructible_v<std::inplace_vector<int, 2>>);
+static_assert(!std::is_trivially_move_constructible_v<std::inplace_vector<X, 2>>);
+static_assert(!std::is_trivially_move_constructible_v<std::inplace_vector<N<true, true>, 2>>);
+// is_trivially_move_constructible_v checks destructor
+static_assert(!std::is_trivially_move_constructible_v<std::inplace_vector<D, 2>>);
+static_assert(std::is_trivially_move_constructible_v<std::inplace_vector<U, 2>>);
+#endif
+
+static_assert(std::is_move_assignable_v<std::inplace_vector<int, 2>>);
+static_assert(std::is_move_assignable_v<std::inplace_vector<X, 2>>);
+static_assert(std::is_move_assignable_v<std::inplace_vector<N<false, false>, 2>>);
+static_assert(std::is_move_assignable_v<std::inplace_vector<D, 2>>);
+static_assert(std::is_move_assignable_v<std::inplace_vector<U, 2>>);
+// The operators are not constrained, as for any other container
+static_assert(std::is_move_assignable_v<std::inplace_vector<Z, 2>>);
+
+static_assert(std::is_nothrow_move_assignable_v<std::inplace_vector<int, 2>>);
+static_assert(!std::is_nothrow_move_assignable_v<std::inplace_vector<X, 2>>);
+static_assert(std::is_nothrow_move_assignable_v<std::inplace_vector<N<true, true>, 2>>);
+static_assert(!std::is_nothrow_move_assignable_v<std::inplace_vector<N<true, false>, 2>>);
+static_assert(!std::is_nothrow_move_assignable_v<std::inplace_vector<N<false, true>, 2>>);
+static_assert(!std::is_nothrow_move_assignable_v<std::inplace_vector<N<false, false>, 2>>);
+static_assert(std::is_nothrow_move_assignable_v<std::inplace_vector<D, 2>>);
+static_assert(!std::is_nothrow_move_assignable_v<std::inplace_vector<U, 2>>);
+
+#if !_GLIBCXX_DEBUG
+static_assert(std::is_trivially_move_assignable_v<std::inplace_vector<int, 2>>);
+static_assert(!std::is_trivially_move_assignable_v<std::inplace_vector<X, 2>>);
+static_assert(!std::is_trivially_move_assignable_v<std::inplace_vector<N<true, true>, 2>>);
+// destructor is not trivial
+static_assert(!std::is_trivially_move_assignable_v<std::inplace_vector<D, 2>>);
+static_assert(std::is_trivially_move_assignable_v<std::inplace_vector<U, 2>>);
+#endif
+
+static_assert(std::is_nothrow_swappable_v<std::inplace_vector<int, 2>>);
+static_assert(!std::is_nothrow_swappable_v<std::inplace_vector<X, 2>>);
+static_assert(std::is_nothrow_swappable_v<std::inplace_vector<N<true, true>, 2>>);
+static_assert(!std::is_nothrow_swappable_v<std::inplace_vector<N<true, false>, 2>>);
+static_assert(!std::is_nothrow_swappable_v<std::inplace_vector<N<false, true>, 2>>);
+static_assert(!std::is_nothrow_swappable_v<std::inplace_vector<N<false, false>, 2>>);
+static_assert(std::is_nothrow_swappable_v<std::inplace_vector<S<true, true, true>, 2>>);
+static_assert(std::is_nothrow_swappable_v<std::inplace_vector<S<true, true, false>, 2>>);
+static_assert(!std::is_nothrow_swappable_v<std::inplace_vector<S<true, false, true>, 2>>);
+static_assert(!std::is_nothrow_swappable_v<std::inplace_vector<S<true, false, false>, 2>>);
+static_assert(!std::is_nothrow_swappable_v<std::inplace_vector<S<false, true, false>, 2>>);
+static_assert(!std::is_nothrow_swappable_v<std::inplace_vector<S<false, false, false>, 2>>);
+static_assert(std::is_nothrow_swappable_v<std::inplace_vector<D, 2>>);
+static_assert(!std::is_nothrow_swappable_v<std::inplace_vector<U, 2>>);
+
+static_assert(std::is_nothrow_move_constructible_v<std::inplace_vector<int, 0>>);
+static_assert(std::is_nothrow_move_constructible_v<std::inplace_vector<X, 0>>);
+static_assert(std::is_nothrow_move_constructible_v<std::inplace_vector<N<false, false>, 0>>);
+static_assert(std::is_nothrow_move_constructible_v<std::inplace_vector<D, 0>>);
+static_assert(std::is_nothrow_move_constructible_v<std::inplace_vector<U, 0>>);
+static_assert(std::is_nothrow_move_constructible_v<std::inplace_vector<Z, 0>>);
+
+static_assert(std::is_trivially_move_constructible_v<std::inplace_vector<int, 0>>);
+static_assert(std::is_trivially_move_constructible_v<std::inplace_vector<X, 0>>);
+static_assert(std::is_trivially_move_constructible_v<std::inplace_vector<D, 0>>);
+static_assert(std::is_trivially_move_constructible_v<std::inplace_vector<U, 0>>);
+static_assert(std::is_trivially_move_constructible_v<std::inplace_vector<Z, 0>>);
+
+static_assert(std::is_nothrow_move_assignable_v<std::inplace_vector<int, 0>>);
+static_assert(std::is_nothrow_move_assignable_v<std::inplace_vector<X, 0>>);
+static_assert(std::is_nothrow_move_assignable_v<std::inplace_vector<N<false, false>, 0>>);
+static_assert(std::is_nothrow_move_assignable_v<std::inplace_vector<D, 0>>);
+static_assert(std::is_nothrow_move_assignable_v<std::inplace_vector<U, 0>>);
+static_assert(std::is_nothrow_move_assignable_v<std::inplace_vector<Z, 0>>);
+
+static_assert(std::is_trivially_move_assignable_v<std::inplace_vector<int, 0>>);
+static_assert(std::is_trivially_move_assignable_v<std::inplace_vector<X, 0>>);
+static_assert(std::is_trivially_move_assignable_v<std::inplace_vector<N<false, false>, 0>>);
+static_assert(std::is_trivially_move_assignable_v<std::inplace_vector<D, 0>>);
+static_assert(std::is_trivially_move_assignable_v<std::inplace_vector<U, 0>>);
+static_assert(std::is_trivially_move_assignable_v<std::inplace_vector<Z, 0>>);
+
+static_assert(std::is_nothrow_swappable_v<std::inplace_vector<int, 0>>);
+static_assert(std::is_nothrow_swappable_v<std::inplace_vector<X, 0>>);
+static_assert(std::is_nothrow_swappable_v<std::inplace_vector<N<false, false>, 0>>);
+static_assert(std::is_nothrow_swappable_v<std::inplace_vector<D, 0>>);
+static_assert(std::is_nothrow_swappable_v<std::inplace_vector<U, 0>>);
+static_assert(std::is_nothrow_swappable_v<std::inplace_vector<Z, 0>>);
+
+template<typename T, size_t N>
+constexpr bool
+eq(const std::inplace_vector<T, N>& s, std::span<const T> o)
+{ return std::ranges::equal(s, o); }
+
+constexpr void
+test_ctor()
+{
+ auto e0 = materialize<0, int>({});
+ VERIFY( e0.empty() );
+ auto e1 = materialize<0, X>({});
+ VERIFY( e1.empty() );
+ auto e2 = materialize<0, Z>({});
+ VERIFY( e2.empty() );
+
+ auto c0 = materialize<5, int>({});
+ VERIFY( c0.empty() );
+
+ auto c3 = materialize<5, int>({1, 2, 3});
+ VERIFY( eq(c3, {1, 2, 3}) );
+
+ auto c5 = materialize<5, int>({1, 2, 3, 4, 5});
+ VERIFY( eq(c5, {1, 2, 3, 4, 5}) );
+
+#ifdef __cpp_lib_constexpr_inplace_vector
+#error remove the consteval check
+#endif
+ if consteval {
+ return;
+ }
+
+ auto x0 = materialize<3, X>({});
+ VERIFY( x0.empty() );
+
+ auto x2 = materialize<3, X>({1, 2});
+ VERIFY( eq(x2, {1, 2}) );
+
+ auto x3 = materialize<3, X>({1, 2, 3});
+ VERIFY( eq(x3, {1, 2, 3}) );
+}
+
+constexpr void
+test_assign()
+{
+ std::inplace_vector<int, 0> e0;
+ e0 = materialize<0, int>({});
+ VERIFY( e0.empty() );
+ std::inplace_vector<X, 0> e1;
+ e1 = materialize<0, X>({});
+ VERIFY( e1.empty() );
+ std::inplace_vector<Z, 0> e2;
+ e2 = materialize<0, Z>({});
+ VERIFY( e2.empty() );
+
+ std::inplace_vector<int, 5> c;
+ c = materialize<5, int>({});
+ VERIFY( c.empty() );
+
+ c = materialize<5, int>({1, 2, 3});
+ VERIFY( eq(c, {1, 2, 3}) );
+
+ c = materialize<5, int>({1, 2, 3, 4, 5});
+ VERIFY( eq(c, {1, 2, 3, 4, 5}) );
+
+ c = materialize<5, int>({4, 5});
+ VERIFY( eq(c, {4, 5}) );
+
+ c = materialize<5, int>({});
+ VERIFY( c.empty() );
+
+#ifdef __cpp_lib_constexpr_inplace_vector
+#error remove the consteval check
+#endif
+ if consteval {
+ return;
+ }
+
+ std::inplace_vector<X, 5> x;
+ x = materialize<5, X>({});
+ VERIFY( x.empty() );
+
+ x = materialize<5, X>({1, 2, 3});
+ VERIFY( eq(x, {1, 2, 3}) );
+
+ x = materialize<5, X>({1, 2, 3, 4, 5});
+ VERIFY( eq(x, {1, 2, 3, 4, 5}) );
+
+ x = materialize<5, X>({4, 5});
+ VERIFY( eq(x, {4, 5}) );
+
+ x = materialize<5, X>({});
+ VERIFY( x.empty() );
+}
+
+constexpr void
+test_swap()
+{
+ std::inplace_vector<int, 0> e0a, e0b;
+ swap(e0a, e0b);
+ VERIFY( e0a.empty() );
+ VERIFY( e0b.empty() );
+ e0a.swap(e0b);
+ VERIFY( e0a.empty() );
+ VERIFY( e0b.empty() );
+
+ std::inplace_vector<X, 0> e1a, e1b;
+ swap(e1a, e1b);
+ VERIFY( e1a.empty() );
+ VERIFY( e1b.empty() );
+ e1a.swap(e1b);
+ VERIFY( e1a.empty() );
+ VERIFY( e1b.empty() );
+
+ std::inplace_vector<Z, 0> e2a, e2b;
+ swap(e2a, e2b);
+ VERIFY( e2a.empty() );
+ VERIFY( e2b.empty() );
+ e2a.swap(e2b);
+ VERIFY( e2a.empty() );
+ VERIFY( e2b.empty() );
+
+ std::inplace_vector<int, 5> c0;
+ std::inplace_vector<int, 5> c3{1, 2, 3};
+ std::inplace_vector<int, 5> c5{1, 2, 3, 4, 5};
+
+ swap(c0, c3);
+ VERIFY( c3.empty() );
+ VERIFY( eq(c0, {1, 2, 3}) );
+ c0.swap(c3);
+ VERIFY( c0.empty() );
+ VERIFY( eq(c3, {1, 2, 3}) );
+
+ swap(c3, c5);
+ VERIFY( eq(c5, {1, 2, 3}) );
+ VERIFY( eq(c3, {1, 2, 3, 4, 5}) );
+ c5.swap(c3);
+ VERIFY( eq(c3, {1, 2, 3}) );
+ VERIFY( eq(c5, {1, 2, 3, 4, 5}) );
+
+#ifdef __cpp_lib_constexpr_inplace_vector
+#error remove the consteval check
+#endif
+ if consteval {
+ return;
+ }
+
+ std::inplace_vector<X, 5> x0;
+ std::inplace_vector<X, 5> x3 = {1, 2, 3};
+ std::inplace_vector<X, 5> x5 = {1, 2, 3, 4, 5};
+
+ swap(x0, x3);
+ VERIFY( x3.empty() );
+ VERIFY( eq(x0, {1, 2, 3}) );
+ x0.swap(x3);
+ VERIFY( x0.empty() );
+ VERIFY( eq(x3, {1, 2, 3}) );
+
+ swap(x3, x5);
+ VERIFY( eq(x5, {1, 2, 3}) );
+ VERIFY( eq(x3, {1, 2, 3, 4, 5}) );
+ x5.swap(x3);
+ VERIFY( eq(x3, {1, 2, 3}) );
+ VERIFY( eq(x5, {1, 2, 3, 4, 5}) );
+}
+
+constexpr auto e0 = materialize<0, int>({});
+constexpr auto e1 = materialize<0, X>({});
+constexpr auto e2 = materialize<0, Z>({});
+
+constexpr auto t1 = materialize<3, int>({});
+constexpr auto t2 = materialize<3, int>({1, 2});
+constexpr auto t3 = materialize<3, int>({11, 22, 33});
+
+int main()
+{
+ auto tests = [] {
+ test_ctor();
+ test_assign();
+ test_swap();
+ return true;
+ };
+
+ tests();
+ constexpr bool _ = tests();
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/relops.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/relops.cc
new file mode 100644
index 0000000..f9c5ce9
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/relops.cc
@@ -0,0 +1,60 @@
+// { dg-do run { target c++26 } }
+
+#include <inplace_vector>
+
+#include <span>
+#include <testsuite_hooks.h>
+
+template<size_t N, typename T>
+constexpr void
+test_equal(size_t c)
+{
+ T a[]{1, 2, 3, 4, 5, 6, 7, 8, 9};
+ std::inplace_vector<T, N> v(a, a+c);
+ VERIFY( v == v );
+ VERIFY( !(v != v) );
+ VERIFY( !(v < v) );
+ VERIFY( !(v > v) );
+ VERIFY( v <= v );
+ VERIFY( v >= v );
+ VERIFY( (v <=> v) == 0 );
+}
+
+template<typename T>
+constexpr void
+test_not_equal()
+{
+ std::inplace_vector<T, 10> v3l{T{1}, T{2}, T{3}};
+ std::inplace_vector<T, 10> v3g{T{1}, T{3}, T{3}};
+ VERIFY( !(v3l == v3g) );
+ VERIFY( v3l != v3g );
+ VERIFY( v3l < v3g );
+ VERIFY( !(v3l > v3g) );
+ VERIFY( v3l <= v3g );
+ VERIFY( !(v3l >= v3g) );
+ VERIFY( (v3l <=> v3g) < 0 );
+
+ std::inplace_vector<T, 10> v2{T{1}, T{2}};
+ VERIFY( !(v2 == v3l) );
+ VERIFY( v2 != v3l );
+ VERIFY( v2 < v3l );
+ VERIFY( !(v2 > v3l) );
+ VERIFY( v2 <= v3l );
+ VERIFY( !(v2 >= v3l) );
+ VERIFY( (v2 <=> v3l) < 0 );
+}
+
+int main()
+{
+ auto test_all = [] {
+ test_equal<0, int>(0);
+ test_equal<4, int>(0);
+ test_equal<4, int>(2);
+ test_equal<4, int>(4);
+ test_not_equal<int>();
+ return true;
+ };
+
+ test_all();
+ static_assert(test_all());;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/version.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/version.cc
new file mode 100644
index 0000000..a5bbdb8
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/version.cc
@@ -0,0 +1,20 @@
+// { dg-do preprocess { target c++26 } }
+// { dg-add-options no_pch }
+
+#include <inplace_vector>
+
+#ifndef __cpp_lib_inplace_vector
+# error "Feature-test macro for inplace_vector missing in <inplace_vector>"
+#elif __cpp_lib_inplace_vector != 202406L
+# error "Feature-test macro for inplace_vector has wrong value in <inplace_vector>"
+#endif
+
+#undef __cpp_lib_inplace_vector
+
+#include <version>
+
+#ifndef __cpp_lib_inplace_vector
+# error "Feature-test macro for inplace_vector missing in <version>"
+#elif __cpp_lib_inplace_vector != 202406L
+# error "Feature-test macro for inplace_vector has wrong value in <version>"
+#endif
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/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 9935f44..1453900 100644
--- a/libstdc++-v3/testsuite/23_containers/map/cons/from_range.cc
+++ b/libstdc++-v3/testsuite/23_containers/map/cons/from_range.cc
@@ -43,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);
@@ -61,7 +61,7 @@ constexpr bool is_equal(std::less<T>, std::less<U>)
{ return true; }
constexpr bool is_equal(StateCmp lhs, StateCmp rhs)
-{ return lhs.state = rhs.state; }
+{ return lhs.state == rhs.state; }
constexpr auto get0 = [](auto const& t) {
using std::get;
@@ -103,12 +103,12 @@ do_test(Alloc alloc, Cmp cmp)
std::map<K, V, Cmp, Alloc> m4(std::from_range, Range(a, a+4), cmp);
VERIFY( eq(m4, {a, 4}) );
VERIFY( m4.get_allocator() == Alloc() );
- VERIFY( is_equal(m4.key_comp(), Cmp()) );
+ VERIFY( is_equal(m4.key_comp(), cmp) );
std::map<K, V, Cmp, Alloc> m9(std::from_range, Range(a, a+9), alloc);
VERIFY( eq(m9, {a, 9}) );
VERIFY( m9.get_allocator() == alloc );
- VERIFY( is_equal(m9.key_comp(), cmp) );
+ VERIFY( is_equal(m9.key_comp(), Cmp()) );
std::map<K, V, Cmp, Alloc> mr(std::from_range, Range(a, a+14), cmp, alloc);
VERIFY( eq(mr, {a, 9}) );
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/accessors/aligned_neg.cc b/libstdc++-v3/testsuite/23_containers/mdspan/accessors/aligned_neg.cc
new file mode 100644
index 0000000..f36ebb1
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/accessors/aligned_neg.cc
@@ -0,0 +1,33 @@
+// { dg-do compile { target c++26 } }
+#include<mdspan>
+
+#include <cstdint>
+
+std::aligned_accessor<uint32_t, 0> a; // { dg-error "required from here" }
+std::aligned_accessor<uint32_t, 7> b; // { dg-error "required from here" }
+std::aligned_accessor<uint32_t, size_t(-1)> c; // { dg-error "required from here" }
+
+std::aligned_accessor<uint32_t, 2> d; // { dg-error "required from here" }
+
+std::aligned_accessor<int[2], 32> e; // { dg-error "required from here" }
+
+class Abstract
+{
+ virtual void
+ foo() const = 0;
+};
+
+class Derived : public Abstract
+{
+ void
+ foo() const override
+ { }
+};
+
+std::aligned_accessor<Derived, alignof(int)> f_ok;
+std::aligned_accessor<Abstract, alignof(int)> f_err; // { dg-error "required from here" }
+
+// { dg-prune-output "ByteAlignment must be a power of two" }
+// { dg-prune-output "ElementType must not be an array type" }
+// { dg-prune-output "ElementType must not be an abstract" }
+// { dg-prune-output "static assertion failed" } // no message for alignment being too small
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/accessors/debug/aligned_access_neg.cc b/libstdc++-v3/testsuite/23_containers/mdspan/accessors/debug/aligned_access_neg.cc
new file mode 100644
index 0000000..3511cef
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/accessors/debug/aligned_access_neg.cc
@@ -0,0 +1,23 @@
+// { dg-do run { target c++26 xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <mdspan>
+#include <array>
+
+void
+test_unaligned_access()
+{
+ constexpr size_t N = 4;
+ alignas(N) std::array<char, 128> buffer{};
+ auto* unaligned = buffer.data() + 1;
+ auto a = std::aligned_accessor<char, N>{};
+
+ [[maybe_unused]] char x = a.access(unaligned, 0);
+}
+
+int
+main()
+{
+ test_unaligned_access();
+ return 0;
+};
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/accessors/debug/aligned_offset_neg.cc b/libstdc++-v3/testsuite/23_containers/mdspan/accessors/debug/aligned_offset_neg.cc
new file mode 100644
index 0000000..319da5f
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/accessors/debug/aligned_offset_neg.cc
@@ -0,0 +1,23 @@
+// { dg-do run { target c++26 xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <mdspan>
+#include <array>
+
+void
+test_unaligned_offset()
+{
+ constexpr size_t N = 4;
+ alignas(N) std::array<char, 128> buffer{};
+ auto* unaligned = buffer.data() + 1;
+ auto a = std::aligned_accessor<char, N>{};
+
+ [[maybe_unused]] char* x = a.offset(unaligned, 0);
+}
+
+int
+main()
+{
+ test_unaligned_offset();
+ 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/accessors/generic.cc b/libstdc++-v3/testsuite/23_containers/mdspan/accessors/generic.cc
new file mode 100644
index 0000000..31cb13e
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/accessors/generic.cc
@@ -0,0 +1,171 @@
+// { dg-do run { target c++23 } }
+#include <mdspan>
+
+#include <testsuite_hooks.h>
+
+template<typename Accessor>
+ constexpr bool
+ test_class_properties()
+ {
+ static_assert(std::is_trivially_copyable_v<Accessor>);
+ static_assert(std::semiregular<Accessor>);
+ return true;
+ }
+
+template<typename Accessor>
+ constexpr bool
+ 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>);
+ return true;
+ }
+
+class Base
+{ };
+
+class Derived : public Base
+{ };
+
+template<typename RhsAccessor, typename LhsAccessor, bool ExpectConvertible>
+ constexpr void
+ check_convertible()
+ {
+ RhsAccessor rhs;
+ [[maybe_unused]] LhsAccessor lhs(rhs);
+ static_assert(std::is_nothrow_constructible_v<LhsAccessor, RhsAccessor>);
+ static_assert(std::is_convertible_v<RhsAccessor, LhsAccessor> == ExpectConvertible);
+ }
+
+template<template<typename T> typename LhsAccessor,
+ template<typename T> typename RhsAccessor = LhsAccessor,
+ bool ExpectConvertible = true>
+ constexpr bool
+ test_ctor()
+ {
+ // T -> T
+ check_convertible<RhsAccessor<double>, LhsAccessor<double>,
+ ExpectConvertible>();
+
+ // T -> const T
+ check_convertible<RhsAccessor<double>, LhsAccessor<const double>,
+ ExpectConvertible>();
+ check_convertible<RhsAccessor<Derived>, LhsAccessor<const Derived>,
+ ExpectConvertible>();
+
+ // const T -> T
+ static_assert(!std::is_constructible_v<LhsAccessor<double>,
+ RhsAccessor<const double>>);
+ static_assert(!std::is_constructible_v<LhsAccessor<Derived>,
+ RhsAccessor<const Derived>>);
+
+ // T <-> volatile T
+ check_convertible<RhsAccessor<int>, LhsAccessor<volatile int>,
+ ExpectConvertible>();
+ static_assert(!std::is_constructible_v<LhsAccessor<int>,
+ RhsAccessor<volatile int>>);
+
+ // size difference
+ static_assert(!std::is_constructible_v<LhsAccessor<char>,
+ RhsAccessor<int>>);
+
+ // signedness
+ static_assert(!std::is_constructible_v<LhsAccessor<int>,
+ RhsAccessor<unsigned int>>);
+ static_assert(!std::is_constructible_v<LhsAccessor<unsigned int>,
+ RhsAccessor<int>>);
+
+ // Derived <-> Base
+ static_assert(!std::is_constructible_v<LhsAccessor<Base>,
+ RhsAccessor<Derived>>);
+ static_assert(!std::is_constructible_v<LhsAccessor<Derived>,
+ RhsAccessor<Base>>);
+ return true;
+ }
+
+template<template<typename T> typename Accessor>
+ constexpr bool
+ test_properties()
+ {
+ test_class_properties<Accessor<double>>();
+ test_accessor_policy<Accessor<double>>();
+ test_ctor<Accessor>();
+ return true;
+ }
+
+static_assert(test_properties<std::default_accessor>());
+
+#ifdef __glibcxx_aligned_accessor
+template<size_t Mult>
+struct OverAlignedAccessorTrait
+{
+ template<typename T>
+ using type = std::aligned_accessor<T, Mult*alignof(T)>;
+};
+
+static_assert(test_properties<OverAlignedAccessorTrait<1>::type>());
+static_assert(test_properties<OverAlignedAccessorTrait<2>::type>());
+static_assert(test_ctor<OverAlignedAccessorTrait<2>::type,
+ std::default_accessor, false>());
+static_assert(test_ctor<OverAlignedAccessorTrait<2>::type,
+ OverAlignedAccessorTrait<4>::type>());
+static_assert(test_ctor<std::default_accessor,
+ OverAlignedAccessorTrait<2>::type>());
+static_assert(!std::is_constructible_v<std::aligned_accessor<char, 4>,
+ std::aligned_accessor<char, 2>>);
+#endif
+
+template<typename A>
+ constexpr size_t
+ accessor_alignment = alignof(typename A::element_type);
+
+#ifdef __glibcxx_aligned_accessor
+template<typename T, size_t N>
+ constexpr size_t
+ accessor_alignment<std::aligned_accessor<T, N>> = N;
+#endif
+
+template<typename Accessor>
+ constexpr void
+ test_access(Accessor accessor)
+ {
+ constexpr size_t N = accessor_alignment<Accessor>;
+ alignas(N) std::array<double, 5> a{10, 11, 12, 13, 14};
+ for (size_t i = 0; i < a.size(); ++i)
+ VERIFY(accessor.access(a.data(), i) == 10 + i);
+ }
+
+template<typename Accessor>
+ constexpr void
+ test_offset(Accessor accessor)
+ {
+ constexpr size_t N = accessor_alignment<Accessor>;
+ alignas(N) std::array<double, 5> a{10, 11, 12, 13, 14};
+ for (size_t i = 0; i < a.size(); ++i)
+ VERIFY(accessor.offset(a.data(), i) == a.data() + i);
+ }
+
+template<typename Accessor>
+ constexpr bool
+ test_all()
+ {
+ auto accessor = Accessor{};
+ test_offset(accessor);
+ test_access(accessor);
+ return true;
+ }
+
+int
+main()
+{
+ test_all<std::default_accessor<double>>();
+ static_assert(test_all<std::default_accessor<double>>());
+
+#ifdef __glibcxx_aligned_accessor
+ test_all<typename OverAlignedAccessorTrait<4>::type<double>>();
+ static_assert(test_all<typename OverAlignedAccessorTrait<4>::type<double>>());
+#endif
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/class_mandate_neg.cc b/libstdc++-v3/testsuite/23_containers/mdspan/class_mandate_neg.cc
new file mode 100644
index 0000000..172f149
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/class_mandate_neg.cc
@@ -0,0 +1,41 @@
+// { dg-do compile { target c++23 } }
+#include<mdspan>
+
+#include <cstdint>
+#include "layout_like.h"
+
+struct ExtentsLike
+{
+ using index_type = int;
+ using size_type = unsigned int;
+ using rank_type = size_t;
+
+ static constexpr size_t rank() { return 1; }
+ static constexpr size_t rank_dynamic() { return 0; }
+};
+
+constexpr bool
+test_custom_extents_type()
+{
+ std::mdspan<double, ExtentsLike> md1; // { dg-error "required from here" }
+ return true;
+}
+static_assert(test_custom_extents_type());
+
+constexpr bool
+test_element_type_mismatch()
+{
+ using E = std::extents<int, 1>;
+ using L = std::layout_right;
+ using A = std::default_accessor<double>;
+
+ [[maybe_unused]] std::mdspan<float, E, L, A> md2; // { dg-error "required from here" }
+ return true;
+};
+static_assert(test_element_type_mismatch());
+
+// { dg-prune-output "Extents must be a specialization of std::extents" }
+// { dg-prune-output "no type named '_Storage'" }
+// { dg-prune-output "non-constant condition" }
+// { dg-prune-output "static assertion failed" }
+// { dg-prune-output "__glibcxx_assert" }
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/extents/class_mandates_neg.cc b/libstdc++-v3/testsuite/23_containers/mdspan/extents/class_mandates_neg.cc
new file mode 100644
index 0000000..db5cad2
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/class_mandates_neg.cc
@@ -0,0 +1,17 @@
+// { 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" }
+// { dg-prune-output "non-constant condition for static assertion" }
+// { dg-prune-output "integer constants in boolean context" }
+// { dg-prune-output "__gnu_cxx::__numeric_traits_integer" }
+// { dg-prune-output "static assertion failed" }
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..fdbcb70
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints.cc
@@ -0,0 +1,69 @@
+// { 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>);
+
+#ifdef __SIZEOF_INT128__
+static_assert(std::is_constructible_v<std::extents<__int128, 1, 2>,
+ __int128, unsigned __int128>);
+static_assert(std::is_constructible_v<std::extents<unsigned __int128, 1, 2>,
+ unsigned int, int>);
+#endif
+
+// 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..1682cc5
--- /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..99de401
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/custom_integer.cc
@@ -0,0 +1,96 @@
+// { dg-do run { target c++23 } }
+#include <mdspan>
+
+#include <testsuite_hooks.h>
+#include "../int_like.h"
+
+// Test construction from a custom integer-like object, that has
+// no copy/move ctor or copy/move assignment operator.
+
+constexpr size_t dyn = std::dynamic_extent;
+
+static_assert(std::is_convertible_v<IntLike, int>);
+static_assert(std::is_nothrow_constructible_v<int, IntLike>);
+
+template<typename Extents, bool Valid>
+ void
+ test_shape(const auto& shape)
+ {
+ static_assert(std::is_constructible_v<Extents, decltype(shape)> == Valid);
+
+ if constexpr (Valid)
+ {
+ std::extents<int, 2, 3> expected;
+ Extents actual(shape);
+ VERIFY(actual == expected);
+ }
+ }
+
+template<typename Int, bool Valid>
+ void
+ test_shape_all()
+ {
+ auto a2 = std::array<Int, 1>{Int(2)};
+ auto s2 = std::span<Int, 1>(a2);
+
+ auto a23 = std::array<Int, 2>{Int(2), Int(3)};
+ auto s23 = std::span<Int, 2>(a23);
+
+ auto check = [](const auto& dyn_exts, const auto& full_exts)
+ {
+ test_shape<std::extents<int, 2, 3>, Valid>(full_exts);
+ test_shape<std::extents<int, dyn, 3>, Valid>(dyn_exts);
+ test_shape<std::extents<int, dyn, 3>, Valid>(full_exts);
+ test_shape<std::extents<int, dyn, dyn>, Valid>(full_exts);
+ };
+
+ check(a2, a23);
+ check(s2, s23);
+ }
+
+// Needed because is_constructible requires that Ints are move constructible.
+template<typename Extents, typename... Ints>
+ concept has_ctor = requires
+ {
+ { Extents(Ints(0)...) } -> std::same_as<Extents>;
+ };
+
+template<typename Int, bool Valid>
+ void
+ test_pack_all()
+ {
+ static_assert(has_ctor<std::extents<int, dyn, 3>, Int> == Valid);
+ static_assert(has_ctor<std::extents<int, dyn, 3>, Int, Int> == Valid);
+ static_assert(has_ctor<std::extents<int, dyn, dyn>, Int, Int> == Valid);
+
+ if constexpr (Valid)
+ {
+ std::extents<int, 2, 3> expected;
+
+ std::extents<int, dyn, 3> e1(Int(2));
+ VERIFY(e1 == expected);
+
+ std::extents<int, dyn, 3> e2(Int(2), Int(3));
+ VERIFY(e2 == expected);
+
+ std::extents<int, dyn, dyn> e3(Int(2), Int(3));
+ VERIFY(e3 == expected);
+ }
+ }
+
+int
+main()
+{
+ test_shape_all<int, true>();
+ test_shape_all<IntLike, true>();
+ test_shape_all<ThrowingInt, false>();
+ test_shape_all<MutatingInt, false>();
+ test_shape_all<RValueInt, false>();
+
+ test_pack_all<int, true>();
+ test_pack_all<IntLike, true>();
+ test_pack_all<ThrowingInt, false>();
+ test_pack_all<MutatingInt, true>();
+ test_pack_all<RValueInt, true>();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/extents/extents_mismatch_neg.cc b/libstdc++-v3/testsuite/23_containers/mdspan/extents/extents_mismatch_neg.cc
new file mode 100644
index 0000000..b35e531
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/extents_mismatch_neg.cc
@@ -0,0 +1,35 @@
+// { dg-do compile { target c++23 } }
+#include<mdspan>
+
+#include <cstdint>
+
+constexpr size_t dyn = std::dynamic_extent;
+
+constexpr bool
+test_dyn2sta_extents_mismatch_00()
+{
+ auto e0 = std::extents<int, dyn>{1};
+ [[maybe_unused]] auto e1 = std::extents<int, 2>{e0}; // { dg-error "expansion of" }
+ return true;
+}
+static_assert(test_dyn2sta_extents_mismatch_00()); // { dg-error "expansion of" }
+
+constexpr bool
+test_dyn2sta_extents_mismatch_01()
+{
+ [[maybe_unused]] auto e = std::extents<int, 1, dyn>{2, 2}; // { dg-error "expansion of" }
+ return true;
+}
+static_assert(test_dyn2sta_extents_mismatch_01()); // { dg-error "expansion of" }
+
+constexpr bool
+test_dyn2sta_extents_mismatch_02()
+{
+ std::array<int, 2> exts{2, 2};
+ [[maybe_unused]] auto e = std::extents<int, 1, dyn>{exts}; // { dg-error "expansion of" }
+ return true;
+}
+static_assert(test_dyn2sta_extents_mismatch_02()); // { dg-error "expansion of" }
+
+// { dg-prune-output "non-constant condition for static assertion" }
+// { dg-prune-output "__glibcxx_assert" }
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/extents/misc.cc b/libstdc++-v3/testsuite/23_containers/mdspan/extents/misc.cc
new file mode 100644
index 0000000..33d6f94
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/misc.cc
@@ -0,0 +1,261 @@
+// { 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_from_constant()
+{
+ auto verify = [](auto actual, auto expected)
+ {
+ static_assert(std::same_as<decltype(actual), decltype(expected)>);
+ VERIFY(actual == expected);
+ };
+
+ constexpr auto i1 = std::integral_constant<size_t, 1>{};
+ constexpr auto i2 = std::integral_constant<int, 2>{};
+
+ verify(std::extents(1), std::extents<size_t, dyn>{1});
+ verify(std::extents(i1), std::extents<size_t, 1>{});
+ verify(std::extents(i2), std::extents<size_t, 2>{});
+ verify(std::extents(std::true_type{}, 2), std::dextents<size_t, 2>{1, 2});
+ verify(std::extents(std::false_type{}, 2), std::dextents<size_t, 2>{0, 2});
+
+#if __glibcxx_constant_wrapper
+ constexpr auto c2 = std::constant_wrapper<2>{};
+ verify(std::extents(c2), std::extents<size_t, 2>{});
+ verify(std::extents(1, c2), std::extents<size_t, dyn, 2>{1});
+ verify(std::extents(c2), std::extents<size_t, 2>{});
+ verify(std::extents(1, c2), std::extents<size_t, dyn, 2>{1});
+ verify(std::extents(std::cw<true>, c2), std::extents<size_t, dyn, 2>{1});
+#endif
+ return true;
+}
+
+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));
+ test_deduction_from_constant();
+ 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);
+
+// dims
+#if __glibcxx_mdspan >= 202406L
+static_assert(std::is_same_v<std::dims<0>, std::dextents<size_t, 0>>);
+static_assert(std::is_same_v<std::dims<3>, std::dextents<size_t, 3>>);
+static_assert(std::is_same_v<std::dims<3, int>, std::dextents<int, 3>>);
+#endif
+
+// 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/int_like.h b/libstdc++-v3/testsuite/23_containers/mdspan/int_like.h
new file mode 100644
index 0000000..b839be7
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/int_like.h
@@ -0,0 +1,81 @@
+#ifndef TEST_MDSPAN_INT_LIKE_H
+#define TEST_MDSPAN_INT_LIKE_H
+
+enum class CustomIndexKind
+{
+ Const,
+ Throwing,
+ Mutating,
+ RValue,
+};
+
+template<CustomIndexKind Kind, bool Copyable = false>
+ class CustomIndexType
+ {
+ public:
+ explicit
+ CustomIndexType(int i)
+ : value(i)
+ { }
+
+ CustomIndexType() requires(Copyable) = default;
+ CustomIndexType() requires(!Copyable) = delete;
+
+ CustomIndexType(const CustomIndexType&) requires(Copyable) = default;
+ CustomIndexType(const CustomIndexType&) requires(!Copyable) = delete;
+
+ CustomIndexType(CustomIndexType&&) requires(Copyable) = default;
+ CustomIndexType(CustomIndexType&&) requires(!Copyable) = delete;
+
+ CustomIndexType&
+ operator=(const CustomIndexType&) requires(Copyable) = default;
+ CustomIndexType&
+ operator=(const CustomIndexType&) requires(!Copyable) = delete;
+
+ CustomIndexType&
+ operator=(CustomIndexType&&) requires(Copyable) = default;
+ CustomIndexType&
+ operator=(CustomIndexType&&) requires(!Copyable) = delete;
+
+ constexpr
+ operator int() const noexcept
+ requires (Kind == CustomIndexKind::Const)
+ { return value; }
+
+ constexpr
+ operator int() const
+ requires (Kind == CustomIndexKind::Throwing)
+ { return value; }
+
+ constexpr
+ operator int() noexcept
+ requires (Kind == CustomIndexKind::Mutating)
+ { return value; }
+
+ constexpr
+ operator int() && noexcept
+ requires (Kind == CustomIndexKind::RValue)
+ { return value; }
+
+ private:
+ int value;
+ };
+
+using IntLike = CustomIndexType<CustomIndexKind::Const>;
+using ThrowingInt = CustomIndexType<CustomIndexKind::Throwing>;
+using MutatingInt = CustomIndexType<CustomIndexKind::Mutating>;
+using RValueInt = CustomIndexType<CustomIndexKind::RValue>;
+
+struct NotIntLike
+{ };
+
+struct StructuralInt
+{
+ constexpr
+ operator int() const noexcept
+ { return value; }
+
+ int value;
+};
+
+#endif // TEST_MDSPAN_INT_LIKE_H
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/layout_like.h b/libstdc++-v3/testsuite/23_containers/mdspan/layout_like.h
new file mode 100644
index 0000000..ded6e9d
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/layout_like.h
@@ -0,0 +1,87 @@
+#ifndef TEST_MDSPAN_LAYOUT_LIKE_H
+#define TEST_MDSPAN_LAYOUT_LIKE_H 1
+
+template<bool Noexcept>
+ struct CustomLayout
+ {
+ template<typename Extents>
+ class mapping
+ {
+ public:
+ using extents_type = Extents;
+ using index_type = typename extents_type::index_type;
+ using size_type = typename extents_type::size_type;
+ using rank_type = typename extents_type::rank_type;
+ using layout_type = CustomLayout;
+
+ constexpr
+ mapping() noexcept = default;
+
+ constexpr
+ mapping(Extents exts)
+ : m_exts(exts)
+ { }
+
+ constexpr const extents_type&
+ extents() const noexcept(Noexcept) { return m_exts; }
+
+ constexpr index_type
+ required_span_size() const noexcept(Noexcept)
+ {
+ for (size_t i = 0; i < extents_type::rank(); ++i)
+ if (m_exts.extent(i) == 0)
+ return 0;
+ return 1;
+ }
+
+ template<typename... Indices>
+ requires (sizeof...(Indices) == extents_type::rank())
+ constexpr index_type
+ operator()(Indices...) const noexcept(Noexcept)
+ { return 0; }
+
+ static constexpr index_type
+ stride(rank_type) noexcept(Noexcept)
+ { return 0; }
+
+ static constexpr bool
+ is_always_unique() noexcept(Noexcept)
+ { return false; }
+
+ static constexpr bool
+ is_always_exhaustive() noexcept(Noexcept)
+ { return true; }
+
+ static constexpr bool
+ is_always_strided() noexcept(Noexcept)
+ { return true; }
+
+ constexpr bool
+ is_unique() const noexcept(Noexcept)
+ {
+ if (required_span_size() == 0)
+ return true;
+
+ for (size_t i = 0; i < extents_type::rank(); ++i)
+ if (m_exts.extent(i) > 1)
+ return false;
+ return true;
+ }
+
+ static constexpr bool
+ is_exhaustive() noexcept(Noexcept)
+ { return true; }
+
+ static constexpr bool
+ is_strided() noexcept(Noexcept)
+ { return true; }
+
+ private:
+ Extents m_exts;
+ };
+ };
+
+using LayoutLike = CustomLayout<true>;
+using ThrowingLayout = CustomLayout<false>;
+
+#endif
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/layout_traits.h b/libstdc++-v3/testsuite/23_containers/mdspan/layout_traits.h
new file mode 100644
index 0000000..f0aeac3
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/layout_traits.h
@@ -0,0 +1,196 @@
+#ifndef TEST_MDSPAN_LAYOUT_TRAITS_H
+#define TEST_MDSPAN_LAYOUT_TRAITS_H
+
+#include <algorithm>
+
+enum class PaddingSide
+{
+ Left,
+ Right
+};
+
+template<typename Layout>
+ constexpr static bool is_left_padded = false;
+
+#if __cplusplus > 202302L
+template<size_t PaddingValue>
+ constexpr static bool is_left_padded<std::layout_left_padded<PaddingValue>>
+ = true;
+#endif
+
+template<typename Layout>
+ constexpr static bool is_right_padded = false;
+
+#if __cplusplus > 202302L
+template<size_t PaddingValue>
+ constexpr static bool is_right_padded<std::layout_right_padded<PaddingValue>>
+ = true;
+#endif
+
+template<typename Layout>
+ constexpr bool
+ is_padded_layout = is_left_padded<Layout> || is_right_padded<Layout>;
+
+#if __cplusplus > 202302L
+template<PaddingSide Side, typename Layout>
+ constexpr bool
+ is_same_padded;
+
+template<typename Layout>
+ constexpr bool
+ is_same_padded<PaddingSide::Left, Layout> = is_left_padded<Layout>;
+
+template<typename Layout>
+ constexpr bool
+ is_same_padded<PaddingSide::Right, Layout> = is_right_padded<Layout>;
+
+template<typename Extents>
+ constexpr auto
+ dynamic_extents_array(const Extents& exts)
+ {
+ std::array<typename Extents::index_type, Extents::rank()> ret;
+ for(size_t i = 0; i < Extents::rank(); ++i)
+ ret[i] = exts.extent(i);
+ return ret;
+ }
+
+struct DeducePaddingSide
+{
+ template<template<size_t> typename Layout>
+ constexpr static PaddingSide
+ from_template()
+ {
+ if constexpr (std::same_as<Layout<0>, std::layout_left_padded<0>>)
+ return PaddingSide::Left;
+ else
+ return PaddingSide::Right;
+ }
+
+ template<typename Layout>
+ constexpr static PaddingSide
+ from_typename()
+ {
+ if constexpr (std::same_as<Layout, std::layout_left>)
+ return PaddingSide::Left;
+ else if constexpr (is_left_padded<Layout>)
+ return PaddingSide::Left;
+ else
+ return PaddingSide::Right;
+ }
+};
+
+template<PaddingSide Side>
+ struct LayoutTraits;
+
+template<>
+ struct LayoutTraits<PaddingSide::Left>
+ {
+ using layout_same = std::layout_left;
+ using layout_other = std::layout_right;
+ template<size_t PaddingValue>
+ using layout_same_padded = std::layout_left_padded<PaddingValue>;
+
+ template<typename Extents>
+ using extents_type = Extents;
+
+ template<typename Extents>
+ constexpr static extents_type<Extents>
+ make_extents(const Extents& exts)
+ { return exts; }
+
+ template<typename T, size_t N>
+ constexpr static std::array<T, N>
+ make_array(const std::array<T, N>& a)
+ { return a; }
+
+ template<typename... Indices>
+ constexpr static auto
+ make_indices(Indices... indices)
+ { return std::array{indices...}; }
+
+ template<typename... Ts>
+ constexpr static std::tuple<Ts...>
+ make_tuple(const std::tuple<Ts...>& tup)
+ { return tup; }
+
+ template<typename Mapping>
+ constexpr static auto
+ padded_stride(const Mapping& m)
+ { return m.stride(1); }
+
+ template<typename Extents>
+ constexpr static auto
+ padded_extent(const Extents& exts)
+ { return exts.extent(0); }
+ };
+
+template<>
+ struct LayoutTraits<PaddingSide::Right>
+ {
+ using layout_same = std::layout_right;
+ template<size_t PaddingValue>
+ using layout_same_padded = std::layout_right_padded<PaddingValue>;
+ using layout_other = std::layout_left;
+
+ template<typename IndexType, size_t... Extents>
+ constexpr static auto
+ make_extents(const std::extents<IndexType, Extents...>& exts)
+ {
+ constexpr size_t rank = sizeof...(Extents);
+ auto impl = [&]<size_t... I>(std::index_sequence<I...>)
+ {
+ auto dyn_exts = make_array(dynamic_extents_array(exts));
+ return std::extents<IndexType, Extents...[rank - 1 - I]...>(dyn_exts);
+ };
+ return impl(std::make_index_sequence<rank>());
+ }
+
+ template<typename Extents>
+ using extents_type = decltype(make_extents(std::declval<Extents>()));
+
+ template<typename T, size_t N>
+ constexpr static std::array<T, N>
+ make_array(std::array<T, N> a)
+ {
+ std::ranges::reverse(a);
+ return a;
+ }
+
+ template<typename... Indices>
+ constexpr static auto
+ make_indices(Indices... indices)
+ { return make_array(std::array{indices...}); }
+
+ template<typename... Ts>
+ constexpr static auto
+ make_tuple(const std::tuple<Ts...>& tup)
+ {
+ constexpr size_t rank = sizeof...(Ts);
+ auto impl = [&]<size_t... I>(std::index_sequence<I...>)
+ {
+ auto idx = [rank](size_t i) consteval
+ { return rank - 1 - i; };
+ return std::tuple<Ts...[idx(I)]...>{get<idx(I)>(tup)...};
+ };
+ return impl(std::make_index_sequence<rank>());
+ }
+
+ template<typename Mapping>
+ constexpr static auto
+ padded_stride(const Mapping& m)
+ {
+ auto rank = Mapping::extents_type::rank();
+ return m.stride(rank - 2);
+ }
+
+ template<typename Extents>
+ constexpr static auto
+ padded_extent(const Extents& exts)
+ {
+ auto rank = Extents::rank();
+ return exts.extent(rank - 1);
+ }
+ };
+
+#endif
+#endif
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..edf07c9
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/class_mandate_neg.cc
@@ -0,0 +1,49 @@
+// { 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" }
+// { dg-prune-output "static assertion failed" }
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..b6e4138
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/ctors.cc
@@ -0,0 +1,532 @@
+// { dg-do run { target c++23 } }
+#include <mdspan>
+
+#include "../layout_traits.h"
+#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)
+ {
+ if constexpr (is_padded_layout<typename To::layout_type>)
+ static_assert(std::is_constructible_v<To, From>);
+ else
+ 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)
+ {
+ if constexpr (is_padded_layout<typename To::layout_type>)
+ static_assert(std::is_constructible_v<To, From>);
+ else
+ 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_convertible(OExtents exts)
+ {
+ using Mapping = typename Layout::mapping<Extents>;
+ using OMapping = typename Layout::mapping<OExtents>;
+
+ ::verify_convertible<Mapping>(OMapping(exts));
+ }
+
+ 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});
+
+ if constexpr (!is_padded_layout<Layout>)
+ verify_nothrow_convertible<Layout, std::extents<int, dyn, 2>>(
+ std::extents<int, 1, 2>{});
+ else
+ verify_nothrow_constructible<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>());
+ }
+}
+
+// checks: convertibility of rank == 0 mappings.
+namespace from_rank0
+{
+ template<typename SLayout, typename OLayout, typename SExtents,
+ typename OExtents>
+ constexpr void
+ verify_ctor()
+ {
+ 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{});
+ else
+ verify_nothrow_constructible<SMapping>(OMapping{});
+ }
+
+ template<typename Layout, typename OLayout>
+ constexpr void
+ test_rank0_convertibility()
+ {
+ using E1 = std::extents<int>;
+ using E2 = std::extents<unsigned int>;
+
+ verify_ctor<Layout, OLayout, E1, E2>();
+ verify_ctor<Layout, OLayout, E2, E1>();
+
+ verify_ctor<Layout, OLayout, E2, E2>();
+ verify_ctor<Layout, OLayout, E1, E1>();
+ }
+
+ constexpr void
+ test_all()
+ {
+ auto run = []<typename Layout>(Layout)
+ {
+ test_rank0_convertibility<Layout, std::layout_left>();
+ test_rank0_convertibility<Layout, std::layout_right>();
+ test_rank0_convertibility<Layout, std::layout_stride>();
+ };
+
+ auto run_all = [run]()
+ {
+ run(std::layout_left{});
+ run(std::layout_right{});
+ run(std::layout_stride{});
+#if __cplusplus > 202302L
+ run(std::layout_left_padded<0>{});
+ run(std::layout_left_padded<1>{});
+ run(std::layout_left_padded<6>{});
+ run(std::layout_left_padded<dyn>{});
+#endif
+ return true;
+ };
+
+ run_all();
+ static_assert(run_all());
+ }
+}
+
+// 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>{});
+
+ verify_nothrow_constructible<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>();
+ }
+
+template<template<size_t> typename Layout>
+ constexpr void
+ test_padded_all()
+ {
+ test_all<Layout<0>>();
+ test_all<Layout<1>>();
+ test_all<Layout<2>>();
+ test_all<Layout<dyn>>();
+ }
+
+int
+main()
+{
+ test_all<std::layout_left>();
+ test_all<std::layout_right>();
+#if __cplusplus > 202302L
+ test_padded_all<std::layout_left_padded>();
+ test_padded_all<std::layout_right_padded>();
+#endif
+
+ from_left_or_right::test_all<std::layout_left, std::layout_right>();
+ from_left_or_right::test_all<std::layout_right, std::layout_left>();
+
+ from_rank0::test_all();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/debug/out_of_bounds_neg.cc b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/debug/out_of_bounds_neg.cc
new file mode 100644
index 0000000..fb8ff01
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/debug/out_of_bounds_neg.cc
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++23 } }
+// { dg-require-debug-mode "" }
+#include<mdspan>
+
+template<typename Layout>
+ constexpr bool
+ test_out_of_bounds_1d()
+ {
+ auto m = typename Layout::mapping<std::extents<int, 0>>{};
+ (void) m(0); // { dg-error "expansion of" }
+ return true;
+ }
+static_assert(test_out_of_bounds_1d<std::layout_left>()); // { dg-error "expansion of" }
+static_assert(test_out_of_bounds_1d<std::layout_right>()); // { dg-error "expansion of" }
+static_assert(test_out_of_bounds_1d<std::layout_stride>()); // { dg-error "expansion of" }
+
+template<typename Layout>
+ constexpr bool
+ test_out_of_bounds_3d()
+ {
+ auto m = typename Layout::mapping<std::extents<int, 3, 5, 7>>{};
+ (void) m(2, 5, 5); // { dg-error "expansion of" }
+ return true;
+ }
+static_assert(test_out_of_bounds_3d<std::layout_left>()); // { dg-error "expansion of" }
+static_assert(test_out_of_bounds_3d<std::layout_right>()); // { dg-error "expansion of" }
+static_assert(test_out_of_bounds_3d<std::layout_stride>()); // { dg-error "expansion of" }
+
+// { dg-prune-output "non-constant condition for static assertion" }
+// { dg-prune-output "__glibcxx_assert" }
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/empty.cc b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/empty.cc
new file mode 100644
index 0000000..8840d07
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/empty.cc
@@ -0,0 +1,148 @@
+// { 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;
+ // Allow some room for padding.
+ constexpr size_t n = (std::cmp_less(n1, n2) ? size_t(n1) : n2) - 4;
+
+ 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;
+ // Allow some room for padding.
+ constexpr Int n = (std::cmp_less(n1, n2) ? n1 : Int(n2)) - 4;
+
+ 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;
+ }
+
+template<template<size_t> typename Layout>
+ constexpr bool
+ test_padded_all()
+ {
+ static_assert(test_all<Layout<0>>());
+ static_assert(test_all<Layout<1>>());
+ static_assert(test_all<Layout<2>>());
+ static_assert(test_all<Layout<dyn>>());
+ 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>());
+#if __cplusplus > 202302L
+ static_assert(test_padded_all<std::layout_left_padded>());
+ static_assert(test_padded_all<std::layout_right_padded>());
+#endif
+ 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..17cfac5
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/mapping.cc
@@ -0,0 +1,717 @@
+// { dg-do run { target c++23 } }
+#include <mdspan>
+
+#include "../int_like.h"
+#include "../layout_traits.h"
+#include <cstdint>
+#include <testsuite_hooks.h>
+
+constexpr size_t dyn = std::dynamic_extent;
+
+template<typename Mapping>
+ concept has_static_is_exhaustive = requires
+ {
+ { Mapping::is_exhaustive() } -> std::same_as<bool>;
+ };
+
+static_assert(has_static_is_exhaustive<std::layout_right::mapping<std::extents<int>>>);
+static_assert(!has_static_is_exhaustive<std::layout_stride::mapping<std::extents<int>>>);
+
+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 (has_static_is_exhaustive<M>)
+ 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 Int, 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(Int(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, typename Int>
+ constexpr void
+ test_linear_index_1d()
+ {
+ typename Layout::mapping<std::extents<int, 5>> m;
+ test_linear_index<Int>(m, 0);
+ test_linear_index<Int>(m, 1);
+ test_linear_index<Int>(m, 4);
+ }
+
+template<typename Layout, typename Int>
+ constexpr void
+ test_linear_index_2d()
+ {
+ typename Layout::mapping<std::extents<int, 3, 256>> m;
+ test_linear_index<Int>(m, 0, 0);
+ test_linear_index<Int>(m, 1, 0);
+ test_linear_index<Int>(m, 0, 1);
+ test_linear_index<Int>(m, 1, 1);
+ test_linear_index<Int>(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, typename Int>
+ constexpr void
+ test_linear_index_3d()
+ {
+ auto m = MappingFactory<Layout>::create(std::extents(3, 5, 7));
+ test_linear_index<Int>(m, 0, 0, 0);
+ test_linear_index<Int>(m, 1, 0, 0);
+ test_linear_index<Int>(m, 0, 1, 0);
+ test_linear_index<Int>(m, 0, 0, 1);
+ test_linear_index<Int>(m, 1, 1, 0);
+ test_linear_index<Int>(m, 2, 4, 6);
+ }
+
+template<typename Mapping, typename... Ints>
+ concept has_linear_index = requires (Mapping m)
+ {
+ { m(Ints(0)...) } -> std::same_as<typename Mapping::index_type>;
+ };
+
+template<typename Layout>
+ constexpr void
+ test_has_linear_index_0d()
+ {
+ using Mapping = typename Layout::mapping<std::extents<int>>;
+ static_assert(has_linear_index<Mapping>);
+ static_assert(!has_linear_index<Mapping, int>);
+ static_assert(!has_linear_index<Mapping, IntLike>);
+ static_assert(!has_linear_index<Mapping, NotIntLike>);
+ }
+
+template<typename Layout>
+ constexpr void
+ test_has_linear_index_1d()
+ {
+ using Mapping = typename Layout::mapping<std::extents<int, 3>>;
+ static_assert(!has_linear_index<Mapping>);
+ static_assert(has_linear_index<Mapping, int>);
+ static_assert(has_linear_index<Mapping, double>);
+ static_assert(has_linear_index<Mapping, IntLike>);
+ static_assert(has_linear_index<Mapping, MutatingInt>);
+ static_assert(!has_linear_index<Mapping, ThrowingInt>);
+ static_assert(!has_linear_index<Mapping, NotIntLike>);
+ static_assert(!has_linear_index<Mapping, int, int>);
+ }
+
+template<typename Layout>
+ constexpr void
+ test_has_linear_index_2d()
+ {
+ using Mapping = typename Layout::mapping<std::extents<int, 3, 5>>;
+ static_assert(!has_linear_index<Mapping, int>);
+ static_assert(has_linear_index<Mapping, int, int>);
+ static_assert(has_linear_index<Mapping, double, double>);
+ static_assert(has_linear_index<Mapping, IntLike, int>);
+ static_assert(has_linear_index<Mapping, MutatingInt, int>);
+ static_assert(!has_linear_index<Mapping, ThrowingInt, int>);
+ static_assert(!has_linear_index<Mapping, NotIntLike, int>);
+ static_assert(!has_linear_index<Mapping, int, int, int>);
+ }
+
+template<typename Layout, typename Int>
+ constexpr bool
+ test_linear_index_all()
+ {
+ test_linear_index_0d<Layout>();
+ test_linear_index_1d<Layout, Int>();
+ test_linear_index_2d<Layout, Int>();
+ test_linear_index_3d<Layout, Int>();
+ 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()
+ {
+ typename Layout::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>
+struct TestStride2D;
+
+template<>
+ struct TestStride2D<std::layout_left>
+ {
+ static constexpr void
+ run()
+ {
+ std::layout_left::mapping<std::extents<int, 3, 5>> m;
+ VERIFY(m.stride(0) == 1);
+ VERIFY(m.stride(1) == 3);
+ }
+ };
+
+template<>
+ struct TestStride2D<std::layout_right>
+ {
+ static constexpr void
+ run()
+ {
+ std::layout_right::mapping<std::extents<int, 3, 5>> m;
+ VERIFY(m.stride(0) == 5);
+ VERIFY(m.stride(1) == 1);
+ }
+ };
+
+template<>
+ struct TestStride2D<std::layout_stride>
+ {
+ static constexpr void
+ run()
+ {
+ 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);
+ }
+ };
+
+#if __cplusplus > 202302L
+template<typename Layout>
+ requires is_left_padded<Layout> || is_right_padded<Layout>
+ struct TestStride2D<Layout>
+ {
+ static constexpr void
+ run()
+ {
+ using Traits = LayoutTraits<DeducePaddingSide::from_typename<Layout>()>;
+ using Extents = typename Traits::extents_type<std::extents<int, 3, 5>>;
+ using Mapping = typename Layout::mapping<Extents>;
+ constexpr size_t padding_value = Mapping::padding_value;
+
+ Mapping m;
+ size_t effective_pad = (padding_value == 0 || padding_value == dyn)
+ ? size_t(1) : padding_value;
+
+ constexpr auto i0 = is_left_padded<Layout> ? 0 : 1;
+ VERIFY(m.stride(i0) == 1);
+
+ // The next multiple of padding_value, that's greater or equal
+ // to exts.extent(0) is the unique value in the range:
+ // [exts.extent(0), exts.extent(0) + padding_value)
+ // that is divisible by padding_value.
+ auto stride = Traits::padded_stride(m);
+ VERIFY((stride % effective_pad) == 0);
+ VERIFY(3 <= stride && std::cmp_less(stride, 3 + effective_pad));
+ }
+ };
+#endif
+
+template<typename Layout>
+ constexpr void
+ test_stride_2d()
+ {
+ TestStride2D<Layout>::run();
+ }
+
+template<typename Layout>
+struct TestStride3D;
+
+template<>
+ struct TestStride3D<std::layout_left>
+ {
+ static constexpr void
+ run()
+ {
+ 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<>
+ struct TestStride3D<std::layout_right>
+ {
+ static constexpr void
+ run()
+ {
+ 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<>
+ struct TestStride3D<std::layout_stride>
+ {
+ static constexpr void
+ run()
+ {
+ 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);
+ }
+ };
+
+#if __cplusplus > 202302L
+template<typename Layout>
+ requires is_left_padded<Layout> || is_right_padded<Layout>
+ struct TestStride3D<Layout>
+ {
+ static constexpr void
+ run()
+ {
+ using Traits = LayoutTraits<DeducePaddingSide::from_typename<Layout>()>;
+ using Extents = typename Traits::extents_type<std::extents<int, 3, 5, 7>>;
+ using Mapping = typename Layout::mapping<Extents>;
+ constexpr size_t padding_value = Mapping::padding_value;
+
+ Mapping m;
+ size_t effective_pad = (padding_value == 0 || padding_value == dyn)
+ ? size_t(1) : padding_value;
+
+ constexpr auto i0 = is_left_padded<Layout> ? 0 : 2;
+ VERIFY(m.stride(i0) == 1);
+
+ // The next multiple of padding_value, that's greater or equal
+ // to exts.extent(0) is the unique value in the range:
+ // [exts.extent(0), exts.extent(0) + padding_value)
+ // that is divisible by padding_value.
+ auto stride = Traits::padded_stride(m);
+ VERIFY((stride % effective_pad) == 0);
+ VERIFY(3 <= stride && std::cmp_less(stride, 3 + effective_pad));
+
+ constexpr auto i2 = is_left_padded<Layout> ? 2 : 0;
+ VERIFY(stride * 5 == m.stride(i2));
+ }
+ };
+#endif
+
+template<typename Layout>
+ constexpr void
+ test_stride_3d()
+ {
+ TestStride3D<Layout>::run();
+ }
+
+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_left>
+ || std::is_same_v<Layout, std::layout_right>);
+ 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, uint8_t>();
+ test_linear_index_all<Layout, int>();
+ if !consteval
+ {
+ test_linear_index_all<Layout, IntLike>();
+ test_linear_index_all<Layout, MutatingInt>();
+ test_linear_index_all<Layout, RValueInt>();
+ }
+
+ 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>();
+ }
+
+#if __cplusplus > 202302L
+template<template<size_t> typename Layout>
+ constexpr bool
+ test_padded_all()
+ {
+ test_all<Layout<0>>();
+ test_all<Layout<1>>();
+ test_all<Layout<2>>();
+ test_all<Layout<5>>();
+ test_all<Layout<dyn>>();
+ return true;
+ }
+
+template<template<size_t> typename Layout>
+ constexpr bool
+ test_padded_has_op_eq()
+ {
+ using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
+ test_has_op_eq<typename Traits::layout_same, Layout<0>, false>();
+ test_has_op_eq<typename Traits::layout_same, Layout<6>, false>();
+ test_has_op_eq<typename Traits::layout_same, Layout<dyn>, false>();
+ // The next one looks strange, because it's neither. Somehow, the
+ // conversion rules seem to be playing a critical role again.
+ // test_has_op_eq<typename Traits::layout_other, Layout<0>, false>();
+
+ test_has_op_eq<Layout<2>, Layout<6>, true>();
+ test_has_op_eq<Layout<2>, Layout<dyn>, true>();
+ return true;
+ }
+#endif
+
+int
+main()
+{
+ test_all<std::layout_left>();
+ test_all<std::layout_right>();
+ test_all<std::layout_stride>();
+#if __cplusplus > 202302L
+ test_padded_all<std::layout_left_padded>();
+ test_padded_all<std::layout_right_padded>();
+#endif
+
+ 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>();
+#if __cplusplus > 202302L
+ test_padded_has_op_eq<std::layout_left_padded>();
+ test_padded_has_op_eq<std::layout_right_padded>();
+#endif
+
+ test_has_op_eq_peculiar();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded.cc b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded.cc
new file mode 100644
index 0000000..1b6e063
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded.cc
@@ -0,0 +1,674 @@
+// { dg-do run { target c++26 } }
+#include <mdspan>
+
+#include <cstdint>
+#include "../int_like.h"
+#include "../layout_traits.h"
+#include <testsuite_hooks.h>
+
+constexpr size_t dyn = std::dynamic_extent;
+
+template<template<size_t> typename Layout>
+ constexpr bool
+ test_representable_padded_size()
+ {
+ using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
+ {
+ using E = typename Traits::extents_type<std::extents<uint8_t, 64, 2>>;
+ [[maybe_unused]] typename Layout<1>::mapping<E> m1;
+ }
+
+ {
+ using E = typename Traits::extents_type<std::extents<uint8_t, 0, 2>>;
+ [[maybe_unused]] typename Layout<0>::mapping<E> m1;
+ [[maybe_unused]] typename Layout<1>::mapping<E> m2;
+ [[maybe_unused]] typename Layout<128>::mapping<E> m3;
+ [[maybe_unused]] typename Layout<255>::mapping<E> m4;
+ }
+
+ {
+ using E = typename Traits::extents_type<std::extents<uint8_t, 0, 2>>;
+ [[maybe_unused]] typename Layout<dyn>::mapping<E> m1(E{}, 0);
+ [[maybe_unused]] typename Layout<dyn>::mapping<E> m2(E{}, 1);
+ [[maybe_unused]] typename Layout<dyn>::mapping<E> m3(E{}, 128);
+ [[maybe_unused]] typename Layout<dyn>::mapping<E> m4(E{}, 255);
+ }
+
+ {
+ using E = typename Traits::extents_type<std::extents<uint8_t, dyn, 2>>;
+ [[maybe_unused]] typename Layout<0>::mapping<E> m1;
+ [[maybe_unused]] typename Layout<1>::mapping<E> m2;
+ [[maybe_unused]] typename Layout<128>::mapping<E> m3;
+ [[maybe_unused]] typename Layout<255>::mapping<E> m4;
+ }
+ return true;
+ }
+
+template<typename Layout, typename CanonicalExtents>
+ constexpr void
+ test_default_ctor_single(auto canonical_strides)
+ {
+ using Traits = LayoutTraits<DeducePaddingSide::from_typename<Layout>()>;
+ using E = typename Traits::extents_type<CanonicalExtents>;
+ auto strides = Traits::make_array(canonical_strides);
+
+ typename Layout::template mapping<E> msta;
+ VERIFY(msta.stride(0) == strides[0]);
+ VERIFY(msta.stride(1) == strides[1]);
+ }
+
+
+template<template<size_t> typename Layout>
+ constexpr bool
+ test_default_ctor()
+ {
+ using E1 = std::extents<size_t, 3, 5>;
+ test_default_ctor_single<Layout<2>, E1>(std::array<size_t, 2>{1, 4});
+ test_default_ctor_single<Layout<dyn>, E1>(std::array<size_t, 2>{1, 3});
+
+ using E2 = std::extents<size_t, dyn, 5>;
+ test_default_ctor_single<Layout<2>, E2>(std::array<size_t, 2>{1, 0});
+ test_default_ctor_single<Layout<dyn>, E2>(std::array<size_t, 2>{1, 0});
+ return true;
+ }
+
+template<template<size_t> typename Layout>
+ constexpr bool
+ test_from_exts()
+ {
+ using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
+ auto exts = Traits::make_extents(std::dextents<size_t, 2>{3, 5});
+
+ typename Layout<0>::mapping m0_sta(exts);
+ VERIFY(Traits::padded_stride(m0_sta) == Traits::padded_extent(exts));
+
+ typename Layout<1>::mapping m1_sta(exts);
+ VERIFY(Traits::padded_stride(m1_sta) == Traits::padded_extent(exts));
+
+ typename Layout<2>::mapping m2_sta(exts);
+ VERIFY(Traits::padded_stride(m2_sta) == 4);
+
+ typename Layout<dyn>::mapping mdyn(exts);
+ VERIFY(Traits::padded_stride(mdyn) == Traits::padded_extent(exts));
+ return true;
+ }
+
+template<typename Layout, typename CustomPadType>
+ constexpr bool
+ test_from_pad_single()
+ {
+ using Traits = LayoutTraits<DeducePaddingSide::from_typename<Layout>()>;
+ auto pad = 3;
+ auto exts = Traits::make_extents(std::dextents<size_t, 3>{pad + 1, 5, 7});
+ typename Layout::mapping m(exts, CustomPadType{pad});
+ VERIFY(std::cmp_equal(Traits::padded_stride(m), 2*pad));
+ VERIFY(m.extents() == exts);
+ return true;
+ }
+
+template<typename Layout>
+ constexpr void
+ test_from_pad()
+ {
+ test_from_pad_single<Layout, int>();
+ static_assert(test_from_pad_single<Layout, int>());
+
+ test_from_pad_single<Layout, IntLike>();
+ test_from_pad_single<Layout, MutatingInt>();
+ test_from_pad_single<Layout, RValueInt>();
+
+ using Extents = std::dims<3>;
+ using Mapping = Layout::template mapping<Extents>;
+ static_assert(!std::is_constructible_v<Mapping, Extents, ThrowingInt>);
+ static_assert(!std::is_constructible_v<Mapping, Extents, NotIntLike>);
+ }
+
+template<template<size_t> typename Layout>
+ constexpr void
+ test_from_pad_all()
+ {
+ test_from_pad<Layout<3>>();
+ test_from_pad<Layout<dyn>>();
+ }
+
+constexpr bool
+is_same_mapping(const auto& lhs, const auto& rhs)
+{
+ if (lhs.extents().rank() != rhs.extents().rank())
+ return false;
+
+ if (lhs.extents() != rhs.extents())
+ return false;
+
+ for (size_t i = 0; i < lhs.extents().rank(); ++i)
+ if (lhs.stride(i) != rhs.stride(i))
+ return false;
+ return true;
+}
+
+enum class ConversionRule
+{
+ Never,
+ Regular
+};
+
+template<typename To, typename From>
+consteval bool
+should_convert(auto rule)
+{
+ if constexpr (rule == ConversionRule::Never)
+ return false;
+ else
+ return std::is_convertible_v<typename From::extents_type,
+ typename To::extents_type>;
+}
+
+template<typename To, typename From>
+ constexpr void
+ check_convertible(const From& m, auto conversion_rule)
+ {
+ VERIFY(is_same_mapping(m, To(m)));
+ constexpr bool expected = should_convert<To, From>(conversion_rule);
+ static_assert(std::is_convertible_v<From, To> == expected);
+ }
+
+template<typename LayoutTo, typename Esta, typename Edyn, typename Ewrong>
+ constexpr void
+ check_convertible_variants(auto msta, auto conversion_rule)
+ {
+ using LayoutFrom = decltype(msta)::layout_type;
+ constexpr auto cregular = std::cw<ConversionRule::Regular>;
+
+ // There's a twist when both mappings are left-padded. There's two distinct
+ // ctors: a defaulted copy ctor and a constrained template that enables
+ // construction from left-padded mappings even if their layout_type (padding) is
+ // different. The two ctors have different rules regarding conversion.
+
+ if constexpr (!std::same_as<LayoutTo, LayoutFrom>)
+ check_convertible<typename LayoutTo::mapping<Esta>>(msta, conversion_rule);
+ else
+ check_convertible<typename LayoutTo::mapping<Esta>>(msta, cregular);
+
+ check_convertible<typename LayoutTo::mapping<Edyn>>(msta, conversion_rule);
+
+ auto mdyn = typename LayoutFrom::mapping<Edyn>(msta);
+ check_convertible<typename LayoutTo::mapping<Esta>>(mdyn, conversion_rule);
+ if constexpr (!std::same_as<LayoutTo, LayoutFrom>)
+ check_convertible<typename LayoutTo::mapping<Edyn>>(mdyn, conversion_rule);
+ else
+ check_convertible<typename LayoutTo::mapping<Edyn>>(mdyn, cregular);
+
+ static_assert(!std::is_constructible_v<
+ typename LayoutTo::mapping<Esta>, typename LayoutFrom::mapping<Ewrong>>);
+ };
+
+template<typename Layout>
+ constexpr void
+ test_from_same_1d()
+ {
+ using E1 = std::extents<int, 6>;
+ using E2 = std::extents<int, dyn>;
+ using E3 = std::extents<int, 5>;
+ constexpr auto cr = std::cw<ConversionRule::Regular>;
+
+ using Traits = LayoutTraits<DeducePaddingSide::from_typename<Layout>()>;
+ auto msta = typename Traits::layout_same::mapping(E1{});
+ check_convertible_variants<Layout, E1, E2, E3>(msta, cr);
+ }
+
+template<typename Layout>
+ constexpr void
+ test_from_same_2d()
+ {
+ using Traits = LayoutTraits<DeducePaddingSide::from_typename<Layout>()>;
+ using E1 = typename Traits::extents_type<std::extents<int, 6, 5>>;
+ using E2 = typename Traits::extents_type<std::extents<int, dyn, 5>>;
+ using E3 = typename Traits::extents_type<std::extents<int, 6, 6>>;
+ constexpr auto cr = std::cw<ConversionRule::Regular>;
+
+ auto msta = typename Traits::layout_same::mapping(E1{});
+ check_convertible_variants<Layout, E1, E2, E3>(msta, cr);
+ }
+
+template<template<size_t> typename Layout>
+constexpr bool
+test_from_same()
+{
+ auto check = []<typename PaddedLayout>(PaddedLayout)
+ {
+ test_from_same_1d<PaddedLayout>();
+ test_from_same_2d<PaddedLayout>();
+ };
+
+ check(Layout<0>{});
+ check(Layout<1>{});
+ check(Layout<2>{});
+ check(Layout<6>{});
+ check(Layout<dyn>{});
+
+ // rank == 1 is more permissive:
+ test_from_same_1d<Layout<5>>();
+ return true;
+}
+
+template<template<size_t> typename Layout, typename E1_, typename E2_,
+ typename E3_>
+ constexpr bool
+ test_from_stride_nd(auto strides_)
+ {
+ using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
+ using E1 = typename Traits::extents_type<E1_>;
+ using E2 = typename Traits::extents_type<E2_>;
+ using E3 = typename Traits::extents_type<E3_>;
+ auto strides = Traits::make_array(strides_);
+
+ auto check = [&strides]<typename PaddedLayout>(PaddedLayout)
+ {
+ auto exts = E1{};
+ constexpr auto cr = std::cw<ConversionRule::Never>;
+
+ auto m = std::layout_stride::mapping(exts, strides);
+ check_convertible_variants<PaddedLayout, E1, E2, E3>(m, cr);
+ };
+
+ check(Layout<0>{});
+ check(Layout<1>{});
+ check(Layout<2>{});
+ check(Layout<6>{});
+ check(Layout<dyn>{});
+ return true;
+ }
+
+template<template<size_t> typename Layout>
+ constexpr bool
+ test_from_stride_2d()
+ {
+ using E1 = std::extents<size_t, 6, 5>;
+ using E2 = std::dims<2>;
+ using E3 = std::extents<size_t, 6, 6>;
+
+ auto strides = std::array<int, 2>{1, 6};
+ test_from_stride_nd<Layout, E1, E2, E3>(strides);
+ return true;
+ }
+
+template<template<size_t> typename Layout>
+ constexpr bool
+ test_from_stride_3d()
+ {
+ using E1 = std::extents<size_t, 6, 5, 7>;
+ using E2 = std::dims<3>;
+ using E3 = std::extents<size_t, 6, 6, 7>;
+
+ auto strides = std::array<int, 3>{1, 6, 6*5};
+ test_from_stride_nd<Layout, E1, E2, E3>(strides);
+ return true;
+ }
+
+template<template<size_t> typename Layout>
+ constexpr bool
+ test_from_stride()
+ {
+ test_from_stride_2d<Layout>();
+ test_from_stride_3d<Layout>();
+ return true;
+ }
+
+template<template<size_t> typename Layout>
+ constexpr void
+ test_from_samepad_0d()
+ {
+ using E1 = std::extents<uint16_t>;
+ using E2 = std::extents<uint8_t>;
+ using E3 = std::extents<uint8_t, 1>;
+
+ typename Layout<6>::mapping<E1> msta{E1{}};
+
+ auto check = []<typename To>(To, auto m)
+ {
+ constexpr auto cr = std::cw<ConversionRule::Regular>;
+ check_convertible_variants<To, E1, E2, E3>(m, cr);
+ };
+
+ check(Layout<6>{}, msta);
+ check(Layout<dyn>{}, msta);
+ }
+
+template<template<size_t> typename Layout>
+ constexpr void
+ test_from_samepad_1d()
+ {
+ using E1 = std::extents<int, 6>;
+ using E2 = std::extents<int, dyn>;
+ using E3 = std::extents<int, 6, 6>;
+
+ typename Layout<6>::mapping<E1> msta{E1{}};
+ typename Layout<dyn>::mapping<E1> mdyn{E1{}};
+
+ auto check = []<typename To>(To, auto m)
+ {
+ constexpr auto cr = std::cw<ConversionRule::Regular>;
+ check_convertible_variants<To, E1, E2, E3>(m, cr);
+ };
+
+ // Remember, for rank <= 1 the padding_value is irrelevant.
+ check(Layout<6>{}, msta);
+ check(Layout<6>{}, mdyn);
+ check(Layout<dyn>{}, msta);
+ check(Layout<dyn>{}, mdyn);
+ }
+
+template<template<size_t> typename Layout>
+ constexpr void
+ test_from_samepad_2d()
+ {
+ using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
+ using E1 = typename Traits::extents_type<std::extents<int, 6, 5>>;
+ using E2 = typename Traits::extents_type<std::extents<int, dyn, 5>>;
+ using E3 = typename Traits::extents_type<std::extents<int, 6, 6>>;
+
+ typename Layout<6>::mapping<E1> msta{E1{}};
+ typename Layout<dyn>::mapping<E1> mdyn{E1{}};
+
+ constexpr auto cregular = std::cw<ConversionRule::Regular>;
+ constexpr auto cnever = std::cw<ConversionRule::Never>;
+
+ auto check = []<typename To>(To, auto m, auto cr)
+ { check_convertible_variants<To, E1, E2, E3>(m, cr); };
+
+ check(Layout<6>{}, msta, cnever);
+ check(Layout<6>{}, mdyn, cnever);
+ check(Layout<dyn>{}, msta, cregular);
+ check(Layout<dyn>{}, mdyn, cnever);
+ }
+
+template<template<size_t> typename Layout>
+ constexpr bool
+ test_from_samepad()
+ {
+ test_from_samepad_0d<Layout>();
+ test_from_samepad_1d<Layout>();
+ test_from_samepad_2d<Layout>();
+ return true;
+ }
+
+template<template<size_t> typename Layout>
+ constexpr bool
+ test_from_other()
+ {
+ using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
+ using E1 = std::extents<size_t, 3>;
+ using E2 = std::dims<1>;
+ using E3 = std::extents<size_t, 5>;
+
+ auto check = []<typename PaddedLayout>(PaddedLayout)
+ {
+ constexpr auto cr = std::cw<ConversionRule::Regular>;
+
+ using layout_other = typename Traits::layout_other;
+ auto msta = typename layout_other::mapping(E1{});
+ check_convertible_variants<PaddedLayout, E1, E2, E3>(msta, cr);
+ };
+
+
+ // Remember, the padding_value has no effect for rank <= 1.
+ check(Layout<0>{});
+ check(Layout<1>{});
+ check(Layout<2>{});
+ check(Layout<5>{});
+ check(Layout<6>{});
+ check(Layout<dyn>{});
+ return true;
+ }
+
+template<template<size_t> typename Layout>
+ constexpr bool
+ test_to_same()
+ {
+ using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
+ using E1 = typename Traits::extents_type<std::extents<int, 6, 5>>;
+ using E2 = typename Traits::extents_type<std::extents<int, dyn, 5>>;
+ using E3 = typename Traits::extents_type<std::extents<int, 6, 6>>;
+
+ auto check = [](auto msta)
+ {
+ constexpr auto cr = std::cw<ConversionRule::Regular>;
+ using LayoutSame = typename Traits::layout_same;
+ check_convertible_variants<LayoutSame, E1, E2, E3>(msta, cr);
+ };
+
+ check(typename Layout<0>::mapping(E1{}));
+ check(typename Layout<2>::mapping(E1{}));
+ check(typename Layout<6>::mapping(E1{}));
+ check(typename Layout<dyn>::mapping(E1{}, 0));
+ check(typename Layout<dyn>::mapping(E1{}, 2));
+ check(typename Layout<dyn>::mapping(E1{}, 6));
+ return true;
+ }
+
+template<template<size_t> typename Layout>
+ constexpr bool
+ test_never_to_other()
+ {
+ using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
+ using E1 = std::extents<size_t, 3>;
+ using E2 = std::dims<1>;
+
+ auto check = []<typename PaddedLayout>(PaddedLayout, auto exts)
+ {
+ using LayoutOther = typename Traits::layout_other;
+ auto mr = typename LayoutOther::mapping(exts);
+ auto mlp = typename PaddedLayout::mapping<decltype(exts)>{mr};
+ static_assert(!std::is_constructible_v<decltype(mr), decltype(mlp)>);
+ };
+
+ check(Layout<2>{}, E1{});
+ check(Layout<2>{}, E2{E1{}});
+ return true;
+ }
+
+template<typename Layout>
+ constexpr void
+ test_strides()
+ {
+ auto check = [](auto exts)
+ {
+ auto m = typename Layout::mapping(exts);
+ using IndexType = typename decltype(m)::index_type;
+ constexpr size_t rank = decltype(m)::extents_type::rank();
+
+ auto strides = m.strides();
+ static_assert(std::same_as<decltype(strides),
+ std::array<IndexType, rank>>);
+ VERIFY(strides.size() == rank);
+ for (size_t i = 0; i < strides.size(); ++i)
+ VERIFY(strides[i] == m.stride(i));
+ };
+
+ check(std::extents());
+ check(std::extents(0));
+ check(std::extents(3));
+ check(std::extents(3, 5, 7));
+ check(std::extents(3, 0, 7));
+ }
+
+template<template<size_t> typename Layout>
+ constexpr bool
+ test_strides_all()
+ {
+ test_strides<Layout<0>>();
+ test_strides<Layout<1>>();
+ test_strides<Layout<3>>();
+ test_strides<Layout<dyn>>();
+ return true;
+ }
+
+template<template<size_t> typename Layout>
+ constexpr void
+ test_exhaustive_0d()
+ {
+ auto exts = std::extents<int>{};
+
+ auto check = [](auto m)
+ {
+ static_assert(m.is_always_exhaustive());
+ VERIFY(m.is_exhaustive());
+ };
+
+ check(typename Layout<0>::mapping(exts));
+ check(typename Layout<1>::mapping(exts));
+ check(typename Layout<2>::mapping(exts));
+ check(typename Layout<dyn>::mapping(exts));
+ }
+
+template<template<size_t> typename Layout>
+constexpr void
+ test_exhaustive_1d()
+ {
+ auto check_dyn_and_sta = []<typename PaddedLayout>(PaddedLayout)
+ {
+ auto check = [](auto exts)
+ {
+ auto m = typename PaddedLayout::mapping(exts);
+ static_assert(m.is_always_exhaustive());
+ VERIFY(m.is_exhaustive());
+ };
+
+ check(std::extents(4));
+ check(std::extents<int, 4>{});
+ };
+
+ check_dyn_and_sta(Layout<1>{});
+ check_dyn_and_sta(Layout<2>{});
+ check_dyn_and_sta(Layout<6>{});
+ check_dyn_and_sta(Layout<dyn>{});
+ }
+
+template<template<size_t> typename Layout>
+ constexpr void
+ test_exhaustive_3d()
+ {
+ using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
+ auto exts_dyn = Traits::make_extents(std::extents(4, 5, 7));
+ auto exts_sta = Traits::make_extents(std::extents<int, 4, 5, 7>{});
+ auto ctrue = std::cw<true>;
+ auto cfalse= std::cw<false>;
+
+ auto check = [](auto m, auto static_expected, auto runtime_expected)
+ {
+ static_assert(m.is_always_exhaustive() == static_expected);
+ VERIFY(m.is_exhaustive() == runtime_expected);
+ };
+
+ check(typename Layout<0>::mapping(exts_sta), ctrue, true);
+ check(typename Layout<0>::mapping(exts_dyn), cfalse, true);
+ check(typename Layout<1>::mapping(exts_sta), ctrue, true);
+ check(typename Layout<1>::mapping(exts_dyn), cfalse, true);
+ check(typename Layout<2>::mapping(exts_sta), ctrue, true);
+ check(typename Layout<2>::mapping(exts_dyn), cfalse, true);
+ check(typename Layout<6>::mapping(exts_dyn), cfalse, false);
+ check(typename Layout<6>::mapping(exts_sta), cfalse, false);
+ check(typename Layout<dyn>::mapping(exts_sta), cfalse, true);
+ check(typename Layout<dyn>::mapping(exts_dyn, 2), cfalse, true);
+ check(typename Layout<dyn>::mapping(exts_dyn, 3), cfalse, false);
+ }
+
+template<template<size_t> typename Layout>
+ constexpr bool
+ test_exhaustive()
+ {
+ test_exhaustive_0d<Layout>();
+ test_exhaustive_1d<Layout>();
+ test_exhaustive_3d<Layout>();
+ return true;
+ }
+
+template<template<size_t> typename Layout>
+ constexpr bool
+ test_op_eq()
+ {
+ // The generic cases are handled in layouts/mapping.cc. Here we check
+ // special cases related to non exhaustive layouts.
+ using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
+
+ auto exts_sta = Traits::make_extents(std::extents<size_t, 6, 5, 7>{});
+ auto exts_dyn = std::dims<3>(exts_sta);
+ auto exts_other = Traits::make_extents(std::extents<size_t, 7, 5, 7>{});
+
+ auto m1 = typename Layout<0>::mapping(exts_sta);
+ auto m2 = typename Layout<7>::mapping(exts_sta);
+
+ VERIFY(m1 == typename Layout<0>::mapping(exts_sta));
+ VERIFY(m1 == typename Layout<1>::mapping(exts_sta));
+ VERIFY(m1 == typename Layout<2>::mapping(exts_sta));
+ VERIFY(m1 == typename Layout<6>::mapping(exts_sta));
+ VERIFY(m1 != typename Layout<7>::mapping(exts_sta));
+ VERIFY(m1 == typename Layout<dyn>::mapping(exts_sta));
+ VERIFY(m1 != typename Layout<dyn>::mapping(exts_sta, 7));
+
+ VERIFY(m1 == typename Layout<0>::mapping(exts_dyn));
+ VERIFY(m1 == typename Layout<1>::mapping(exts_dyn));
+ VERIFY(m1 == typename Layout<2>::mapping(exts_dyn));
+ VERIFY(m1 == typename Layout<6>::mapping(exts_dyn));
+ VERIFY(m1 != typename Layout<7>::mapping(exts_dyn));
+ VERIFY(m1 == typename Layout<dyn>::mapping(exts_dyn));
+ VERIFY(m1 != typename Layout<dyn>::mapping(exts_dyn, 7));
+
+ VERIFY(m2 == typename Layout<7>::mapping(exts_sta));
+ VERIFY(m2 == typename Layout<dyn>::mapping(exts_sta, 7));
+ VERIFY(m2 == typename Layout<7>::mapping(exts_dyn));
+ VERIFY(m2 == typename Layout<dyn>::mapping(exts_dyn, 7));
+
+ VERIFY(m2 != typename Layout<7>::mapping(exts_other));
+ VERIFY(m2 != typename Layout<dyn>::mapping(exts_other, 7));
+ return true;
+ }
+
+template<template<size_t> typename Layout>
+ constexpr bool
+ test_required_span_size_overflow()
+ {
+ using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
+ using Extents = std::dextents<uint8_t, 2>;
+ auto exts = Traits::make_extents(Extents{64, 2});
+ auto strides = Traits::make_array(std::array<uint8_t, 2>{1, 128});
+ auto ms = std::layout_stride::mapping(exts, strides);
+ auto m = typename Layout<dyn>::mapping<Extents>(ms);
+ VERIFY(is_same_mapping(m, ms));
+ VERIFY(m.required_span_size() == ms.required_span_size());
+ return true;
+ }
+
+template<template<size_t> typename Layout>
+ constexpr bool
+ test_all()
+ {
+ test_representable_padded_size<std::layout_left_padded>();
+ test_default_ctor<Layout>();
+ test_from_exts<Layout>();
+ test_from_stride<Layout>();
+ test_from_samepad<Layout>();
+ test_from_same<Layout>();
+ test_from_other<Layout>();
+ test_to_same<Layout>();
+ test_never_to_other<Layout>();
+ test_strides_all<Layout>();
+ test_exhaustive<Layout>();
+ test_op_eq<Layout>();
+ test_required_span_size_overflow<Layout>();
+ return true;
+ }
+
+int
+main()
+{
+ test_all<std::layout_left_padded>();
+ static_assert(test_all<std::layout_left_padded>());
+
+ test_all<std::layout_right_padded>();
+ static_assert(test_all<std::layout_right_padded>());
+
+ test_from_pad_all<std::layout_left_padded>();
+ test_from_pad_all<std::layout_right_padded>();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded_neg.cc b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded_neg.cc
new file mode 100644
index 0000000..4073f68
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded_neg.cc
@@ -0,0 +1,352 @@
+// { dg-do compile { target c++26 } }
+#include <mdspan>
+
+#include "../layout_traits.h"
+#include <cstdint>
+
+constexpr size_t dyn = std::dynamic_extent;
+
+template<template<size_t> typename Layout>
+ constexpr bool
+ test_from_extens_representable_sta()
+ {
+ using E1 = std::extents<uint8_t, 8, 128>;
+ auto m = typename Layout<dyn>::mapping(E1{}); // { dg-error "required from" }
+ return true;
+ }
+static_assert(test_from_extens_representable_sta<std::layout_left_padded>()); // { dg-error "from here" }
+static_assert(test_from_extens_representable_sta<std::layout_right_padded>()); // { dg-error "from here" }
+
+template<template<size_t> typename Layout>
+ constexpr bool
+ test_from_extents_representable_padded_size()
+ {
+ using E1 = std::extents<uint8_t, 8, 128>;
+ using E2 = std::dextents<uint8_t, 2>;
+
+ auto m = typename Layout<dyn>::mapping(E2{E1{}}); // { dg-error "expansion of" }
+ (void) m;
+ return true;
+ }
+static_assert(test_from_extents_representable_padded_size<std::layout_left_padded>()); // { dg-error "expansion of" }
+static_assert(test_from_extents_representable_padded_size<std::layout_right_padded>()); // { dg-error "expansion of" }
+
+template<template<size_t> typename Layout>
+ constexpr bool
+ test_from_extents_representable_stride()
+ {
+ using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
+ using E1 = typename Traits::extents_type<std::extents<uint8_t, dyn, 1>>;
+ auto m = typename Layout<128>::mapping(E1{129}); // { dg-error "expansion of" }
+ (void) m;
+ return true;
+ }
+static_assert(test_from_extents_representable_stride<std::layout_left_padded>()); // { dg-error "expansion of" }
+static_assert(test_from_extents_representable_stride<std::layout_right_padded>()); // { dg-error "expansion of" }
+
+template<template<size_t> typename Layout>
+ constexpr bool
+ test_from_pad_representable_stride()
+ {
+ using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
+ auto exts = Traits::make_extents(std::dextents<uint8_t, 2>(129, 2));
+ auto m = typename Layout<dyn>::mapping(exts, 128); // { dg-error "expansion of" }
+ return true;
+ }
+static_assert(test_from_pad_representable_stride<std::layout_left_padded>()); // { dg-error "expansion of" }
+static_assert(test_from_pad_representable_stride<std::layout_right_padded>()); // { dg-error "expansion of" }
+
+template<template<size_t> typename Layout>
+ constexpr bool
+ test_from_pad_representable_padded_size()
+ {
+ using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
+ auto exts = Traits::make_extents(std::dextents<uint8_t, 2>(64, 2));
+ auto m = typename Layout<dyn>::mapping(exts, 128); // { dg-error "expansion of" }
+ return true;
+ }
+static_assert(test_from_pad_representable_padded_size<std::layout_left_padded>()); // { dg-error "expansion of" }
+static_assert(test_from_pad_representable_padded_size<std::layout_right_padded>()); // { dg-error "expansion of" }
+
+template<template<size_t> typename Layout>
+ constexpr bool
+ test_from_left()
+ {
+ using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
+ using LayoutSame = typename Traits::layout_same;
+ auto exts = Traits::make_extents(std::extents<uint8_t, 6, dyn>{4});
+ auto ml = typename LayoutSame::mapping(exts);
+
+ typename Layout<4>::mapping<decltype(exts)> m(ml); // { dg-error "expansion of" }
+ return true;
+ }
+static_assert(test_from_left<std::layout_left_padded>()); // { dg-error "required from here" }
+static_assert(test_from_left<std::layout_right_padded>()); // { dg-error "required from here" }
+
+template<template<size_t> typename Layout>
+ constexpr bool
+ test_from_left_bad_runtime_stride()
+ {
+ using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
+ auto exts = Traits::make_extents(std::extents<uint8_t, dyn, dyn>{6, 4});
+ auto ml = typename Traits::layout_same::mapping(exts);
+
+ typename Layout<4>::mapping<decltype(exts)> m(ml); // { dg-error "expansion of" }
+ (void) m;
+ return true;
+ }
+static_assert(test_from_left_bad_runtime_stride<std::layout_left_padded>()); // { dg-error "expansion of" }
+static_assert(test_from_left_bad_runtime_stride<std::layout_right_padded>()); // { dg-error "expansion of" }
+
+template<template<size_t> typename Layout>
+ constexpr bool
+ test_from_left_representable_extents()
+ {
+ using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
+ auto exts = Traits::make_extents(std::extents<uint16_t, dyn, dyn>{8, 128});
+ auto ml = typename Traits::layout_same::mapping(exts);
+
+ typename Layout<8>::mapping<std::extents<uint8_t, dyn, dyn>> m(ml); // { dg-error "expansion of" }
+ return true;
+ }
+static_assert(test_from_left_representable_extents<std::layout_left_padded>()); // { dg-error "expansion of" }
+static_assert(test_from_left_representable_extents<std::layout_right_padded>()); // { dg-error "expansion of" }
+
+template<template<size_t> typename Layout, size_t PaddingValue>
+ constexpr bool
+ test_pad_overflow()
+ {
+ auto exts = std::extents<uint8_t, dyn>{4};
+ auto n = size_t(1) << 9;
+ auto m = typename Layout<PaddingValue>::mapping(exts, n);
+ (void) m;
+ return true;
+ }
+static_assert(test_pad_overflow<std::layout_left_padded, 1>()); // { dg-error "expansion of" }
+static_assert(test_pad_overflow<std::layout_left_padded, dyn>()); // { dg-error "expansion of" }
+static_assert(test_pad_overflow<std::layout_right_padded, 1>()); // { dg-error "expansion of" }
+static_assert(test_pad_overflow<std::layout_right_padded, dyn>()); // { dg-error "expansion of" }
+
+template<template<size_t> typename Layout, size_t PaddingValue>
+ constexpr bool
+ test_from_pad_negative()
+ {
+ auto exts = std::extents(4);
+ auto m = typename Layout<PaddingValue>::mapping(exts, -1);
+ (void) m;
+ return true;
+ }
+static_assert(test_from_pad_negative<std::layout_left_padded, 1>()); // { dg-error "expansion of" }
+static_assert(test_from_pad_negative<std::layout_left_padded, dyn>()); // { dg-error "expansion of" }
+static_assert(test_from_pad_negative<std::layout_right_padded, 1>()); // { dg-error "expansion of" }
+static_assert(test_from_pad_negative<std::layout_right_padded, dyn>()); // { dg-error "expansion of" }
+
+template<template<size_t> typename Layout, size_t Pad>
+ constexpr bool
+ test_static_pad_same()
+ {
+ using Extents = std::extents<int, dyn>;
+ using Mapping = typename Layout<Pad>::mapping<Extents>;
+ auto exts = Extents{4};
+ auto m = Mapping(exts, Pad + 1); // { dg-error "expansion of" }
+ (void) m;
+ return true;
+ }
+static_assert(test_static_pad_same<std::layout_left_padded, 1>()); // { dg-error "expansion of" }
+static_assert(test_static_pad_same<std::layout_left_padded, 3>()); // { dg-error "expansion of" }
+static_assert(test_static_pad_same<std::layout_right_padded, 1>()); // { dg-error "expansion of" }
+static_assert(test_static_pad_same<std::layout_right_padded, 3>()); // { dg-error "expansion of" }
+
+template<template<size_t> typename Layout>
+ constexpr bool
+ test_from_stride_wrong_stride0()
+ {
+ using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
+ auto e = Traits::make_extents(std::extents{3, 5});
+ auto s = Traits::make_array(std::array<int, 2>{2, 7});
+ auto ms = std::layout_stride::mapping(e, s);
+ auto m = typename Layout<dyn>::mapping<decltype(e)>(ms); // { dg-error "expansion of" }
+ (void) m;
+ return true;
+ }
+static_assert(test_from_stride_wrong_stride0<std::layout_left_padded>()); // { dg-error "expansion of" }
+static_assert(test_from_stride_wrong_stride0<std::layout_right_padded>()); // { dg-error "expansion of" }
+
+template<template<size_t> typename Layout>
+ constexpr bool
+ test_from_stride_wrong_stride1()
+ {
+ using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
+ auto e = Traits::make_extents(std::extents(3, 5));
+ auto s = Traits::make_array(std::array<int, 2>{1, 3});
+ auto ms = std::layout_stride::mapping(e, s);
+ auto m = typename Layout<2>::mapping<decltype(e)>(ms); // { dg-error "expansion of" }
+ (void) m;
+ return true;
+ }
+static_assert(test_from_stride_wrong_stride1<std::layout_left_padded>()); // { dg-error "expansion of" }
+static_assert(test_from_stride_wrong_stride1<std::layout_right_padded>()); // { dg-error "expansion of" }
+
+template<template<size_t> typename Layout>
+ constexpr bool
+ test_from_stride_wrong_stride2()
+ {
+ using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
+ auto e = Traits::make_extents(std::extents(3, 5, 7));
+ auto s = Traits::make_array(std::array<int, 3>{1, 4, 21});
+ auto ms = std::layout_stride::mapping(e, s);
+ auto m = typename Layout<dyn>::mapping<decltype(e)>(ms); // here (not implemented)
+ (void) m;
+ return true;
+ }
+static_assert(test_from_stride_wrong_stride2<std::layout_left_padded>());
+static_assert(test_from_stride_wrong_stride2<std::layout_right_padded>());
+
+template<template<size_t> typename Layout>
+ constexpr bool
+ test_from_stride_oversized()
+ {
+ using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
+ auto exts = Traits::make_extents(std::extents<uint16_t, dyn, dyn>{3, 6});
+ auto s = Traits::make_array(std::array<uint16_t, 2>{1, 128});
+ auto ms = std::layout_stride::mapping(exts, s);
+
+ using Mapping = typename Layout<dyn>::mapping<std::dextents<uint8_t, 2>>;
+ Mapping m(ms); // { dg-error "expansion of" }
+ (void) m;
+ return true;
+ }
+static_assert(test_from_stride_oversized<std::layout_left_padded>()); // { dg-error "expansion of" }
+static_assert(test_from_stride_oversized<std::layout_right_padded>()); // { dg-error "expansion of" }
+
+template<template<size_t> typename Layout>
+ constexpr bool
+ test_from_samepad_dyn()
+ {
+ using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
+ auto e = Traits::make_extents(std::extents(3, 5));
+ auto mlp = typename Layout<dyn>::mapping(e);
+ auto m = typename Layout<2>::mapping<decltype(e)>(mlp); // { dg-error "expansion of" }
+ (void) m;
+ return true;
+ }
+static_assert(test_from_samepad_dyn<std::layout_left_padded>()); // { dg-error "expansion of" }
+static_assert(test_from_samepad_dyn<std::layout_right_padded>()); // { dg-error "expansion of" }
+
+template<template<size_t> typename Layout>
+ constexpr bool
+ test_from_samepad_sta()
+ {
+ using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
+ auto e = Traits::make_extents(std::extents{3, 5});
+ auto mlp = typename Layout<3>::mapping(e);
+ auto m = typename Layout<2>::mapping<decltype(e)>(mlp); // { dg-error "expansion of" }
+ (void) m;
+ return true;
+ }
+static_assert(test_from_samepad_sta<std::layout_left_padded>()); // { dg-error "expansion of" }
+static_assert(test_from_samepad_sta<std::layout_right_padded>()); // { dg-error "expansion of" }
+
+template<template<size_t> typename Layout>
+ constexpr bool
+ test_from_samepad_oversized()
+ {
+ using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
+ using E1 = typename Traits::extents_type<std::extents<uint16_t, 8, 128>>;
+ using E2 = typename Traits::extents_type<std::extents<uint8_t, dyn, dyn>>;
+ auto mlp = typename Layout<dyn>::mapping<E1>(E1{});
+ auto m = typename Layout<dyn>::mapping<E2>(mlp); // { dg-error "expansion of" }
+ (void) m;
+ return true;
+ }
+static_assert(test_from_samepad_oversized<std::layout_left_padded>()); // { dg-error "expansion of" }
+static_assert(test_from_samepad_oversized<std::layout_right_padded>()); // { dg-error "expansion of" }
+
+template<template<size_t> typename Layout, size_t RunId>
+ constexpr bool
+ test_to_same_not_exhaustive()
+ {
+ using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
+ using E1 = typename Traits::extents_type<std::extents<int, 6, 5>>;
+ using E2 = typename Traits::extents_type<std::extents<int, dyn, 5>>;
+
+ [[maybe_unused]] auto msta = typename Layout<7>::mapping(E1{});
+ if constexpr (RunId == 0)
+ {
+ auto m = typename Traits::layout_same::mapping<E1>(msta); // { dg-error "required from" }
+ (void) m;
+ }
+ if constexpr (RunId == 1)
+ {
+ auto m = typename Traits::layout_same::mapping<E2>(msta); // { dg-error "expansion of" }
+ (void) m;
+ }
+
+ [[maybe_unused]] auto mdyn = typename Layout<dyn>::mapping(E2{E1{}}, 7);
+ if constexpr (RunId == 2)
+ {
+ auto m = typename Traits::layout_same::mapping<E1>(mdyn); // { dg-error "expansion of" }
+ (void) m;
+ }
+ if constexpr (RunId == 3)
+ {
+ auto m = typename Traits::layout_same::mapping<E2>(mdyn); // { dg-error "expansion of" }
+ (void) m;
+ }
+ return true;
+ }
+static_assert(test_to_same_not_exhaustive<std::layout_left_padded, 0>()); // { dg-error "expansion of" }
+static_assert(test_to_same_not_exhaustive<std::layout_left_padded, 1>()); // { dg-error "expansion of" }
+static_assert(test_to_same_not_exhaustive<std::layout_left_padded, 2>()); // { dg-error "expansion of" }
+static_assert(test_to_same_not_exhaustive<std::layout_left_padded, 3>()); // { dg-error "expansion of" }
+static_assert(test_to_same_not_exhaustive<std::layout_right_padded, 0>()); // { dg-error "expansion of" }
+static_assert(test_to_same_not_exhaustive<std::layout_right_padded, 1>()); // { dg-error "expansion of" }
+static_assert(test_to_same_not_exhaustive<std::layout_right_padded, 2>()); // { dg-error "expansion of" }
+static_assert(test_to_same_not_exhaustive<std::layout_right_padded, 3>()); // { dg-error "expansion of" }
+
+template<template<size_t> typename Layout>
+ constexpr bool
+ test_statically_bad_padding_value1()
+ {
+ using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
+ constexpr auto N = std::numeric_limits<size_t>::max() - 1;
+ using Extents = typename Traits::extents_type<std::extents<size_t, N, 0>>;
+ typename Layout<10>::mapping<Extents> m; // { dg-error "required from" }
+ return true;
+ }
+static_assert(test_statically_bad_padding_value1<std::layout_left_padded>()); // { dg-error "required from" }
+static_assert(test_statically_bad_padding_value1<std::layout_right_padded>()); // { dg-error "required from" }
+
+template<template<size_t> typename Layout>
+ constexpr bool
+ test_statically_bad_padding_value2()
+ {
+ using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
+ using Extents = typename Traits::extents_type<std::extents<uint8_t, 255, 0>>;
+ typename Layout<2>::mapping<Extents> m; // { dg-error "required from" }
+ return true;
+ }
+static_assert(test_statically_bad_padding_value2<std::layout_left_padded>()); // { dg-error "required from" }
+static_assert(test_statically_bad_padding_value2<std::layout_right_padded>()); // { dg-error "required from" }
+
+template<template<size_t> typename Layout>
+ constexpr bool
+ test_statically_oversized()
+ {
+ using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
+ using Extents = typename Traits::extents_type<std::extents<uint8_t, 127, 2>>;
+ typename Layout<2>::mapping<Extents> m; // { dg-error "required from" }
+ return true;
+ }
+static_assert(test_statically_oversized<std::layout_left_padded>()); // { dg-error "from here" }
+static_assert(test_statically_oversized<std::layout_right_padded>()); // { dg-error "from here" }
+
+// { dg-prune-output "padding_value must be representable as index_type" }
+// { dg-prune-output "non-constant condition for static assertion" }
+// { dg-prune-output "called in a constant expression" }
+// { dg-prune-output "no matching function" }
+// { dg-prune-output "static assertion failed" }
+// { dg-prune-output "__glibcxx_assert_fail()" }
+// { dg-prune-output "must be compatible with other.stride" }
+// { dg-prune-output "padding_value is dynamic_extent" }
+// { dg-prune-output "_S_rank <= 1" }
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..8d2fad2
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/stride.cc
@@ -0,0 +1,513 @@
+// { dg-do run { target c++23 } }
+#include <mdspan>
+
+#include "../int_like.h"
+#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;
+}
+
+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, IntLike, 0, true>();
+ test_stride_constructible<E0, E0, ThrowingInt, 0, false>();
+ test_stride_constructible<E0, E0, MutatingInt, 0, false>();
+ 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/mdspan/mdspan.cc b/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc
new file mode 100644
index 0000000..a92a055
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc
@@ -0,0 +1,779 @@
+// { dg-do run { target c++23 } }
+#include <mdspan>
+
+#include <testsuite_hooks.h>
+#include "int_like.h"
+#include "layout_like.h"
+#include <stdexcept>
+
+constexpr auto dyn = std::dynamic_extent;
+
+template<typename MDSpan, typename T, typename E, typename L = std::layout_right,
+ typename A = std::default_accessor<T>>
+ constexpr void
+ assert_typedefs()
+ {
+ static_assert(std::same_as<typename MDSpan::extents_type, E>);
+ static_assert(std::same_as<typename MDSpan::layout_type, L>);
+ static_assert(std::same_as<typename MDSpan::accessor_type, A>);
+ static_assert(std::same_as<typename MDSpan::mapping_type,
+ typename L::mapping<E>>);
+ static_assert(std::same_as<typename MDSpan::element_type, T>);
+ static_assert(std::same_as<typename MDSpan::value_type,
+ std::remove_const_t<T>>);
+ static_assert(std::same_as<typename MDSpan::index_type,
+ typename E::index_type>);
+ static_assert(std::same_as<typename MDSpan::size_type,
+ typename E::size_type>);
+ static_assert(std::same_as<typename MDSpan::rank_type,
+ typename E::rank_type>);
+ static_assert(std::same_as<typename MDSpan::data_handle_type,
+ typename A::data_handle_type>);
+ static_assert(std::same_as<typename MDSpan::reference,
+ typename A::reference>);
+ }
+
+template<typename T, typename E, typename L, template<typename U> typename A>
+ constexpr void
+ test_typedefs()
+ { assert_typedefs<std::mdspan<T, E, L, A<T>>, T, E, L, A<T>>(); }
+
+constexpr void
+test_typedefs_all()
+{
+ using E = std::extents<int, 1, 2>;
+ using L = std::layout_left;
+
+ test_typedefs<double, E, L, std::default_accessor>();
+ test_typedefs<const double, E, L, std::default_accessor>();
+}
+
+template<typename MDSpan>
+ constexpr void
+ test_rank()
+ {
+ using Extents = typename MDSpan::extents_type;
+ static_assert(MDSpan::rank() == Extents::rank());
+ static_assert(MDSpan::rank_dynamic() == Extents::rank_dynamic());
+ }
+
+constexpr bool
+test_rank_all()
+{
+ test_rank<std::mdspan<double, std::extents<int>>>();
+ test_rank<std::mdspan<double, std::extents<int, 1>>>();
+ test_rank<std::mdspan<double, std::extents<int, dyn>>>();
+ return true;
+}
+
+template<typename Extents>
+ constexpr void
+ test_extent(Extents exts)
+ {
+ double data = 1.0;
+ auto md = std::mdspan(&data, exts);
+ using MDSpan = decltype(md);
+
+ for(size_t i = 0; i < MDSpan::rank(); ++i)
+ {
+ VERIFY(MDSpan::static_extent(i) == Extents::static_extent(i));
+ VERIFY(md.extent(i) == exts.extent(i));
+ }
+ }
+
+constexpr bool
+test_extent_all()
+{
+ // For rank == 0, check existence of the methods without calling them.
+ test_extent(std::extents<int>{});
+ test_extent(std::extents<int, 0>{});
+ test_extent(std::extents<int, dyn>{});
+ return true;
+}
+
+template<typename MDSpan>
+ constexpr void
+ test_class_properties()
+ {
+ static_assert(std::copyable<MDSpan>);
+ static_assert(std::is_nothrow_move_constructible_v<MDSpan>);
+ static_assert(std::is_nothrow_move_assignable_v<MDSpan>);
+ static_assert(std::is_nothrow_swappable_v<MDSpan>);
+ constexpr bool trivially_copyable =
+ std::is_trivially_copyable_v<typename MDSpan::accessor_type>
+ && std::is_trivially_copyable_v<typename MDSpan::mapping_type>
+ && std::is_trivially_copyable_v<typename MDSpan::data_handle_type>;
+ static_assert(std::is_trivially_copyable_v<MDSpan> == trivially_copyable);
+ }
+
+constexpr bool
+test_class_properties_all()
+{
+ test_class_properties<std::mdspan<double, std::extents<int>>>();
+ test_class_properties<std::mdspan<double, std::extents<int, 1>>>();
+ test_class_properties<std::mdspan<double, std::extents<int, dyn>>>();
+ return true;
+}
+
+template<typename T>
+ class ThrowingDefaultAccessor
+ {
+ public:
+ using element_type = T;
+ using reference = element_type&;
+ using data_handle_type = element_type*;
+ using offset_policy = ThrowingDefaultAccessor;
+
+ ThrowingDefaultAccessor() noexcept(false)
+ { }
+
+ reference
+ access(data_handle_type p, size_t i) const
+ { return p[i]; }
+
+ typename offset_policy::data_handle_type
+ offset(data_handle_type p, size_t i) const
+ { return p + i; }
+ };
+
+constexpr bool
+test_default_ctor()
+{
+ static_assert(!std::is_default_constructible_v<std::mdspan<double,
+ std::extents<int>>>);
+ static_assert(!std::is_default_constructible_v<std::mdspan<double,
+ std::extents<int, 1>>>);
+ static_assert(std::is_default_constructible_v<std::mdspan<double,
+ std::extents<int, dyn>>>);
+
+ std::mdspan<double, std::extents<int, dyn>> md;
+ VERIFY(md.data_handle() == nullptr);
+ VERIFY(md.empty());
+ return true;
+}
+
+template<template<typename T> typename Accessor, bool Expected>
+ constexpr void
+ test_nothrow_default_ctor()
+ {
+ using Extents = std::extents<int, dyn>;
+ using Layout = std::layout_left;
+ using MDSpan = std::mdspan<double, Extents, Layout, Accessor<double>>;
+
+ static_assert(std::is_default_constructible_v<MDSpan>);
+ static_assert(std::is_nothrow_default_constructible_v<MDSpan> == Expected);
+ }
+
+constexpr bool
+test_from_other()
+{
+ using Extents = std::extents<int, 3, 5, 7>;
+ auto exts = Extents{};
+
+ auto mapping = std::layout_right::mapping(exts);
+ constexpr size_t n = mapping.required_span_size();
+ std::array<double, n> storage{};
+
+ auto md1 = std::mdspan(storage.data(), exts);
+ auto md2 = std::mdspan<double, std::dextents<int, 3>>(md1);
+
+ VERIFY(md1.data_handle() == md2.data_handle());
+ VERIFY(md1.size() == md2.size());
+
+ static_assert(!std::is_convertible_v<
+ std::mdspan<double, std::extents<unsigned int, 2>>,
+ std::mdspan<double, std::extents<int, 2>>>);
+
+ static_assert(std::is_convertible_v<
+ std::mdspan<double, std::extents<int, 2>>,
+ std::mdspan<const double, std::extents<int, 2>>>);
+
+ static_assert(!std::is_constructible_v<
+ std::mdspan<double, std::extents<int, 2>>,
+ std::mdspan<const double, std::extents<int, 2>>>);
+
+ return true;
+}
+
+template<typename T, typename E, typename L = std::layout_right,
+ typename A = std::default_accessor<T>>
+ constexpr void
+ assert_deduced_typedefs(auto md)
+ { assert_typedefs<decltype(md), T, E, L, A>(); }
+
+constexpr bool
+test_from_carray()
+{
+ constexpr size_t n = 5;
+ double data[n] = {1.1, 2.2, 3.3, 4.4, 5.5};
+
+ auto md = std::mdspan(data);
+ assert_deduced_typedefs<double, std::extents<size_t, n>>(md);
+ VERIFY(md.rank() == 1);
+ VERIFY(md.rank_dynamic() == 0);
+ VERIFY(md[2] == data[2]);
+ return true;
+}
+
+constexpr bool
+test_from_pointer()
+{
+ double value = 12.3;
+ auto md = std::mdspan(&value);
+ assert_deduced_typedefs<double, std::extents<size_t>>(md);
+ VERIFY(md.rank() == 0);
+ VERIFY(md.rank_dynamic() == 0);
+ VERIFY(md[] == value);
+ return true;
+}
+
+constexpr bool
+test_from_pointer_and_shape()
+{
+ constexpr size_t n = 6;
+ std::array<double, n> data{1.1, 2.2, 3.3, 4.4, 5.5, 6.6};
+ std::array<int, 2> shape{2, 3};
+ std::span<const int, 2> shape_view(shape);
+
+ auto verify = [&data](auto md)
+ {
+ assert_deduced_typedefs<double, std::dextents<size_t, 2>>(md);
+ VERIFY(md.rank() == 2);
+ VERIFY(md.rank_dynamic() == 2);
+ VERIFY(md[0, 0] == data[0]);
+ VERIFY(md[0, 1] == data[1]);
+ VERIFY(md[1, 0] == data[3]);
+ };
+
+ verify(std::mdspan(data.data(), shape[0], shape[1]));
+ verify(std::mdspan(data.data(), shape));
+ verify(std::mdspan(data.data(), shape_view));
+
+ std::mdspan<double, std::dextents<size_t, 2>> md1 = {data.data(), shape};
+ verify(md1);
+
+ std::mdspan<double, std::dextents<size_t, 2>> md2 = {data.data(), shape_view};
+ verify(md2);
+
+ static_assert(std::is_constructible_v<
+ std::mdspan<float, std::extents<int, 3, 5>>, float*>);
+ static_assert(!std::is_constructible_v<
+ std::mdspan<float, std::extents<int, 3, 5>>, float*, int>);
+ static_assert(std::is_constructible_v<
+ std::mdspan<float, std::extents<int, 3, 5>>, float*, int, int>);
+ static_assert(std::is_constructible_v<
+ std::mdspan<float, std::extents<int, 3, 5>>, float*, std::span<int, 0>>);
+ static_assert(std::is_constructible_v<
+ std::mdspan<float, std::extents<int, 3, 5>>, float*, std::span<int, 2>>);
+ static_assert(!std::is_convertible_v<
+ float*, std::mdspan<float, std::extents<int, 3, 5>>>);
+
+ static_assert(std::is_constructible_v<
+ std::mdspan<float, std::dextents<int, 2>>, float*, std::span<int, 2>>);
+ static_assert(!std::is_constructible_v<
+ std::mdspan<float, std::dextents<int, 2>>, float*, std::span<int, 1>>);
+ static_assert(!std::is_constructible_v<
+ std::mdspan<float, std::dextents<int, 2>>, float*, std::span<int, 3>>);
+ static_assert(!std::is_constructible_v<
+ std::mdspan<float, std::dextents<int, 2>>, float*, std::span<int, dyn>>);
+ return true;
+}
+
+constexpr bool
+test_from_pointer_and_constant()
+{
+ std::array<double, 6> buffer{};
+ double * ptr = buffer.data();
+
+ auto verify = [ptr](auto actual, auto exts)
+ {
+ auto expected = std::mdspan<double, decltype(exts)>(ptr, exts);
+ static_assert(std::same_as<decltype(actual), decltype(expected)>);
+ VERIFY(actual.extents() == expected.extents());
+ };
+
+ auto i3 = std::integral_constant<int, 3>{};
+ auto i6 = std::integral_constant<int, 6>{};
+
+ verify(std::mdspan(ptr, 6), std::extents(6));
+ verify(std::mdspan(ptr, i6), std::extents(i6));
+ verify(std::mdspan(ptr, 2, i3), std::extents(2, i3));
+ verify(std::mdspan(ptr, std::true_type{}, i3), std::extents(1, i3));
+
+#if __glibcxx_constant_wrapper
+ auto c3 = std::constant_wrapper<3>{};
+ verify(std::mdspan(ptr, 2, c3), std::extents(2, i3));
+ verify(std::mdspan(ptr, 2, std::cw<3>), std::extents(2, i3));
+ verify(std::mdspan(ptr, std::cw<true>, std::cw<3>), std::extents(1, i3));
+#endif
+ return true;
+}
+
+constexpr bool
+test_from_extents()
+{
+ constexpr size_t n = 3*5*7;
+ std::array<double, n> storage{};
+ using Extents = std::extents<int, 3, 5, 7>;
+ auto exts = Extents{};
+ auto md = std::mdspan(storage.data(), exts);
+
+ assert_deduced_typedefs<double, Extents>(md);
+ VERIFY(md.data_handle() == storage.data());
+ VERIFY(md.extents() == exts);
+ return true;
+}
+
+constexpr bool
+test_from_mapping()
+{
+ constexpr size_t n = 3*5*7;
+ std::array<double, n> storage{};
+ using Extents = std::extents<int, 3, 5, 7>;
+
+ auto exts = Extents{};
+ auto m = std::layout_left::mapping(exts);
+ auto md = std::mdspan(storage.data(), m);
+
+ assert_deduced_typedefs<double, Extents, std::layout_left>(md);
+ VERIFY(md.data_handle() == storage.data());
+ VERIFY(md.mapping() == m);
+ return true;
+}
+
+constexpr bool
+test_from_accessor()
+{
+ constexpr size_t n = 3*5*7;
+ std::array<double, n> storage{};
+ using Extents = std::extents<int, 3, 5, 7>;
+
+ auto exts = Extents{};
+ auto m = std::layout_left::mapping(exts);
+ auto a = std::default_accessor<double>{};
+ auto md = std::mdspan(storage.data(), m, a);
+
+ assert_deduced_typedefs<double, Extents, std::layout_left>(md);
+ VERIFY(md.data_handle() == storage.data());
+ VERIFY(md.mapping() == m);
+ return true;
+}
+
+template<typename MDSpan, typename Pointer, typename... Ints>
+ concept has_pack_ctor = requires
+ {
+ { MDSpan(Pointer{}, Ints(0)...) } -> std::same_as<MDSpan>;
+ };
+
+template<typename CustomInt, bool ValidForPacks, bool ValidForArrays>
+ constexpr bool
+ test_from_int_like()
+ {
+ constexpr size_t n = 3*5*7;
+ std::array<double, n> storage{};
+
+ auto verify = [&](auto md)
+ {
+ VERIFY(md.data_handle() == storage.data());
+ VERIFY(md.extent(0) == 3);
+ VERIFY(md.extent(1) == 5);
+ VERIFY(md.extent(2) == 7);
+ };
+
+ static_assert(has_pack_ctor<std::mdspan<float, std::dextents<int, 3>>,
+ float*, CustomInt, int, CustomInt> == ValidForPacks);
+
+ static_assert(std::is_constructible_v<
+ std::mdspan<float, std::dextents<int, 3>>, float*,
+ std::span<CustomInt, 3>> == ValidForArrays);
+
+ static_assert(std::is_constructible_v<
+ std::mdspan<float, std::dextents<int, 3>>, float*,
+ std::array<CustomInt, 3>> == ValidForArrays);
+
+ if constexpr (ValidForPacks)
+ verify(std::mdspan(storage.data(), CustomInt(3), 5, CustomInt(7)));
+
+ if constexpr (ValidForArrays)
+ {
+ auto shape = std::array{CustomInt(3), CustomInt(5), CustomInt(7)};
+ auto shape_view = std::span<CustomInt, 3>{shape};
+ verify(std::mdspan(storage.data(), shape));
+ verify(std::mdspan(storage.data(), shape_view));
+ }
+ return true;
+ }
+
+template<typename T, bool NothrowConstructible = true,
+ bool NothrowAssignable = true>
+ class OpaqueAccessor
+ {
+ struct Handle
+ {
+ constexpr
+ Handle(T * other)
+ : ptr(other)
+ { }
+
+ constexpr
+ Handle(const Handle&) noexcept(NothrowConstructible) = default;
+
+ constexpr
+ Handle(Handle&&) noexcept(NothrowConstructible) = default;
+
+ constexpr Handle&
+ operator=(const Handle&) noexcept(NothrowAssignable) = default;
+
+ constexpr Handle&
+ operator=(Handle&&) noexcept(NothrowAssignable) = default;
+
+ T * ptr;
+ };
+
+ public:
+ using element_type = T;
+ using reference = T&;
+ using data_handle_type = Handle;
+ using offset_policy = OpaqueAccessor;
+
+ reference
+ access(data_handle_type p, size_t i) const
+ {
+ ++access_count;
+ return p.ptr[i];
+ }
+
+ typename offset_policy::data_handle_type
+ offset(data_handle_type p, size_t i) const
+ {
+ ++offset_count;
+ return typename offset_policy::data_handle_type{(void*)(p.ptr + i)};
+ }
+
+ mutable size_t access_count = 0;
+ mutable size_t offset_count = 0;
+ };
+
+void
+test_from_opaque_accessor()
+{
+ constexpr size_t n = 3*5*7;
+ std::array<double, n> storage{};
+ using Extents = std::extents<int, 3, 5, 7>;
+
+ auto exts = Extents{};
+ auto m = std::layout_left::mapping(exts);
+ auto a = OpaqueAccessor<double>{};
+ auto handle = OpaqueAccessor<double>::data_handle_type{storage.data()};
+ auto md = std::mdspan(handle, m, a);
+
+ using MDSpan = decltype(md);
+ static_assert(std::same_as<MDSpan::accessor_type, decltype(a)>);
+
+ VERIFY(md[0, 0, 0] == 0.0);
+ VERIFY(md.accessor().access_count == 1);
+
+ VERIFY(md[2, 4, 6] == 0.0);
+ VERIFY(md.accessor().access_count == 2);
+}
+
+template<typename T, typename Base>
+ class BaseClassAccessor
+ {
+ public:
+ using element_type = T;
+ using reference = Base&;
+ using data_handle_type = T*;
+ using offset_policy = BaseClassAccessor;
+
+ static_assert(std::common_reference_with<reference&&, element_type&>);
+
+ reference
+ access(data_handle_type p, size_t i) const
+ { return p[i]; }
+
+ typename offset_policy::data_handle_type
+ offset(data_handle_type p, size_t i) const
+ { return typename offset_policy::data_handle_type{p + i}; }
+ };
+
+struct Base
+{
+ double value = 1.0;
+};
+
+struct Derived : Base
+{
+ double value = 2.0;
+};
+
+void
+test_from_base_class_accessor()
+{
+ constexpr size_t n = 3*5*7;
+ std::array<Derived, n> storage{};
+ using Extents = std::extents<int, 3, 5, 7>;
+
+ auto exts = Extents{};
+ auto m = std::layout_left::mapping(exts);
+ auto a = BaseClassAccessor<Derived, Base>{};
+ auto md = std::mdspan(storage.data(), m, a);
+
+ using MDSpan = decltype(md);
+ static_assert(std::same_as<MDSpan::accessor_type, decltype(a)>);
+ static_assert(std::same_as<decltype(md[0, 0, 0]), Base&>);
+ VERIFY(md[0, 0, 0].value == 1.0);
+ VERIFY(md[2, 4, 6].value == 1.0);
+}
+
+constexpr bool
+test_from_mapping_like()
+{
+ double data = 1.1;
+ auto m = LayoutLike::mapping<std::extents<int, 1, 2, 3>>{};
+ auto md = std::mdspan(&data, m);
+ VERIFY(md[0, 0, 0] == data);
+ VERIFY(md[0, 1, 2] == data);
+ return true;
+}
+
+template<typename MDSpan>
+ constexpr void
+ test_empty(MDSpan md)
+ {
+ VERIFY(md.empty() == (md.size() == 0));
+ }
+
+constexpr bool
+test_empty_all()
+{
+ test_empty(std::mdspan<double, std::extents<int, dyn>>{});
+ return true;
+}
+
+template<typename MDSpan, typename... Args>
+concept indexable = requires (MDSpan md, Args... args)
+{
+ { md[args...] } -> std::same_as<typename MDSpan::reference>;
+};
+
+template<typename Int, bool ValidForPacks, bool ValidForArrays>
+ constexpr bool
+ test_access()
+ {
+ using Extents = std::extents<int, 3, 5, 7>;
+ auto exts = Extents{};
+
+ auto mapping = std::layout_left::mapping(exts);
+ constexpr size_t n = mapping.required_span_size();
+ std::array<double, n> storage{};
+
+ auto md = std::mdspan(storage.data(), mapping);
+ using MDSpan = decltype(md);
+
+ for(int i = 0; i < exts.extent(0); ++i)
+ for(int j = 0; j < exts.extent(1); ++j)
+ for(int k = 0; k < exts.extent(2); ++k)
+ {
+ storage[mapping(i, j, k)] = 1.0;
+ if constexpr (ValidForPacks)
+ VERIFY(md[Int(i), Int(j), Int(k)] == 1.0);
+
+ if constexpr (ValidForArrays)
+ {
+ std::array<Int, 3> ijk{Int(i), Int(j), Int(k)};
+ VERIFY(md[ijk] == 1.0);
+ VERIFY(md[std::span(ijk)] == 1.0);
+ }
+ storage[mapping(i, j, k)] = 0.0;
+ }
+
+ if constexpr (!ValidForPacks)
+ static_assert(!indexable<MDSpan, Int, int, Int>);
+
+ if constexpr (!ValidForArrays)
+ {
+ static_assert(!indexable<MDSpan, std::array<Int, 3>>);
+ static_assert(!indexable<MDSpan, std::span<Int, 3>>);
+ }
+ return true;
+ }
+
+constexpr bool
+test_swap()
+{
+ using Extents = std::dextents<int, 2>;
+ auto e1 = Extents{3, 5};
+ auto e2 = Extents{7, 11};
+
+ std::array<double, 3*5> s1{};
+ std::array<double, 7*11> s2{};
+
+ auto md1 = std::mdspan(s1.data(), e1);
+ auto md2 = std::mdspan(s2.data(), e2);
+
+ std::swap(md1, md2);
+
+ VERIFY(md1.data_handle() == s2.data());
+ VERIFY(md2.data_handle() == s1.data());
+
+ VERIFY(md1.size() == s2.size());
+ VERIFY(md2.size() == s1.size());
+ return true;
+}
+
+namespace adl
+{
+ template<typename T>
+ struct SwappableAccessor
+ {
+ using element_type = T;
+ using reference = T&;
+ using data_handle_type = T*;
+ using offset_policy = SwappableAccessor;
+
+ reference
+ access(data_handle_type p, size_t i) const
+ { return p[i]; }
+
+ typename offset_policy::data_handle_type
+ offset(data_handle_type p, size_t i) const
+ { return p + i; }
+
+ friend void
+ swap(SwappableAccessor&, SwappableAccessor&)
+ { ++swap_count; }
+
+ static inline size_t swap_count = 0;
+ };
+}
+
+void
+test_swap_adl()
+{
+ using Extents = std::extents<int, dyn>;
+ using Layout = std::layout_left;
+ using Accessor = adl::SwappableAccessor<double>;
+ Accessor::swap_count = 0;
+
+ std::mdspan<double, Extents, Layout, Accessor> m1, m2;
+ swap(m1, m2);
+ VERIFY(Accessor::swap_count == 1);
+}
+
+template<bool Constructible, bool Assignable>
+constexpr void
+test_nothrow_movable()
+{
+ using Layout = std::layout_left;
+ using Extents = std::dextents<int, 3>;
+ using Accessor = OpaqueAccessor<int, Constructible, Assignable>;
+ using Handle = Accessor::data_handle_type;
+ static_assert(std::is_nothrow_move_assignable_v<Accessor>);
+ static_assert(std::is_nothrow_move_constructible_v<Accessor>);
+ static_assert(std::is_nothrow_move_assignable_v<Handle> == Assignable);
+ static_assert(std::is_nothrow_move_constructible_v<Handle> == Constructible);
+
+ using MDSpan = std::mdspan<int, Extents, Layout, Accessor>;
+ static_assert(std::is_nothrow_move_assignable_v<MDSpan> == Assignable);
+ static_assert(std::is_nothrow_move_constructible_v<MDSpan> == Constructible);
+}
+
+constexpr void
+test_nothrow_movable_all()
+{
+ using MDSpan = std::mdspan<double, std::dextents<int, 3>>;
+ static_assert(std::is_nothrow_move_assignable_v<MDSpan>);
+ static_assert(std::is_nothrow_move_constructible_v<MDSpan>);
+
+ test_nothrow_movable<true, true>();
+ test_nothrow_movable<true, false>();
+ test_nothrow_movable<false, true>();
+ test_nothrow_movable<false, false>();
+}
+
+template<typename Layout, bool Expected>
+ constexpr void
+ test_nothrow_is_methods()
+ {
+ using Extents = std::extents<int, dyn>;
+ using MDSpan = std::mdspan<double, Extents, Layout>;
+ static_assert(noexcept(MDSpan::is_always_unique()) == Expected);
+ static_assert(noexcept(MDSpan::is_always_exhaustive()) == Expected);
+ static_assert(noexcept(MDSpan::is_always_strided()) == Expected);
+
+ static_assert(noexcept(std::declval<MDSpan>().is_unique()) == Expected);
+ static_assert(noexcept(std::declval<MDSpan>().is_exhaustive()) == Expected);
+ static_assert(noexcept(std::declval<MDSpan>().is_strided()) == Expected);
+ }
+
+int
+main()
+{
+ test_typedefs_all();
+
+ test_rank_all();
+ test_extent_all();
+ static_assert(test_extent_all());
+
+ test_class_properties_all();
+ static_assert(test_class_properties_all());
+
+ test_empty_all();
+ static_assert(test_empty_all());
+
+ test_default_ctor();
+ static_assert(test_default_ctor());
+
+ test_nothrow_default_ctor<std::default_accessor, true>();
+ test_nothrow_default_ctor<ThrowingDefaultAccessor, false>();
+
+ test_from_other();
+ static_assert(test_from_other());
+
+ test_from_carray();
+ static_assert(test_from_carray());
+
+ test_from_pointer_and_shape();
+ static_assert(test_from_pointer_and_shape());
+
+ test_from_pointer_and_constant();
+ static_assert(test_from_pointer_and_constant());
+
+ test_from_extents();
+ static_assert(test_from_extents());
+
+ test_from_mapping();
+ static_assert(test_from_mapping());
+
+ test_from_accessor();
+ static_assert(test_from_accessor());
+
+ test_from_int_like<int, true, true>();
+ static_assert(test_from_int_like<int, true, true>());
+ test_from_int_like<IntLike, true, true>();
+ test_from_int_like<ThrowingInt, false, false>();
+ test_from_int_like<MutatingInt, true, false>();
+ test_from_int_like<RValueInt, true, false>();
+
+ test_from_opaque_accessor();
+ test_from_base_class_accessor();
+ test_from_mapping_like();
+ static_assert(test_from_mapping_like());
+
+ test_access<int, true, true>();
+ static_assert(test_access<int, true, true>());
+ test_access<IntLike, true, true>();
+ test_access<ThrowingInt, false, false>();
+ test_access<MutatingInt, true, false>();
+ test_access<RValueInt, true, false>();
+
+ test_swap();
+ static_assert(test_swap());
+ test_swap_adl();
+
+ test_nothrow_movable_all();
+ test_nothrow_is_methods<std::layout_right, true>();
+ test_nothrow_is_methods<ThrowingLayout, false>();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/out_of_bounds_neg.cc b/libstdc++-v3/testsuite/23_containers/mdspan/out_of_bounds_neg.cc
new file mode 100644
index 0000000..dceae56
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/out_of_bounds_neg.cc
@@ -0,0 +1,24 @@
+// { dg-do compile { target c++23 } }
+#include<mdspan>
+
+#include "layout_like.h"
+
+template<typename Layout>
+constexpr bool
+test_invalid_multi_index()
+{
+
+ double data = 1.1;
+ auto m = typename Layout::mapping<std::extents<int, 1, 2, 3>>{};
+ auto md = std::mdspan(&data, m);
+
+ [[maybe_unused]] double x = md[0, 2, 2]; // { dg-error "expansion of" }
+ return true;
+};
+static_assert(test_invalid_multi_index<LayoutLike>()); // { dg-error "expansion of" }
+static_assert(test_invalid_multi_index<std::layout_left>()); // { dg-error "expansion of" }
+static_assert(test_invalid_multi_index<std::layout_right>()); // { dg-error "expansion of" }
+static_assert(test_invalid_multi_index<std::layout_stride>()); // { dg-error "expansion of" }
+
+// { dg-prune-output "non-constant condition" }
+// { dg-prune-output "__glibcxx_assert" }
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/generic.cc b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/generic.cc
new file mode 100644
index 0000000..682ff62
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/generic.cc
@@ -0,0 +1,71 @@
+// { dg-do compile { target c++26 } }
+#include <mdspan>
+
+namespace adl
+{
+ struct NoFriend
+ {
+ template<typename Extents>
+ class mapping
+ {
+ public:
+ using extents_type = Extents;
+ using index_type = typename extents_type::index_type;
+ };
+ };
+
+ struct NoFull
+ {
+ template<typename Extents>
+ class mapping
+ {
+ public:
+ using extents_type = Extents;
+ using index_type = typename extents_type::index_type;
+
+ private:
+ friend constexpr auto
+ submdspan_mapping(mapping, int)
+ { return std::submdspan_mapping_result{mapping{}, 0}; }
+ };
+ };
+
+ struct WrongReturnValue
+ {
+ template<typename Extents>
+ class mapping
+ {
+ public:
+ using extents_type = Extents;
+ using index_type = typename extents_type::index_type;
+
+ private:
+ friend constexpr int
+ submdspan_mapping(mapping, std::full_extent_t)
+ { return 42; }
+ };
+ };
+}
+
+template<typename MdSpan, typename... Slices>
+ concept submdspan_exists = requires (MdSpan md, Slices... slices)
+ {
+ std::submdspan(md, slices...);
+ };
+
+template<typename Layout, bool Expected>
+constexpr bool
+test_invalid_mapping()
+{
+ using Extents = std::extents<int, 3>;
+ using MdSpan = std::mdspan<double, Extents, Layout>;
+ static_assert(submdspan_exists<MdSpan, int> == Expected);
+ static_assert(submdspan_exists<MdSpan, std::full_extent_t> == Expected);
+ static_assert(!submdspan_exists<MdSpan>);
+ static_assert(!submdspan_exists<MdSpan, int, int>);
+ return true;
+}
+static_assert(test_invalid_mapping<std::layout_left, true>());
+static_assert(test_invalid_mapping<adl::NoFriend, false>());
+static_assert(test_invalid_mapping<adl::NoFull, false>());
+static_assert(test_invalid_mapping<adl::WrongReturnValue, false>());
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/left.cc b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/left.cc
new file mode 100644
index 0000000..d6a85d0
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/left.cc
@@ -0,0 +1,9 @@
+// { dg-do run { target c++26 } }
+#include "testcases.h"
+
+int
+main()
+{
+ test_all<std::layout_left>();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/left_padded.cc b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/left_padded.cc
new file mode 100644
index 0000000..711ce35
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/left_padded.cc
@@ -0,0 +1,12 @@
+// { dg-do run { target c++26 } }
+// { dg-timeout-factor 2 }
+#include "testcases.h"
+
+int
+main()
+{
+ test_all<std::layout_left_padded<1>>();
+ test_all<std::layout_left_padded<8>>();
+ test_all<std::layout_left_padded<dyn>>();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/right.cc b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/right.cc
new file mode 100644
index 0000000..2557072
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/right.cc
@@ -0,0 +1,9 @@
+// { dg-do run { target c++26 } }
+#include "testcases.h"
+
+int
+main()
+{
+ test_all<std::layout_right>();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/right_padded.cc b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/right_padded.cc
new file mode 100644
index 0000000..24ed6cb
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/right_padded.cc
@@ -0,0 +1,12 @@
+// { dg-do run { target c++26 } }
+// { dg-timeout-factor 2 }
+#include "testcases.h"
+
+int
+main()
+{
+ test_all<std::layout_right_padded<1>>();
+ test_all<std::layout_right_padded<8>>();
+ test_all<std::layout_right_padded<dyn>>();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/stride.cc b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/stride.cc
new file mode 100644
index 0000000..19451d7
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/stride.cc
@@ -0,0 +1,9 @@
+// { dg-do run { target c++26 } }
+#include "testcases.h"
+
+int
+main()
+{
+ test_all<std::layout_stride>();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/testcases.h b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/testcases.h
new file mode 100644
index 0000000..d7b751d
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/testcases.h
@@ -0,0 +1,360 @@
+#include <mdspan>
+
+#include <vector>
+#include <numeric>
+#include "../../layout_traits.h"
+#include <testsuite_hooks.h>
+
+constexpr size_t dyn = std::dynamic_extent;
+constexpr auto all = std::full_extent;
+
+template<typename T>
+ constexpr bool is_strided_slice = false;
+
+template<typename O, typename E, typename S>
+ constexpr bool is_strided_slice<std::strided_slice<O, E, S>> = true;
+
+template<typename MDSpan>
+ constexpr void
+ fill(const MDSpan& md)
+ {
+ using IndexType = typename MDSpan::index_type;
+ auto exts = md.extents();
+ if constexpr (exts.rank() == 3)
+ for(IndexType i = 0; i < exts.extent(0); ++i)
+ for(IndexType j = 0; j < exts.extent(1); ++j)
+ for(IndexType k = 0; k < exts.extent(2); ++k)
+ md[i, j, k] = 100 * i + 10 * j + k;
+ }
+
+template<typename Int, size_t Rank>
+ class multi_index_generator
+ {
+ struct sentinel
+ { };
+
+ class iterator
+ {
+ public:
+ constexpr
+ iterator(const std::array<Int, Rank>& shape)
+ : M_shape(shape)
+ { }
+
+ constexpr iterator&
+ operator++()
+ {
+ if constexpr (Rank > 0)
+ {
+ ++M_indices[Rank-1];
+ for(size_t i = Rank; i > 1; --i)
+ if (M_indices[i-1] == M_shape[i-1])
+ {
+ M_indices[i-1] = 0;
+ ++M_indices[i-2];
+ }
+ }
+ return *this;
+ }
+
+ constexpr auto
+ operator*()
+ { return M_indices; }
+
+ private:
+ friend constexpr bool
+ operator==(const iterator& it, sentinel)
+ {
+ if constexpr (Rank > 0)
+ return it.M_indices[0] == it.M_shape[0];
+ else
+ return true;
+ }
+
+ std::array<Int, Rank> M_indices{};
+ std::array<Int, Rank> M_shape;
+ };
+
+ public:
+ constexpr
+ multi_index_generator(std::array<Int, Rank> shape)
+ : M_shape(shape)
+ { }
+
+ constexpr iterator
+ begin() const
+ { return iterator(M_shape); }
+
+ constexpr sentinel
+ end() const
+ { return sentinel{}; }
+
+ private:
+ std::array<Int, Rank> M_shape;
+ };
+
+constexpr bool
+test_multi_index()
+{
+ auto shape = std::array{3, 5, 7, 1};
+ auto gen = multi_index_generator(shape);
+ auto it = gen.begin();
+ auto end = gen.end();
+ for (int i = 0; i < shape[0]; ++i)
+ for (int j = 0; j < shape[1]; ++j)
+ for (int k = 0; k < shape[2]; ++k)
+ for (int l = 0; l < shape[3]; ++l)
+ {
+ VERIFY(it != end);
+ VERIFY(*it == std::array{i, j, k, l});
+ ++it;
+ }
+ return true;
+}
+static_assert(test_multi_index());
+
+struct
+collapse
+{ };
+
+template<typename... Slices>
+ consteval auto
+ inv_collapsed_index_map()
+ {
+ constexpr size_t rank = sizeof...(Slices);
+ auto is_collapsing = std::array{std::same_as<Slices, collapse>...};
+ constexpr auto collapsed_rank = ((!std::same_as<Slices, collapse>) + ... + 0);
+
+ std::array<size_t, collapsed_rank> ret;
+ if constexpr (collapsed_rank > 0)
+ for(size_t k = 0, i = 0; i < rank; ++i)
+ if (!is_collapsing[i])
+ ret[k++] = i;
+ return ret;
+ }
+
+static_assert(inv_collapsed_index_map<collapse, collapse, collapse>()
+ == std::array<size_t, 0>{});
+
+static_assert(inv_collapsed_index_map<collapse, decltype(all), collapse>()
+ == std::array<size_t, 1>{1});
+
+template<typename IndexType, typename Slice>
+ constexpr std::vector<IndexType>
+ make_selection(IndexType extent, const Slice& slice)
+ {
+ if constexpr (std::convertible_to<Slice, IndexType>)
+ return {static_cast<IndexType>(slice)};
+ else if constexpr (std::same_as<Slice, std::full_extent_t>)
+ {
+ auto ret = std::vector<IndexType>(static_cast<size_t>(extent));
+ std::ranges::iota(ret, 0);
+ return ret;
+ }
+ else if constexpr (is_strided_slice<Slice>)
+ {
+ auto ret = std::vector<IndexType>{};
+ size_t n = static_cast<size_t>(slice.extent);
+ for(size_t i = 0; i < n; i += slice.stride)
+ ret.push_back(slice.offset + i);
+ return ret;
+ }
+ else
+ {
+ auto [begin, end] = slice;
+ auto ret = std::vector<IndexType>(static_cast<size_t>(end - begin));
+ std::ranges::iota(ret, begin);
+ return ret;
+ }
+ }
+
+template<typename Layout, size_t... I, typename... Slices>
+ constexpr bool
+ check_selection(std::index_sequence<I...>, auto md, Slices... slices)
+ {
+ auto exts = md.extents();
+ auto outer_shape = std::array{exts.extent(0), exts.extent(1), exts.extent(2)};
+
+ constexpr auto full_index = inv_collapsed_index_map<Slices...>();
+ auto make_slice = [](size_t i, auto slice)
+ {
+ if constexpr (std::same_as<decltype(slice), collapse>)
+ return i;
+ else
+ return slice;
+ };
+
+ auto loop_body = [&]<size_t... J>(std::index_sequence<J...>, auto ijk,
+ auto... slices)
+ {
+ auto submd = submdspan(md, slices...[I]...);
+ auto selection = std::tuple{make_selection(exts.extent(I), slices...[I])...};
+ auto inner_shape = std::array<size_t, full_index.size()>{
+ std::get<full_index[J]>(selection).size()...
+ };
+
+ for (auto ij : multi_index_generator(inner_shape))
+ {
+ ((ijk[full_index[J]] = get<full_index[J]>(selection)[ij[J]]),...);
+ VERIFY(submd[ij] == md[ijk]);
+ }
+ };
+
+ for (auto ijk : multi_index_generator(outer_shape))
+ loop_body(std::make_index_sequence<full_index.size()>(), ijk,
+ make_slice(ijk[I], slices...[I])...);
+ return true;
+ }
+
+template<typename Layout, typename...MD, typename... Slices>
+ constexpr bool
+ check_selection(std::mdspan<MD...> md, Slices... slices)
+ {
+ auto indices = std::make_index_sequence<sizeof...(slices)>();
+ return check_selection<Layout>(indices, md, slices...);
+ }
+
+template<typename Layout, typename IndexType, size_t... Extents,
+ typename... Slices>
+ constexpr bool
+ check_selection(std::extents<IndexType, Extents...>exts, Slices... slices)
+ {
+ auto run = [&](auto m)
+ {
+ auto storage = std::vector<double>(m.required_span_size());
+ auto md = std::mdspan(storage.data(), m);
+ fill(md);
+ return check_selection<Layout>(md, slices...);
+ };
+
+ if constexpr (std::same_as<Layout, std::layout_stride>)
+ {
+ auto m = typename Layout::mapping(exts, std::array{15, 2, 50});
+ return run(m);
+ }
+ else
+ {
+ auto m = typename Layout::mapping(exts);
+ return run(m);
+ }
+ }
+
+template<typename Layout>
+ constexpr bool
+ test_scalar_selection(auto exts)
+ {
+ check_selection<Layout>(exts, collapse{}, collapse{}, collapse{});
+ return true;
+ }
+
+template<typename Layout>
+ constexpr bool
+ test_full_lines(auto exts)
+ {
+ check_selection<Layout>(exts, all, collapse{}, collapse{});
+ check_selection<Layout>(exts, collapse{}, all, collapse{});
+ check_selection<Layout>(exts, collapse{}, collapse{}, all);
+ return true;
+ }
+
+template<typename Layout>
+ constexpr bool
+ test_full_blocks(auto exts)
+ {
+ check_selection<Layout>(exts, all, all, collapse{});
+ check_selection<Layout>(exts, all, collapse{}, all);
+ check_selection<Layout>(exts, collapse{}, all, all);
+ return true;
+ }
+
+template<typename Layout>
+ constexpr bool
+ test_cubes(auto exts)
+ {
+ auto s0 = std::pair{0, 2};
+ auto s1 = std::pair{1, 4};
+ auto s2 = std::pair{3, 7};
+
+ check_selection<Layout>(exts, all, all, all);
+ check_selection<Layout>(exts, all, all, s2);
+ check_selection<Layout>(exts, s0, all, all);
+ check_selection<Layout>(exts, s0, all, s2);
+ check_selection<Layout>(exts, s0, s1, s2);
+ return true;
+ }
+
+template<typename Layout>
+ constexpr bool
+ test_strided_line_selection(auto exts)
+ {
+ auto check = [&](auto s)
+ {
+ check_selection<Layout>(exts, collapse{}, s, collapse{});
+ };
+
+ check(std::strided_slice(0, 2, 2));
+ check(std::strided_slice(0, 3, 2));
+ check(std::strided_slice(1, 3, 2));
+ check(std::strided_slice(1, std::cw<3>, std::cw<2>));
+ return true;
+ }
+
+template<typename Layout>
+ constexpr bool
+ test_strided_box_selection(auto exts)
+ {
+ auto s0 = std::strided_slice(0, 3, 2);
+ auto s1 = std::strided_slice(1, 4, 2);
+ auto s2 = std::strided_slice(0, 7, 3);
+
+ check_selection<Layout>(exts, s0, s1, s2);
+ return true;
+ }
+
+template<typename Layout>
+ constexpr bool
+ test_all_cheap()
+ {
+ constexpr auto dyn_exts = std::extents(3, 5, 7);
+ constexpr auto sta_exts = std::extents<int, 3, 5, 7>{};
+
+ test_scalar_selection<Layout>(dyn_exts);
+ test_scalar_selection<Layout>(sta_exts);
+ static_assert(test_scalar_selection<Layout>(dyn_exts));
+ static_assert(test_scalar_selection<Layout>(sta_exts));
+
+ test_full_lines<Layout>(dyn_exts);
+ test_full_lines<Layout>(sta_exts);
+ static_assert(test_full_lines<Layout>(dyn_exts));
+ static_assert(test_full_lines<Layout>(sta_exts));
+
+ test_strided_box_selection<Layout>(dyn_exts);
+ test_strided_box_selection<Layout>(sta_exts);
+ static_assert(test_strided_box_selection<Layout>(dyn_exts));
+ static_assert(test_strided_box_selection<Layout>(sta_exts));
+ return true;
+ }
+
+template<typename Layout>
+ constexpr bool
+ test_all_expensive()
+ {
+ auto run = [](auto exts)
+ {
+ test_full_blocks<Layout>(exts);
+ test_cubes<Layout>(exts);
+ };
+
+ run(std::extents(3, 5, 7));
+ run(std::extents<int, 3, 5, 7>{});
+ return true;
+ }
+
+template<typename Layout>
+ constexpr bool
+ test_all()
+ {
+ test_all_cheap<Layout>();
+ test_all_expensive<Layout>();
+ return true;
+ }
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/strided_slice.cc b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/strided_slice.cc
new file mode 100644
index 0000000..6fa5aaa
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/strided_slice.cc
@@ -0,0 +1,49 @@
+// { dg-do run { target c++26 } }
+#include <mdspan>
+
+#include <cstdint>
+#include <testsuite_hooks.h>
+
+constexpr void
+check_strided_slice(auto s, auto offset, auto extent, auto stride)
+{
+ using slice_type = std::strided_slice<decltype(offset), decltype(extent),
+ decltype(stride)>;
+ static_assert(std::same_as<decltype(s), slice_type>);
+ VERIFY(s.offset == offset);
+ VERIFY(s.extent == extent);
+ VERIFY(s.stride == stride);
+}
+
+constexpr void
+test_initializers(auto offset, auto extent, auto stride)
+{
+ auto check = [&](auto s)
+ {
+ check_strided_slice(s, offset, extent, stride);
+ };
+
+ check(std::strided_slice{.offset=offset, .extent=extent, .stride=stride});
+ check(std::strided_slice{offset, extent, stride});
+ check(std::strided_slice(offset, extent, stride));
+}
+
+constexpr bool
+test_all()
+{
+ test_initializers(0, 1, 2);
+ test_initializers(std::integral_constant<short, 0>{}, size_t{1}, std::cw<2>);
+ test_initializers(-1, 2, 2);
+#ifdef __SIZEOF_INT128__
+ test_initializers((__int128)1, (unsigned __int128)-2, std::cw<(__int128)3>);
+#endif
+ return true;
+}
+
+int
+main()
+{
+ test_all();
+ static_assert(test_all());
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/strided_slice_neg.cc b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/strided_slice_neg.cc
new file mode 100644
index 0000000..0f1d791
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/strided_slice_neg.cc
@@ -0,0 +1,19 @@
+// { dg-do compile { target c++26 } }
+#include <mdspan>
+
+#include <cstdint>
+
+template<typename OffsetType, typename ExtentType, typename StrideType>
+ constexpr bool
+ test_invalid()
+ {
+ auto s1 = std::strided_slice(OffsetType{}, ExtentType{}, StrideType{}); // { dg-error "required from" }
+ return true;
+ }
+
+static_assert(test_invalid<double, int, int>()); // { dg-error "required from" }
+static_assert(test_invalid<int, double, int>()); // { dg-error "required from" }
+static_assert(test_invalid<int, int, double>()); // { dg-error "required from" }
+static_assert(test_invalid<double, double, double>()); // { dg-error "required from" }
+
+// { dg-prune-output "static assertion failed" }
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_canonicalize_slices.cc b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_canonicalize_slices.cc
new file mode 100644
index 0000000..077bafc
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_canonicalize_slices.cc
@@ -0,0 +1,220 @@
+// { dg-do run { target c++26 } }
+#include <mdspan>
+
+#include <testsuite_hooks.h>
+#include <cstddef>
+#include <cstdint>
+
+constexpr size_t dyn = std::dynamic_extent;
+
+template<typename Extents, typename CInt>
+ constexpr bool
+ check_collapsing(Extents exts, CInt ci_raw)
+ {
+ using IndexType = typename Extents::index_type;
+ auto ci_expected = std::cw<IndexType{ci_raw.value}>;
+ auto [ci] = std::submdspan_canonicalize_slices(exts, ci_raw);
+ static_assert(std::same_as<decltype(ci), decltype(ci_expected)>);
+ VERIFY(std::cmp_equal(ci.value, ci_raw.value));
+
+ auto [i] = std::submdspan_canonicalize_slices(exts, ci_raw.value);
+ static_assert(std::same_as<decltype(i), IndexType>);
+ VERIFY(std::cmp_equal(i, ci_raw.value));
+ return true;
+ }
+
+template<typename Extents>
+ constexpr bool
+ test_scalar(Extents exts)
+ {
+ using IndexType = typename Extents::index_type;
+
+ check_collapsing(exts, std::cw<uint8_t{0}>);
+ check_collapsing(exts, std::cw<IndexType{0}>);
+
+ check_collapsing(exts, std::cw<uint8_t{4}>);
+ check_collapsing(exts, std::cw<IndexType{4}>);
+ return true;
+ }
+
+constexpr bool
+test_scalar()
+{
+ test_scalar(std::extents<int, dyn>{5});
+ test_scalar(std::extents<int, 5>{});
+ test_scalar(std::extents<unsigned int, dyn>{5});
+ test_scalar(std::extents<unsigned int, 5>{});
+ return true;
+}
+
+constexpr void
+assert_same(auto lhs, auto rhs)
+{
+ static_assert(std::same_as<decltype(lhs), decltype(rhs)>);
+ VERIFY(lhs == rhs);
+}
+
+template<template<typename, typename> typename Pair>
+ constexpr bool
+ test_pair(auto exts, auto cbegin, auto cend, auto coffset, auto cextent)
+ {
+ using IndexType = typename decltype(exts)::index_type;
+ auto c1 = std::cw<IndexType{1}>;
+
+ auto raw_cc = Pair{cbegin, cend};
+ auto [cc] = std::submdspan_canonicalize_slices(exts, raw_cc);
+ assert_same(cc.offset, coffset);
+ assert_same(cc.extent, cextent);
+ assert_same(cc.stride, c1);
+
+ auto raw_cd = Pair{cbegin, cend.value};
+ auto [cd] = std::submdspan_canonicalize_slices(exts, raw_cd);
+ assert_same(cd.offset, coffset);
+ assert_same(cd.extent, cextent.value);
+ assert_same(cd.stride, c1);
+
+ auto raw_dc = Pair{cbegin.value, cend};
+ auto [dc] = std::submdspan_canonicalize_slices(exts, raw_dc);
+ assert_same(dc.offset, coffset.value);
+ assert_same(dc.extent, cextent.value);
+ assert_same(dc.stride, c1);
+
+ auto raw_dd = Pair{cbegin.value, cend.value};
+ auto [dd] = std::submdspan_canonicalize_slices(exts, raw_dd);
+ assert_same(dd.offset, coffset.value);
+ assert_same(dd.extent, cextent.value);
+ assert_same(dd.stride, c1);
+ return true;
+ }
+
+template<template<typename, typename> typename Pair>
+ constexpr bool
+ test_pair()
+ {
+ test_pair<Pair>(std::extents<int, dyn>{5}, std::cw<uint8_t{2}>,
+ std::cw<uint8_t{5}>, std::cw<2>, std::cw<3>);
+ test_pair<Pair>(std::extents<int, 5>{}, std::cw<uint8_t{2}>,
+ std::cw<uint8_t{5}>, std::cw<2>, std::cw<3>);
+ test_pair<Pair>(std::extents<int, 0>{}, std::cw<uint8_t{0}>,
+ std::cw<uint8_t{0}>, std::cw<0>, std::cw<0>);
+ test_pair<Pair>(std::extents<int, dyn>{0}, std::cw<uint8_t{0}>,
+ std::cw<uint8_t{0}>, std::cw<0>, std::cw<0>);
+ return true;
+ }
+
+template<typename Lower, typename Upper>
+struct Range
+{
+ Lower lower;
+ Upper upper;
+};
+
+constexpr bool
+test_pair_all()
+{
+ test_pair<std::pair>();
+ test_pair<std::tuple>();
+ test_pair<Range>();
+ return true;
+}
+
+constexpr bool
+test_strided_slice(auto exts, auto co, auto ce, auto cs)
+{
+ using IndexType = decltype(exts)::index_type;
+
+ auto coffset = std::cw<IndexType{co.value}>;
+ auto cextent = std::cw<IndexType{ce.value}>;
+ auto cstride = std::cw<IndexType{cs.value}>;
+
+ auto raw_ccc = std::strided_slice{co, ce, cs};
+ auto [ccc] = std::submdspan_canonicalize_slices(exts, raw_ccc);
+ assert_same(ccc.offset, coffset);
+ assert_same(ccc.extent, cextent);
+ assert_same(ccc.stride, cstride);
+
+ auto raw_dcc = std::strided_slice{co.value, ce, cs};
+ auto [dcc] = std::submdspan_canonicalize_slices(exts, raw_dcc);
+ assert_same(dcc.offset, coffset.value);
+ assert_same(dcc.extent, cextent);
+ assert_same(dcc.stride, cstride);
+
+ auto raw_cdc = std::strided_slice{co, ce.value, cs};
+ auto [cdc] = std::submdspan_canonicalize_slices(exts, raw_cdc);
+ assert_same(cdc.offset, coffset);
+ assert_same(cdc.extent, cextent.value);
+ assert_same(cdc.stride, cstride);
+
+ auto raw_ccd = std::strided_slice{co, ce, cs.value};
+ auto [ccd] = std::submdspan_canonicalize_slices(exts, raw_ccd);
+ assert_same(ccd.offset, coffset);
+ assert_same(ccd.extent, cextent);
+ assert_same(ccd.stride, cstride.value);
+ return true;
+}
+
+constexpr bool
+test_strided_slice()
+{
+ auto run = [](auto exts)
+ {
+ auto cs = std::cw<uint8_t{9}>;
+ test_strided_slice(exts, std::cw<uint8_t{2}>, std::cw<uint8_t{3}>, cs);
+ test_strided_slice(exts, std::cw<uint8_t{0}>, std::cw<uint8_t{5}>, cs);
+ };
+
+ run(std::extents<int, 5>{});
+ run(std::extents<int, dyn>{5});
+ return true;
+}
+
+constexpr bool
+test_strided_slice_zero_extent(auto exts, auto cs)
+{
+ using IndexType = typename decltype(exts)::index_type;
+ auto c0 = std::cw<uint8_t{0}>;
+ auto raw_ccc = std::strided_slice{c0, c0, cs};
+ auto [ccc] = std::submdspan_canonicalize_slices(exts, raw_ccc);
+ assert_same(ccc.stride, std::cw<IndexType{1}>);
+
+ auto raw_ccd = std::strided_slice{c0, c0, cs.value};
+ auto [ccd] = std::submdspan_canonicalize_slices(exts, raw_ccd);
+ assert_same(ccd.stride, std::cw<IndexType{1}>);
+ return true;
+}
+
+constexpr bool
+test_strided_slice_zero_extent(auto exts)
+{
+ test_strided_slice_zero_extent(exts, std::cw<uint8_t{0}>);
+ test_strided_slice_zero_extent(exts, std::cw<uint8_t{9}>);
+ return true;
+}
+
+constexpr bool
+test_strided_slice_zero_extent()
+{
+ test_strided_slice_zero_extent(std::extents<int, 0>{});
+ test_strided_slice_zero_extent(std::extents<int, dyn>{0});
+ test_strided_slice_zero_extent(std::extents<int, 5>{});
+ test_strided_slice_zero_extent(std::extents<int, dyn>{5});
+ return true;
+}
+
+constexpr bool
+test_all()
+{
+ test_scalar();
+ test_pair_all();
+ test_strided_slice();
+ test_strided_slice_zero_extent();
+ return true;
+}
+
+int
+main()
+{
+ test_all();
+ static_assert(test_all());
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_canonicalize_slices_neg.cc b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_canonicalize_slices_neg.cc
new file mode 100644
index 0000000..94bca18
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_canonicalize_slices_neg.cc
@@ -0,0 +1,208 @@
+// { dg-do compile { target c++26 } }
+#include <mdspan>
+
+#include <cstdint>
+
+constexpr size_t dyn = std::dynamic_extent;
+
+constexpr auto dyn_empty = std::extents<int32_t, dyn>{0};
+constexpr auto sta_empty = std::extents<uint32_t, 0>{};
+
+constexpr auto dyn_uexts = std::extents<uint8_t, dyn>{5};
+constexpr auto sta_uexts = std::extents<uint16_t, 5>{5};
+constexpr auto dyn_sexts = std::extents<int8_t, dyn>{5};
+constexpr auto sta_sexts = std::extents<int16_t, 5>{5};
+
+constexpr bool
+test_rank_mismatch()
+{
+ auto exts = std::extents(1);
+ std::submdspan_canonicalize_slices(exts, 0, 0); // { dg-error "no matching" }
+ return true;
+}
+
+template<typename Int, typename Extents>
+constexpr bool
+test_under1(Int i1, Extents exts)
+{
+ auto [s1] = std::submdspan_canonicalize_slices(exts, i1);
+ return true;
+}
+
+static_assert(test_under1(-1, dyn_sexts)); // { dg-error "expansion of" }
+static_assert(test_under1(-1, dyn_uexts)); // { dg-error "expansion of" }
+static_assert(test_under1(-1, sta_sexts)); // { dg-error "expansion of" }
+static_assert(test_under1(-1, sta_uexts)); // { dg-error "expansion of" }
+
+static_assert(test_under1(std::cw<-1>, dyn_sexts)); // { dg-error "required from" }
+static_assert(test_under1(std::cw<-1>, dyn_uexts)); // { dg-error "required from" }
+static_assert(test_under1(std::cw<-1>, sta_sexts)); // { dg-error "required from" }
+static_assert(test_under1(std::cw<-1>, sta_uexts)); // { dg-error "required from" }
+
+template<typename Int, typename Extents>
+constexpr bool
+test_over1(Int i1, Extents exts)
+{
+ auto [s1] = std::submdspan_canonicalize_slices(exts, i1);
+ return true;
+}
+
+static_assert(test_over1(0, dyn_empty)); // { dg-error "expansion of" }
+static_assert(test_over1(0, sta_empty)); // { dg-error "expansion of" }
+static_assert(test_over1(5, dyn_sexts)); // { dg-error "expansion of" }
+static_assert(test_over1(5, dyn_uexts)); // { dg-error "expansion of" }
+static_assert(test_over1(5, sta_sexts)); // { dg-error "expansion of" }
+static_assert(test_over1(5, sta_uexts)); // { dg-error "expansion of" }
+
+static_assert(test_over1(std::cw<0>, dyn_empty)); // { dg-error "expansion of" }
+static_assert(test_over1(std::cw<0>, sta_empty)); // { dg-error "expansion of" }
+static_assert(test_over1(std::cw<5>, dyn_sexts)); // { dg-error "expansion of" }
+static_assert(test_over1(std::cw<5>, dyn_uexts)); // { dg-error "expansion of" }
+static_assert(test_over1(std::cw<5>, sta_sexts)); // { dg-error "expansion of" }
+static_assert(test_over1(std::cw<5>, sta_uexts)); // { dg-error "expansion of" }
+
+template<typename Offset, typename Extent, typename Stride, typename Extents>
+ constexpr bool
+ test_under2(Offset o, Extent e, Stride s, Extents exts)
+ {
+ std::submdspan_canonicalize_slices(exts, std::strided_slice{o, e, s});
+ return true;
+ }
+
+constexpr auto i8_1 = int8_t{1};
+
+static_assert(test_under2(-i8_1, 0, 1, dyn_uexts)); // { dg-error "expansion of" }
+static_assert(test_under2(0, -i8_1, 1, dyn_uexts)); // { dg-error "expansion of" }
+static_assert(test_under2(0, 1, -i8_1, dyn_uexts)); // { dg-error "expansion of" }
+static_assert(test_under2(-i8_1, 0, 1, dyn_sexts)); // { dg-error "expansion of" }
+static_assert(test_under2(0, -i8_1, 1, dyn_sexts)); // { dg-error "expansion of" }
+static_assert(test_under2(0, 1, -i8_1, dyn_sexts)); // { dg-error "expansion of" }
+static_assert(test_under2(-i8_1, 0, 1, sta_uexts)); // { dg-error "expansion of" }
+static_assert(test_under2(0, -i8_1, 1, sta_uexts)); // { dg-error "expansion of" }
+static_assert(test_under2(0, 1, -i8_1, sta_uexts)); // { dg-error "expansion of" }
+static_assert(test_under2(-i8_1, 0, 1, sta_sexts)); // { dg-error "expansion of" }
+static_assert(test_under2(0, -i8_1, 1, sta_sexts)); // { dg-error "expansion of" }
+static_assert(test_under2(0, 1, -i8_1, sta_sexts)); // { dg-error "expansion of" }
+
+constexpr auto c_i8_m1 = std::cw<int8_t{-1}>;
+constexpr auto c_i16_m1 = std::cw<int16_t{-1}>;
+constexpr auto c_i64_m1 = std::cw<int64_t{-1}>;
+
+static_assert(test_under2(c_i8_m1, 0, 1, dyn_uexts)); // { dg-error "required from" }
+static_assert(test_under2(0, c_i16_m1, 1, dyn_uexts)); // { dg-error "required from" }
+static_assert(test_under2(0, 1, c_i64_m1, dyn_uexts)); // { dg-error "required from" }
+static_assert(test_under2(c_i8_m1, 0, 1, dyn_sexts)); // { dg-error "required from" }
+static_assert(test_under2(0, c_i16_m1, 1, dyn_sexts)); // { dg-error "required from" }
+static_assert(test_under2(0, 1, c_i64_m1, dyn_sexts)); // { dg-error "required from" }
+static_assert(test_under2(c_i8_m1, 0, 1, sta_uexts)); // { dg-error "required from" }
+static_assert(test_under2(0, c_i16_m1, 1, sta_uexts)); // { dg-error "required from" }
+static_assert(test_under2(0, 1, c_i64_m1, sta_uexts)); // { dg-error "required from" }
+static_assert(test_under2(c_i8_m1, 0, 1, sta_sexts)); // { dg-error "required from" }
+static_assert(test_under2(0, c_i16_m1, 1, sta_sexts)); // { dg-error "required from" }
+static_assert(test_under2(0, 1, c_i64_m1, sta_sexts)); // { dg-error "required from" }
+
+template<typename Offset, typename Extent, typename Stride, typename Extents>
+ constexpr bool
+ test_over2(Offset o, Extent e, Stride s, Extents exts)
+ {
+ std::submdspan_canonicalize_slices(exts, std::strided_slice{o, e, s});
+ return true;
+ }
+
+constexpr auto i8_6 = int8_t{6};
+constexpr auto c_i8_6 = std::cw<int8_t{6}>;
+constexpr auto c2 = std::cw<2>;
+constexpr auto c4 = std::cw<4>;
+
+static_assert(test_over2(i8_6, 0, 1, dyn_uexts)); // { dg-error "expansion of" }
+static_assert(test_over2(0, i8_6, 1, dyn_uexts)); // { dg-error "expansion of" }
+static_assert(test_over2(2, 4, 0, dyn_uexts)); // { dg-error "expansion of" }
+static_assert(test_over2(c_i8_6, 0, 1, dyn_uexts)); // { dg-error "expansion of" }
+static_assert(test_over2(0, c_i8_6, 1, dyn_uexts)); // { dg-error "expansion of" }
+static_assert(test_over2(c2, 4, 1, dyn_uexts)); // { dg-error "expansion of" }
+static_assert(test_over2(2, c4, 1, dyn_uexts)); // { dg-error "expansion of" }
+static_assert(test_over2(c2, c4, 1, dyn_uexts)); // { dg-error "expansion of" }
+
+static_assert(test_over2(i8_6, 0, 1, dyn_sexts)); // { dg-error "expansion of" }
+static_assert(test_over2(0, i8_6, 1, dyn_sexts)); // { dg-error "expansion of" }
+static_assert(test_over2(2, 4, 0, dyn_sexts)); // { dg-error "expansion of" }
+static_assert(test_over2(c_i8_6, 0, 1, dyn_sexts)); // { dg-error "expansion of" }
+static_assert(test_over2(0, c_i8_6, 1, dyn_sexts)); // { dg-error "expansion of" }
+static_assert(test_over2(c2, 4, 1, dyn_sexts)); // { dg-error "expansion of" }
+static_assert(test_over2(2, c4, 1, dyn_sexts)); // { dg-error "expansion of" }
+static_assert(test_over2(c2, c4, 1, dyn_sexts)); // { dg-error "expansion of" }
+
+static_assert(test_over2(i8_6, 0, 1, sta_uexts)); // { dg-error "expansion of" }
+static_assert(test_over2(0, i8_6, 1, sta_uexts)); // { dg-error "expansion of" }
+static_assert(test_over2(2, 4, 0, sta_uexts)); // { dg-error "expansion of" }
+static_assert(test_over2(c_i8_6, 0, 1, sta_uexts)); // { dg-error "expansion of" }
+static_assert(test_over2(0, c_i8_6, 1, sta_uexts)); // { dg-error "expansion of" }
+static_assert(test_over2(c2, 4, 1, sta_uexts)); // { dg-error "expansion of" }
+static_assert(test_over2(2, c4, 1, sta_uexts)); // { dg-error "expansion of" }
+static_assert(test_over2(c2, c4, 1, sta_uexts)); // { dg-error "expansion of" }
+
+static_assert(test_over2(i8_6, 0, 1, sta_sexts)); // { dg-error "expansion of" }
+static_assert(test_over2(0, i8_6, 1, sta_sexts)); // { dg-error "expansion of" }
+static_assert(test_over2(2, 4, 0, sta_sexts)); // { dg-error "expansion of" }
+static_assert(test_over2(c_i8_6, 0, 1, sta_sexts)); // { dg-error "expansion of" }
+static_assert(test_over2(0, c_i8_6, 1, sta_sexts)); // { dg-error "expansion of" }
+static_assert(test_over2(c2, 4, 1, sta_sexts)); // { dg-error "expansion of" }
+static_assert(test_over2(2, c4, 1, sta_sexts)); // { dg-error "expansion of" }
+static_assert(test_over2(c2, c4, 1, sta_sexts)); // { dg-error "expansion of" }
+
+// Checks the precondition: offset + extent <= exts.extent(0) for unsigned
+// index_type when offset + extent overflows.
+constexpr bool
+test_overflow1(auto o, auto e)
+{
+ auto exts = std::extents<uint8_t, dyn>{255};
+ auto slice = std::strided_slice{o, e, 1};
+ std::submdspan_canonicalize_slices(exts, slice);
+ return true;
+}
+
+static_assert(test_overflow1(128, 128)); // { dg-error "expansion of" }
+static_assert(test_overflow1(std::cw<128>, 128)); // { dg-error "expansion of" }
+static_assert(test_overflow1(128, std::cw<128>)); // { dg-error "expansion of" }
+static_assert(test_overflow1(std::cw<128>, std::cw<128>)); // { dg-error "expansion of" }
+
+constexpr bool
+test_overflow2(auto b, auto e)
+{
+ auto exts = std::extents<uint8_t, dyn>{255};
+ auto slice = std::pair{b, e};
+ std::submdspan_canonicalize_slices(exts, slice);
+ return true;
+}
+
+static_assert(test_overflow2(5, 4)); // { dg-error "expansion of" }
+static_assert(test_overflow2(std::cw<5>, 4)); // { dg-error "expansion of" }
+static_assert(test_overflow2(5, std::cw<4>)); // { dg-error "expansion of" }
+static_assert(test_overflow2(std::cw<5>, std::cw<4>)); // { dg-error "expansion of" }
+
+constexpr auto u8_4 = uint8_t{4};
+constexpr auto u8_5 = uint8_t{5};
+static_assert(test_overflow2(u8_5, u8_4)); // { dg-error "expansion of" }
+static_assert(test_overflow2(std::cw<u8_5>, u8_4)); // { dg-error "expansion of" }
+static_assert(test_overflow2(u8_5, std::cw<u8_4>)); // { dg-error "expansion of" }
+static_assert(test_overflow2(std::cw<u8_5>, std::cw<u8_4>)); // { dg-error "expansion of" }
+
+constexpr bool
+test_invalid(auto e, auto s)
+{
+ auto exts = std::extents(5);
+ auto slice = std::strided_slice(0, e, s);
+ std::submdspan_canonicalize_slices(exts, slice);
+ return true;
+}
+
+static_assert(test_invalid(3, 0)); // { dg-error "expansion of" }
+static_assert(test_invalid(3, std::cw<0>)); // { dg-error "expansion of" }
+static_assert(test_invalid(3, std::cw<0>)); // { dg-error "expansion of" }
+static_assert(test_invalid(std::cw<3>, std::cw<0>)); // { dg-error "expansion of" }
+
+
+// { dg-prune-output "static assertion failed" }
+// { dg-prune-output "__glibcxx_assert_fail" }
+// { dg-prune-output "__glibcxx_assert" }
+// { dg-prune-output "non-constant condition" }
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_extents.cc b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_extents.cc
new file mode 100644
index 0000000..841910a
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_extents.cc
@@ -0,0 +1,169 @@
+// { dg-do run { target c++26 } }
+#include <mdspan>
+
+#include "../int_like.h"
+#include <testsuite_hooks.h>
+
+constexpr size_t dyn = std::dynamic_extent;
+constexpr auto all = std::full_extent;
+
+constexpr bool
+test_from_full_extent()
+{
+ auto exts = std::extents<int, 3, dyn, 7>{};
+ auto sub_exts = submdspan_extents(exts, 1, all, all);
+ VERIFY(sub_exts.rank() == 2);
+ VERIFY(sub_exts.static_extent(0) == dyn);
+ VERIFY(sub_exts.extent(0) == exts.extent(1));
+ VERIFY(std::cmp_equal(sub_exts.static_extent(1), exts.extent(2)));
+ return true;
+}
+
+template<template<typename, typename> typename Pair, template<int> typename Cw>
+ constexpr bool
+ test_from_tuple()
+ {
+ auto exts = std::extents<int, 3, 5, 7>{};
+ auto s0 = Cw<1>{};
+ auto s1 = Pair{Cw<1>{}, Cw<2>{}};
+ auto s2 = Pair{Cw<1>{}, 4};
+ auto sub_exts = submdspan_extents(exts, s0, s1, s2);
+ VERIFY(sub_exts.rank() == 2);
+ VERIFY(sub_exts.static_extent(0) == size_t(get<1>(s1) - get<0>(s1)));
+ VERIFY(sub_exts.static_extent(1) == dyn);
+ VERIFY(std::cmp_equal(sub_exts.extent(1), get<1>(s2) - get<0>(s2)));
+ return true;
+ }
+
+template<template<int> typename Cw>
+ constexpr bool
+ test_from_tuple_all()
+ {
+ test_from_tuple<std::tuple, Cw>();
+ test_from_tuple<std::pair, Cw>();
+ return true;
+ }
+
+
+template<typename Int>
+ void
+ test_from_int_like_as_scalar()
+ {
+ auto exts = std::extents<int, 3, 5>{};
+ auto sub_exts = submdspan_extents(exts, Int(1), std::tuple{1, 3});
+ VERIFY(sub_exts.rank() == 1);
+ VERIFY(sub_exts.static_extent(0) == dyn);
+ VERIFY(sub_exts.extent(0) == 2);
+ }
+
+template<template<int> typename Cw>
+ constexpr bool
+ test_from_const_int()
+ {
+ auto exts = std::extents<int, 3, 5>{};
+ auto sub_exts = submdspan_extents(exts, Cw<1>{}, std::tuple{1, 3});
+ VERIFY(sub_exts.rank() == 1);
+ VERIFY(sub_exts.static_extent(0) == dyn);
+ VERIFY(sub_exts.extent(0) == 2);
+ return true;
+ }
+
+template<typename Int>
+ constexpr bool
+ test_from_int_like_in_tuple()
+ {
+ auto exts = std::extents<int, 3, 5>{};
+ auto sub_exts = submdspan_extents(exts, Int(1), std::tuple{Int(1), Int(3)});
+ VERIFY(sub_exts.rank() == 1);
+ VERIFY(sub_exts.static_extent(0) == dyn);
+ VERIFY(sub_exts.extent(0) == 2);
+ return true;
+ }
+
+template<template<int> typename Cw>
+ constexpr bool
+ test_from_strided_slice()
+ {
+ auto exts = std::extents<int, 5, 7, 11>{};
+ {
+ auto s0 = 1;
+ auto s1 = std::strided_slice{0, 0, 0};
+ auto s2 = std::strided_slice{1, Cw<0>{}, 0};
+ auto sub_exts = submdspan_extents(exts, s0, s1, s2);
+ VERIFY(sub_exts.rank() == 2);
+ VERIFY(sub_exts.static_extent(0) == dyn);
+ VERIFY(sub_exts.extent(0) == 0);
+ VERIFY(sub_exts.static_extent(1) == 0);
+ }
+
+ {
+ auto s0 = 1;
+ auto s1 = std::strided_slice{0, 2, Cw<1>{}};
+ auto s2 = std::strided_slice{1, Cw<2>{}, 1};
+ auto sub_exts = submdspan_extents(exts, s0, s1, s2);
+ VERIFY(sub_exts.rank() == 2);
+ VERIFY(sub_exts.static_extent(0) == dyn);
+ VERIFY(sub_exts.extent(0) == 2);
+ VERIFY(sub_exts.static_extent(1) == dyn);
+ VERIFY(sub_exts.extent(1) == 2);
+ }
+
+ {
+ // selected = 1 x [1, 3] x [1, 4, 7, 10]
+ auto s0 = 1;
+ auto s1 = std::strided_slice{1, Cw<4>{}, 2};
+ auto s2 = std::strided_slice{1, Cw<10>{}, Cw<3>{}};
+ auto sub_exts = submdspan_extents(exts, s0, s1, s2);
+ VERIFY(sub_exts.rank() == 2);
+ VERIFY(sub_exts.static_extent(0) == dyn);
+ VERIFY(sub_exts.extent(0) == 2);
+ VERIFY(sub_exts.static_extent(1) == 4);
+ }
+
+ {
+ // selected = [0, 2] x [1, 3] x [0, 3, 6]
+ auto s0 = std::strided_slice(0, 3, 2);
+ auto s1 = std::strided_slice(1, 4, 2);
+ auto s2 = std::strided_slice(0, 7, 3);
+ auto sub_exts = submdspan_extents(exts, s0, s1, s2);
+ VERIFY(sub_exts.rank() == 3);
+ VERIFY(sub_exts.extent(0) == 2);
+ VERIFY(sub_exts.extent(1) == 2);
+ VERIFY(sub_exts.extent(2) == 3);
+ }
+ return true;
+ }
+
+template<int Value>
+ using CW = std::constant_wrapper<Value, int>;
+
+template<int Value>
+ using IC = std::integral_constant<int, Value>;
+
+constexpr bool
+test_all()
+{
+ test_from_full_extent();
+ test_from_tuple_all<CW>();
+ test_from_tuple_all<IC>();
+ test_from_const_int<CW>();
+ test_from_const_int<IC>();
+ test_from_strided_slice<CW>();
+ test_from_strided_slice<IC>();
+ test_from_int_like_in_tuple<StructuralInt>();
+ return true;
+}
+
+int
+main()
+{
+ test_all();
+ static_assert(test_all());
+
+ test_from_int_like_as_scalar<CustomIndexType<CustomIndexKind::Const, true>>();
+ test_from_int_like_as_scalar<CustomIndexType<CustomIndexKind::Throwing, true>>();
+ test_from_int_like_as_scalar<CustomIndexType<CustomIndexKind::Mutating, true>>();
+ test_from_int_like_as_scalar<CustomIndexType<CustomIndexKind::RValue, true>>();
+ test_from_int_like_as_scalar<StructuralInt>();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_extents_neg.cc b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_extents_neg.cc
new file mode 100644
index 0000000..cf27c0c
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_extents_neg.cc
@@ -0,0 +1,48 @@
+// { dg-do compile { target c++26 } }
+#include <mdspan>
+
+#include <cstdint>
+
+struct NotASlice
+{ };
+
+constexpr bool
+test_unrelated_stride_type()
+{
+ auto exts = std::extents(3, 5, 7);
+ auto sub_exts = submdspan_extents(exts, 1, NotASlice{}, 2); // { dg-error "required from" }
+ return true;
+}
+static_assert(test_unrelated_stride_type());
+
+constexpr bool
+test_invalid_stride_zero()
+{
+ auto exts = std::extents(3, 5, 7);
+ auto s = std::strided_slice{0, 1, 0};
+ auto sub_exts = submdspan_extents(exts, 1, s, 2); // { dg-error "expansion of" }
+ return true;
+}
+static_assert(test_invalid_stride_zero());
+
+template<typename Slice>
+constexpr bool
+test_out_of_bounds(const Slice& slice)
+{
+ auto exts = std::extents<uint16_t, 3, 5, 7>{};
+ auto sub_exts = submdspan_extents(exts, 1, slice, 2); // { dg-error "expansion of" }
+ return true;
+}
+static_assert(test_out_of_bounds(std::strided_slice{0, 6, 1})); // { dg-error "expansion of" }
+static_assert(test_out_of_bounds(std::strided_slice{0, 7, 2})); // { dg-error "expansion of" }
+static_assert(test_out_of_bounds(std::strided_slice{1, 6, 1})); // { dg-error "expansion of" }
+static_assert(test_out_of_bounds(std::strided_slice{1, 6, 2})); // { dg-error "expansion of" }
+static_assert(test_out_of_bounds(std::tuple{1, 6})); // { dg-error "expansion of" }
+static_assert(test_out_of_bounds(std::tuple{std::cw<1>, std::cw<6>})); // { dg-error "expansion of" }
+static_assert(test_out_of_bounds(std::strided_slice{-1, 2, 1})); // { dg-error "expansion of" }
+static_assert(test_out_of_bounds(std::tuple{-1, 2})); // { dg-error "expansion of" }
+
+// { dg-prune-output "cannot decompose class type 'NotASlice'" }
+// { dg-prune-output "static assertion failed" }
+// { dg-prune-output "__glibcxx_assert_fail" }
+// { dg-prune-output "non-constant condition" }
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_mapping.cc b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_mapping.cc
new file mode 100644
index 0000000..efd71d1
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_mapping.cc
@@ -0,0 +1,301 @@
+// { dg-do run { target c++26 } }
+#include <mdspan>
+
+#include <iostream> // TODO remove
+#include "../layout_traits.h"
+#include <testsuite_hooks.h>
+
+constexpr size_t dyn = std::dynamic_extent;
+constexpr auto all = std::full_extent;
+
+template<typename Mapping, typename... Slices>
+ constexpr auto
+ call_submdspan_mapping(const Mapping& m, std::tuple<Slices...> slices)
+ {
+ auto impl = [&]<size_t... I>(std::index_sequence<I...>)
+ { return submdspan_mapping(m, get<I>(slices)...); };
+ return impl(std::make_index_sequence<sizeof...(Slices)>());
+ }
+
+template<typename Layout>
+ constexpr bool
+ test_layout_common_return_types()
+ {
+ constexpr auto padding_side = DeducePaddingSide::from_typename<Layout>();
+ using Traits = LayoutTraits<padding_side>;
+ using layout_unpadded = typename Traits::layout_same;
+
+ {
+ auto m0 = typename Layout::mapping(std::extents());
+ auto result = submdspan_mapping(m0);
+ using layout_type = typename decltype(result.mapping)::layout_type;
+ static_assert(std::same_as<layout_type, Layout>);
+ }
+
+ auto exts = Traits::make_extents(std::dims<5, int>(3, 5, 7, 11, 13));
+ auto m = typename Layout::mapping(exts);
+ auto s251 = std::strided_slice{2, 5, std::cw<1>};
+
+ {
+ auto slices = std::tuple{0, 0, 0, 0, 0};
+ auto result = call_submdspan_mapping(m, Traits::make_tuple(slices));
+ using layout_type = typename decltype(result.mapping)::layout_type;
+ static_assert(std::same_as<layout_type, layout_unpadded>);
+ }
+
+ {
+ auto s0 = std::strided_slice{1, 1, std::cw<1>};
+ auto slices = std::tuple{s0, all, all, s251, 0};
+ auto result = call_submdspan_mapping(m, Traits::make_tuple(slices));
+ using layout_type = typename decltype(result.mapping)::layout_type;
+ static_assert(is_same_padded<padding_side, layout_type>);
+ }
+
+ {
+ auto s0 = std::strided_slice{1, 2, std::cw<1>};
+ auto slices = std::tuple{s0, all, all, s251, 0};
+ auto result = call_submdspan_mapping(m, Traits::make_tuple(slices));
+ using layout_type = typename decltype(result.mapping)::layout_type;
+ static_assert(is_same_padded<padding_side, layout_type>);
+ }
+
+ {
+ auto s0 = std::strided_slice{1, 2, std::cw<1>};
+ auto slices = std::tuple{s0, 0, all, s251, 0};
+ auto result = call_submdspan_mapping(m, Traits::make_tuple(slices));
+ using layout_type = typename decltype(result.mapping)::layout_type;
+ static_assert(is_same_padded<padding_side, layout_type>);
+ }
+
+ {
+ auto s0 = std::strided_slice{1, 2, 1};
+ auto slices = std::tuple{s0, all, all, s251, 0};
+ auto result = call_submdspan_mapping(m, Traits::make_tuple(slices));
+ using layout_type = decltype(result.mapping)::layout_type;
+ static_assert(std::same_as<layout_type, std::layout_stride>);
+ }
+
+ {
+ auto slices = std::tuple{1, all, all, s251, 0};
+ auto result = call_submdspan_mapping(m, Traits::make_tuple(slices));
+ using layout_type = decltype(result.mapping)::layout_type;
+ static_assert(std::same_as<layout_type, std::layout_stride>);
+ }
+
+ {
+ auto s3 = std::strided_slice{2, std::cw<7>, std::cw<2>};
+ auto slices = std::tuple{all, all, all, s3, 0};
+ auto result = call_submdspan_mapping(m, Traits::make_tuple(slices));
+ using layout_type = decltype(result.mapping)::layout_type;
+ static_assert(std::same_as<layout_type, std::layout_stride>);
+ }
+ return true;
+ }
+
+template<typename Layout>
+ constexpr bool
+ test_layout_unpadded_return_types()
+ {
+ constexpr auto padding_side = DeducePaddingSide::from_typename<Layout>();
+ using Traits = LayoutTraits<padding_side>;
+
+ auto exts = Traits::make_extents(std::dims<5, int>(3, 5, 7, 11, 13));
+ auto m = typename Layout::mapping(exts);
+ auto s251 = std::strided_slice{2, 5, std::cw<1>};
+
+ {
+ auto slices = std::tuple{all, all, all, s251, 0};
+ auto result = call_submdspan_mapping(m, Traits::make_tuple(slices));
+ using layout_type = typename decltype(result.mapping)::layout_type;
+ static_assert(std::same_as<layout_type, Layout>);
+ }
+ return true;
+ }
+
+template<typename Layout>
+ constexpr bool
+ test_layout_padded_return_types()
+ {
+ constexpr auto padding_side = DeducePaddingSide::from_typename<Layout>();
+ using Traits = LayoutTraits<padding_side>;
+
+ auto exts = Traits::make_extents(std::dims<5, int>(3, 5, 7, 11, 13));
+ auto m = typename Layout::mapping(exts);
+ auto s251 = std::strided_slice{2, 5, std::cw<1>};
+
+ {
+ auto slices = std::tuple{all, all, all, s251, 0};
+ auto result = call_submdspan_mapping(m, Traits::make_tuple(slices));
+ using layout_type = typename decltype(result.mapping)::layout_type;
+ using layout_expected = typename Traits::layout_same_padded<dyn>;
+ static_assert(std::same_as<layout_type, layout_expected>);
+ }
+
+ {
+ auto slices = std::tuple{all, 0, 0, 0, 0};
+ auto result = call_submdspan_mapping(m, Traits::make_tuple(slices));
+ using layout_type = typename decltype(result.mapping)::layout_type;
+ using layout_expected = typename Traits::layout_same;
+ static_assert(std::same_as<layout_type, layout_expected>);
+ }
+
+ {
+ auto s121 = std::strided_slice{1, 2, std::cw<1>};
+ auto slices = std::tuple{s121, 0, 0, 0, 0};
+ auto result = call_submdspan_mapping(m, Traits::make_tuple(slices));
+ using layout_type = typename decltype(result.mapping)::layout_type;
+ using layout_expected = typename Traits::layout_same;
+ static_assert(std::same_as<layout_type, layout_expected>);
+ }
+
+ {
+ auto s121 = std::strided_slice{1, 2, std::cw<1>};
+ auto slices = std::tuple{0, s121, 0, 0, 0};
+ auto result = call_submdspan_mapping(m, Traits::make_tuple(slices));
+ using layout_type = typename decltype(result.mapping)::layout_type;
+ static_assert(std::same_as<layout_type, std::layout_stride>);
+ }
+ return true;
+ }
+
+template<typename Layout>
+ constexpr bool
+ test_layout_unpadded_padding_value()
+ {
+ using Traits = LayoutTraits<DeducePaddingSide::from_typename<Layout>()>;
+ auto s0 = std::strided_slice{size_t(1), size_t(2), std::cw<size_t(1)>};
+ auto s3 = std::strided_slice{size_t(2), size_t(5), std::cw<size_t(1)>};
+
+ auto check = [&](auto exts, size_t expected)
+ {
+ auto m = typename Layout::mapping(Traits::make_extents(exts));
+ auto slices = std::tuple{s0, size_t(0), all, s3, size_t(0)};
+ auto result = call_submdspan_mapping(m, Traits::make_tuple(slices));
+ auto padding_value = decltype(result.mapping)::padding_value;
+ VERIFY(padding_value == expected);
+ };
+
+ check(std::extents(std::cw<3>, std::cw<5>, std::cw<7>, 11, 13), 3*5);
+ check(std::extents(std::cw<3>, std::cw<5>, 7, 11, 13), 3*5);
+ check(std::extents(std::cw<3>, 5, 7, 11, 13), dyn);
+ check(std::extents(3, 5, 7, 11, 13), dyn);
+ return true;
+ }
+
+template<typename Layout>
+constexpr size_t static_padding_value = 1;
+
+template<size_t PaddingValue>
+constexpr size_t static_padding_value<std::layout_left_padded<PaddingValue>> = PaddingValue;
+
+template<size_t PaddingValue>
+constexpr size_t static_padding_value<std::layout_right_padded<PaddingValue>> = PaddingValue;
+
+template<typename Layout>
+ constexpr bool
+ test_layout_padded_padding_value()
+ {
+ using Traits = LayoutTraits<DeducePaddingSide::from_typename<Layout>()>;
+ auto s0 = std::strided_slice{size_t(1), size_t(2), std::cw<size_t(1)>};
+ auto s3 = std::strided_slice{size_t(2), size_t(5), std::cw<size_t(1)>};
+
+ auto check = [&](auto exts, size_t expected)
+ {
+ auto m = typename Layout::mapping(Traits::make_extents(exts));
+ auto slices = std::tuple{s0, size_t(0), all, s3, size_t(0)};
+ auto result = call_submdspan_mapping(m, Traits::make_tuple(slices));
+ auto padding_value = decltype(result.mapping)::padding_value;
+ VERIFY(padding_value == expected);
+ };
+
+ auto pad = [](int n, int m) -> size_t
+ {
+ constexpr auto padding_value = static_padding_value<Layout>;
+ if constexpr (padding_value != dyn)
+ {
+ auto npad = ((n + padding_value - 1) / padding_value) * padding_value;
+ return npad * m;
+ }
+ else
+ return dyn;
+ };
+
+ check(std::extents(std::cw<3>, std::cw<5>, std::cw<7>, 11, 13), pad(3, 5));
+ check(std::extents(std::cw<3>, std::cw<5>, 7, 11, 13), pad(3, 5));
+ check(std::extents(std::cw<3>, std::cw<6>, 7, 11, 13), pad(3, 6));
+ check(std::extents(std::cw<3>, 5, 7, 11, 13), dyn);
+ check(std::extents(3, 5, 7, 11, 13), dyn);
+ return true;
+ }
+
+constexpr bool
+test_layout_stride_return_types()
+{
+ auto exts = std::extents(3, 5);
+ auto m = std::layout_stride::mapping(exts, std::array{2, 12});
+
+ using index_type = decltype(exts)::index_type;
+ auto s1 = std::strided_slice{index_type(2), index_type(2),
+ std::cw<index_type(2)>};
+ auto result = submdspan_mapping(m, index_type(1), s1);
+ using layout_type = decltype(result.mapping)::layout_type;
+ static_assert(std::same_as<layout_type, std::layout_stride>);
+ return true;
+}
+
+template<typename Layout>
+ constexpr bool
+ test_return_types_all()
+ {
+ return true;
+ }
+
+template<typename Layout>
+ constexpr bool
+ test_return_types_unpadded_all()
+ {
+ test_layout_common_return_types<Layout>();
+ static_assert(test_layout_common_return_types<Layout>());
+
+ test_layout_unpadded_return_types<Layout>();
+ static_assert(test_layout_unpadded_return_types<Layout>());
+
+ test_layout_unpadded_padding_value<Layout>();
+ static_assert(test_layout_unpadded_padding_value<Layout>());
+ return true;
+ }
+
+template<typename Layout>
+ constexpr bool
+ test_return_types_padded_all()
+ {
+ test_layout_common_return_types<Layout>();
+ static_assert(test_layout_common_return_types<Layout>());
+
+ test_layout_padded_return_types<Layout>();
+ static_assert(test_layout_padded_return_types<Layout>());
+
+ test_layout_padded_padding_value<Layout>();
+ static_assert(test_layout_padded_padding_value<Layout>());
+ return true;
+ }
+
+int
+main()
+{
+ test_return_types_unpadded_all<std::layout_left>();
+ test_return_types_unpadded_all<std::layout_right>();
+
+ test_return_types_padded_all<std::layout_left_padded<1>>();
+ test_return_types_padded_all<std::layout_left_padded<2>>();
+ test_return_types_padded_all<std::layout_left_padded<dyn>>();
+
+ test_return_types_padded_all<std::layout_right_padded<1>>();
+ test_return_types_padded_all<std::layout_right_padded<2>>();
+ test_return_types_padded_all<std::layout_right_padded<dyn>>();
+
+ test_layout_stride_return_types();
+ static_assert(test_layout_stride_return_types());
+ return 0;
+}
+
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_neg.cc b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_neg.cc
new file mode 100644
index 0000000..39eb18c
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_neg.cc
@@ -0,0 +1,122 @@
+// { dg-do compile { target c++26 } }
+#include <mdspan>
+
+#include <vector>
+
+template<typename Layout, typename... Slices>
+ constexpr bool
+ check_slice_range(Slices... slices)
+ {
+ auto m = typename Layout::mapping<std::extents<int, 3, 5, 7>>{};
+ auto storage = std::vector<double>(m.required_span_size());
+ auto md = std::mdspan(storage.data(), m);
+
+ auto submd = submdspan(md, slices...); // { dg-error "expansion of" }
+ (void) submd;
+ return true;
+ }
+
+template<typename Layout>
+ constexpr bool
+ test_int_under()
+ {
+ check_slice_range<Layout>(1, -1, 2); // { dg-error "expansion of" }
+ return true;
+ }
+static_assert(test_int_under<std::layout_left>()); // { dg-error "expansion of" }
+static_assert(test_int_under<std::layout_right>()); // { dg-error "expansion of" }
+static_assert(test_int_under<std::layout_stride>()); // { dg-error "expansion of" }
+
+template<typename Layout>
+ constexpr bool
+ test_int_over()
+ {
+ check_slice_range<Layout>(1, 5, 2); // { dg-error "expansion of" }
+ return true;
+ }
+static_assert(test_int_over<std::layout_left>()); // { dg-error "expansion of" }
+static_assert(test_int_over<std::layout_right>()); // { dg-error "expansion of" }
+static_assert(test_int_over<std::layout_stride>()); // { dg-error "expansion of" }
+
+template<typename Layout>
+ constexpr bool
+ test_tuple_under()
+ {
+ check_slice_range<Layout>(1, std::tuple{-1, 2}, 2); // { dg-error "expansion of" }
+ return true;
+ }
+static_assert(test_tuple_under<std::layout_left>()); // { dg-error "expansion of" }
+static_assert(test_tuple_under<std::layout_right>()); // { dg-error "expansion of" }
+static_assert(test_tuple_under<std::layout_stride>()); // { dg-error "expansion of" }
+
+template<typename Layout>
+ constexpr bool
+ test_tuple_reversed()
+ {
+ check_slice_range<Layout>(1, std::tuple{3, 2}, 2); // { dg-error "expansion of" }
+ return true;
+ }
+static_assert(test_tuple_reversed<std::layout_left>()); // { dg-error "expansion of" }
+static_assert(test_tuple_reversed<std::layout_right>()); // { dg-error "expansion of" }
+static_assert(test_tuple_reversed<std::layout_stride>()); // { dg-error "expansion of" }
+
+template<typename Layout>
+ constexpr bool
+ test_tuple_over()
+ {
+ check_slice_range<Layout>(1, std::tuple{0, 6}, 2); // { dg-error "expansion of" }
+ return true;
+ }
+static_assert(test_tuple_over<std::layout_left>()); // { dg-error "expansion of" }
+static_assert(test_tuple_over<std::layout_right>()); // { dg-error "expansion of" }
+static_assert(test_tuple_over<std::layout_stride>()); // { dg-error "expansion of" }
+
+template<typename Layout>
+ constexpr bool
+ test_strided_slice_zero()
+ {
+ check_slice_range<Layout>(1, std::strided_slice{1, 1, 0}, 2); // { dg-error "expansion of" }
+ return true;
+ }
+static_assert(test_strided_slice_zero<std::layout_left>()); // { dg-error "expansion of" }
+static_assert(test_strided_slice_zero<std::layout_right>()); // { dg-error "expansion of" }
+static_assert(test_strided_slice_zero<std::layout_stride>()); // { dg-error "expansion of" }
+
+template<typename Layout>
+ constexpr bool
+ test_strided_slice_offset_under()
+ {
+ check_slice_range<Layout>(1, std::strided_slice{-1, 1, 1}, 2); // { dg-error "expansion of" }
+ return true;
+ }
+static_assert(test_strided_slice_offset_under<std::layout_left>()); // { dg-error "expansion of" }
+static_assert(test_strided_slice_offset_under<std::layout_right>()); // { dg-error "expansion of" }
+static_assert(test_strided_slice_offset_under<std::layout_stride>()); // { dg-error "expansion of" }
+
+template<typename Layout>
+ constexpr bool
+ test_strided_slice_offset_over()
+ {
+ check_slice_range<Layout>(1, std::strided_slice{6, 0, 1}, 2); // { dg-error "expansion of" }
+ return true;
+ }
+static_assert(test_strided_slice_offset_over<std::layout_left>()); // { dg-error "expansion of" }
+static_assert(test_strided_slice_offset_over<std::layout_right>()); // { dg-error "expansion of" }
+static_assert(test_strided_slice_offset_over<std::layout_stride>()); // { dg-error "expansion of" }
+
+template<typename Layout>
+ constexpr bool
+ test_strided_slice_extent_over()
+ {
+ check_slice_range<Layout>(1, std::strided_slice{1, 5, 1}, 2); // { dg-error "expansion of" }
+ return true;
+ }
+static_assert(test_strided_slice_extent_over<std::layout_left>()); // { dg-error "expansion of" }
+static_assert(test_strided_slice_extent_over<std::layout_right>()); // { dg-error "expansion of" }
+static_assert(test_strided_slice_extent_over<std::layout_stride>()); // { dg-error "expansion of" }
+
+// { dg-prune-output "static assertion failed" }
+// { dg-prune-output "__glibcxx_assert_fail" }
+// { dg-prune-output "non-constant condition" }
+// { dg-prune-output "no matching function" }
+// { dg-prune-output "does not satisfy placeholder constraints" }
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/version.cc b/libstdc++-v3/testsuite/23_containers/mdspan/version.cc
new file mode 100644
index 0000000..1882600
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/version.cc
@@ -0,0 +1,20 @@
+// { dg-do preprocess { target c++23 } }
+// { dg-add-options no_pch }
+
+#include <mdspan>
+
+#ifndef __cpp_lib_mdspan
+#error "Feature test macro __cpp_lib_mdspan is missing for <mdspan>"
+#elif __cplusplus <= 202302L && __cpp_lib_mdspan != 202207L
+#error "Feature test macro __cpp_lib_mdspan has the wrong value for C++23"
+#elif __cplusplus > 202302L && __cpp_lib_mdspan != 202406L
+#error "Feature test macro __cpp_lib_mdspan has the wrong value for C++26"
+#endif
+
+#if __cplusplus > 202302L
+#ifndef __cpp_lib_aligned_accessor
+#error "Feature test macro __cpp_lib_aligned_accessor is missing for <mdspan>"
+#elif __cpp_lib_aligned_accessor != 202411L
+#error "Feature test macro __cpp_lib_aligned_accessor has the wrong value"
+#endif
+#endif
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 4a8ea9f..bb79720 100644
--- a/libstdc++-v3/testsuite/23_containers/multimap/cons/from_range.cc
+++ b/libstdc++-v3/testsuite/23_containers/multimap/cons/from_range.cc
@@ -43,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);
@@ -61,7 +61,7 @@ constexpr bool is_equal(std::less<T>, std::less<U>)
{ return true; }
constexpr bool is_equal(StateCmp lhs, StateCmp rhs)
-{ return lhs.state = rhs.state; }
+{ return lhs.state == rhs.state; }
constexpr auto get0 = [](auto const& t) {
using std::get;
@@ -103,12 +103,12 @@ do_test(Alloc alloc, Cmp cmp)
std::multimap<K, V, Cmp, Alloc> m4(std::from_range, Range(a, a+4), cmp);
VERIFY( eq(m4, {a, 4}) );
VERIFY( m4.get_allocator() == Alloc() );
- VERIFY( is_equal(m4.key_comp(), Cmp()) );
+ VERIFY( is_equal(m4.key_comp(), cmp) );
std::multimap<K, V, Cmp, Alloc> m9(std::from_range, Range(a, a+9), alloc);
VERIFY( eq(m9, {a, 9}) );
VERIFY( m9.get_allocator() == alloc );
- VERIFY( is_equal(m9.key_comp(), cmp) );
+ VERIFY( is_equal(m9.key_comp(), Cmp()) );
std::multimap<K, V, Cmp, Alloc> mr(std::from_range, Range(a, a+14), cmp, alloc);
VERIFY( eq(mr, {a, 14}) );
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 cdba7eb..aa9be9c 100644
--- a/libstdc++-v3/testsuite/23_containers/multiset/cons/from_range.cc
+++ b/libstdc++-v3/testsuite/23_containers/multiset/cons/from_range.cc
@@ -48,7 +48,7 @@ constexpr bool is_equal(std::less<T>, std::less<U>)
{ return true; }
constexpr bool is_equal(StateCmp lhs, StateCmp rhs)
-{ return lhs.state = rhs.state; }
+{ return lhs.state == rhs.state; }
template<typename Range, typename Alloc, typename Cmp>
constexpr void
@@ -82,12 +82,12 @@ do_test(Alloc alloc, Cmp cmp)
std::set<V, Cmp, Alloc> s4(std::from_range, Range(a, a+4), cmp);
VERIFY( eq(s4, {a, 4}) );
VERIFY( s4.get_allocator() == Alloc() );
- VERIFY( is_equal(s4.key_comp(), Cmp()) );
+ VERIFY( is_equal(s4.key_comp(), cmp) );
std::set<V, Cmp, Alloc> s9(std::from_range, Range(a, a+9), alloc);
VERIFY( eq(s9, {a, 9}) );
VERIFY( s9.get_allocator() == alloc );
- VERIFY( is_equal(s9.key_comp(), cmp) );
+ VERIFY( is_equal(s9.key_comp(), Cmp()) );
std::set<V, Cmp, Alloc> sr(std::from_range, Range(a, a+14), cmp, alloc);
VERIFY( eq(sr, {a, 9}) );
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 efde05d..23922bf 100644
--- a/libstdc++-v3/testsuite/23_containers/set/cons/from_range.cc
+++ b/libstdc++-v3/testsuite/23_containers/set/cons/from_range.cc
@@ -47,7 +47,7 @@ constexpr bool is_equal(std::less<T>, std::less<U>)
{ return true; }
constexpr bool is_equal(StateCmp lhs, StateCmp rhs)
-{ return lhs.state = rhs.state; }
+{ return lhs.state == rhs.state; }
template<typename Range, typename Alloc, typename Cmp>
constexpr void
@@ -81,12 +81,12 @@ do_test(Alloc alloc, Cmp cmp)
std::set<V, Cmp, Alloc> s4(std::from_range, Range(a, a+4), cmp);
VERIFY( eq(s4, {a, 4}) );
VERIFY( s4.get_allocator() == Alloc() );
- VERIFY( is_equal(s4.key_comp(), Cmp()) );
+ VERIFY( is_equal(s4.key_comp(), cmp) );
std::set<V, Cmp, Alloc> s9(std::from_range, Range(a, a+9), alloc);
VERIFY( eq(s9, {a, 9}) );
VERIFY( s9.get_allocator() == alloc );
- VERIFY( is_equal(s9.key_comp(), cmp) );
+ VERIFY( is_equal(s9.key_comp(), Cmp()) );
std::set<V, Cmp, Alloc> sr(std::from_range, Range(a, a+14), cmp, alloc);
VERIFY( eq(sr, {a, 9}) );
diff --git a/libstdc++-v3/testsuite/23_containers/span/120997.cc b/libstdc++-v3/testsuite/23_containers/span/120997.cc
new file mode 100644
index 0000000..fbf194c
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/span/120997.cc
@@ -0,0 +1,46 @@
+// { dg-do run { target c++26 } }
+
+#include <span>
+#include <testsuite_hooks.h>
+
+void
+test_first()
+{
+ bool arr[5];
+ std::span<const bool> s(arr);
+ std::span<const bool> s2 = s.first(5);
+ VERIFY( s2.data() == s.data() );
+ std::span<const bool> s3 = s.first<5>();
+ VERIFY( s3.data() == s.data() );
+}
+
+void
+test_last()
+{
+ bool arr[5];
+ std::span<const bool> s(arr);
+ std::span<const bool> s2 = s.last(5);
+ VERIFY( s2.data() == s.data() );
+ std::span<const bool> s3 = s.last<5>();
+ VERIFY( s3.data() == s.data() );
+}
+
+void
+test_subspan()
+{
+ bool arr[5];
+ std::span<const bool> s(arr);
+ std::span<const bool> s2 = s.subspan(0, 5);
+ VERIFY( s2.data() == s.data() );
+ std::span<const bool> s3 = s.subspan<0>();
+ VERIFY( s3.data() == s.data() );
+ std::span<const bool> s4 = s.subspan<0, 5>();
+ VERIFY( s4.data() == s.data() );
+}
+
+int main()
+{
+ test_first();
+ test_last();
+ test_subspan();
+}
diff --git a/libstdc++-v3/testsuite/23_containers/span/contiguous_range_neg.cc b/libstdc++-v3/testsuite/23_containers/span/contiguous_range_neg.cc
index c9e9112..890fdf8 100644
--- a/libstdc++-v3/testsuite/23_containers/span/contiguous_range_neg.cc
+++ b/libstdc++-v3/testsuite/23_containers/span/contiguous_range_neg.cc
@@ -25,6 +25,7 @@ main()
{
std::deque<int> d{};
std::span<int, std::dynamic_extent> myspan(d); // { dg-error "no match" }
+ (void) myspan;
}
// { dg-prune-output "data" }
diff --git a/libstdc++-v3/testsuite/23_containers/span/deduction.cc b/libstdc++-v3/testsuite/23_containers/span/deduction.cc
index dce6ced..55a5862 100644
--- a/libstdc++-v3/testsuite/23_containers/span/deduction.cc
+++ b/libstdc++-v3/testsuite/23_containers/span/deduction.cc
@@ -80,4 +80,25 @@ test01()
std::span s12(const_cast<const std::span<int>&>(s5));
static_assert( is_dynamic_span<int>(s12) );
+
+ std::span s13(a.data(), std::integral_constant<size_t, 3>{});
+ static_assert( is_static_span<long, 3>(s13) );
+
+ std::span s14(a.data(), true);
+ static_assert( is_dynamic_span<long>(s14) );
+
+ std::span s15(a.data(), std::true_type{});
+ static_assert( is_dynamic_span<long>(s15) );
+
+#if __glibcxx_constant_wrapper
+ auto c5 = std::constant_wrapper<5>{};
+ std::span s16(a.data(), c5);
+ static_assert( is_static_span<long, 5>(s16) );
+
+ std::span s17(a.data(), std::cw<4>);
+ static_assert( is_static_span<long, 4>(s17) );
+
+ std::span s18(a.data(), std::cw<true>);
+ static_assert( is_dynamic_span<long>(s18) );
+#endif
}
diff --git a/libstdc++-v3/testsuite/23_containers/tuple/comparison_operators/119721.cc b/libstdc++-v3/testsuite/23_containers/tuple/comparison_operators/119721.cc
new file mode 100644
index 0000000..cad7ca0
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/tuple/comparison_operators/119721.cc
@@ -0,0 +1,65 @@
+// { dg-do compile { target c++23 } }
+// { dg-options "-std=c++23" }
+
+// Test for PR libstdc++/119721: tuple<> comparison with array<T, 0>
+
+#include <tuple>
+#include <array>
+#include <testsuite_hooks.h>
+#include <cassert>
+
+constexpr void
+test01()
+{
+ std::tuple<> t;
+ std::array<int, 0> a;
+
+ // Basic comparison should work
+ VERIFY( t == a );
+ VERIFY( a == t );
+ VERIFY( !(t != a) );
+ VERIFY( !(a != t) );
+
+ // Ordering comparisons should be equal
+ VERIFY( !(t < a) );
+ VERIFY( !(t > a) );
+ VERIFY( t <= a );
+ VERIFY( t >= a );
+ VERIFY( !(a < t) );
+ VERIFY( !(a > t) );
+ VERIFY( a <= t );
+ VERIFY( a >= t );
+
+ // Three-way comparison should return equal
+ VERIFY( (t <=> a) == std::strong_ordering::equal );
+ VERIFY( (a <=> t) == std::strong_ordering::equal );
+}
+
+constexpr void
+test02()
+{
+ // Test with non-comparable element type
+ struct NonComparable {
+ void operator==(const NonComparable&) const = delete;
+ void operator<=>(const NonComparable&) const = delete;
+ };
+
+ std::tuple<> t;
+ std::array<NonComparable, 0> a;
+
+ // Should still work because empty containers don't compare elements
+ VERIFY( t == a );
+ VERIFY( (t <=> a) == std::strong_ordering::equal );
+}
+
+int main()
+{
+ auto test_all = [] {
+ test01();
+ test02();
+ };
+
+ test_all();
+ static_VERIFY( test_all() );
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/tuple/cons/119721.cc b/libstdc++-v3/testsuite/23_containers/tuple/cons/119721.cc
new file mode 100644
index 0000000..1d15238
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/tuple/cons/119721.cc
@@ -0,0 +1,121 @@
+// { dg-do run { target c++23 } }
+
+// Test for PR libstdc++/119721: tuple<> construction/assignment with array<T, 0>
+
+#include <tuple>
+#include <array>
+#include <memory>
+#include <testsuite_hooks.h>
+
+constexpr void
+test01()
+{
+ std::array<int, 0> a{};
+
+ // Constructor from array<int, 0>
+ std::tuple<> t1(a);
+ std::tuple<> t2(std::move(a));
+
+ // Assignment from array<int, 0>
+ std::tuple<> t3;
+ t3 = a;
+ t3 = std::move(a);
+
+ VERIFY( t1 == a );
+ VERIFY( t2 == a );
+ VERIFY( t3 == a );
+}
+
+constexpr void
+test02()
+{
+ // Test with non-comparable element type
+ struct NonComparable
+ {
+ void operator==(const NonComparable&) const = delete;
+ void operator<=>(const NonComparable&) const = delete;
+ };
+
+ std::array<NonComparable, 0> a{};
+
+ std::tuple<> t1(a);
+ std::tuple<> t2(std::move(a));
+
+ std::tuple<> t3;
+ t3 = a;
+ t3 = std::move(a);
+
+ VERIFY( t1 == a );
+}
+
+constexpr void
+test03()
+{
+ // Test assignment return type (non-const assignment)
+ std::tuple<> t, u;
+ std::tuple<>& r1 = (t = u);
+ VERIFY( &r1 == &t );
+
+ std::tuple<>& r2 = (t = {});
+ VERIFY( &r2 == &t );
+
+ std::array<int, 0> a{};
+ std::tuple<>& r3 = (t = a);
+ VERIFY( &r3 == &t );
+}
+
+constexpr void
+test04()
+{
+ std::array<int, 0> a{};
+ const std::tuple<> t1;
+
+ // Const assignment from array
+ std::tuple<> t2;
+ const std::tuple<>& r1 = (t1 = t2);
+ VERIFY( &r1 == &t1 );
+ const std::tuple<>& r2 = (t1 = std::move(t2));
+ VERIFY( &r2 == &t1 );
+
+ const std::tuple<>& r3 = (t1 = {});
+ VERIFY( &r3 == &t1 );
+
+ // Const assignment from array
+ const std::tuple<>& r4 = (t1 = a);
+ VERIFY( &r4 == &t1 );
+ const std::tuple<>& r5 = (t1 = std::move(a));
+ VERIFY( &r5 == &t1 );
+}
+
+void
+test05()
+{
+ std::array<int, 0> a{};
+ std::allocator<int> alloc;
+
+ // Allocator constructor from array
+ std::tuple<> t1(std::allocator_arg, alloc, a);
+ std::tuple<> t2(std::allocator_arg, alloc, std::move(a));
+
+ VERIFY( t1 == a );
+ VERIFY( t2 == a );
+}
+
+int main()
+{
+ auto test_all = [] {
+ test01();
+ test02();
+ test03();
+ test04();
+ return true;
+ };
+
+ test_all();
+ static_assert( test_all() );
+
+ // allocator test is not constexpr
+ test05();
+ return 0;
+}
+
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 36efc2d..cad102e 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
@@ -78,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);
@@ -102,10 +100,10 @@ constexpr bool is_equal(std::equal_to<T>, std::equal_to<U>)
{ return true; }
constexpr bool is_equal(StateHash lhs, StateHash rhs)
-{ return lhs.state = rhs.state; }
+{ return lhs.state == rhs.state; }
constexpr bool is_equal(StateEq lhs, StateEq rhs)
-{ return lhs.state = rhs.state; }
+{ return lhs.state == rhs.state; }
template<typename Range, typename Alloc, typename Hash, typename Equal>
constexpr void
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/const_container.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/const_container.cc
new file mode 100644
index 0000000..e62f158
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_map/const_container.cc
@@ -0,0 +1,19 @@
+// { dg-do compile { target c++11 } }
+
+#include <unordered_map>
+
+#include <testsuite_hooks.h>
+
+// PR c++/116369
+const std::unordered_map<int, int> um
+ {
+ { 0, 1 },
+ { 2, 3 },
+ { 4, 5 }
+ };
+
+int main()
+{
+ VERIFY( um.size() == 3 );
+ VERIFY( um.find(0) != um.end() );
+}
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/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 b551df4..ab30e3c 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
@@ -86,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);
@@ -112,10 +114,10 @@ constexpr bool is_equal(std::equal_to<T>, std::equal_to<U>)
{ return true; }
constexpr bool is_equal(StateHash lhs, StateHash rhs)
-{ return lhs.state = rhs.state; }
+{ return lhs.state == rhs.state; }
constexpr bool is_equal(StateEq lhs, StateEq rhs)
-{ return lhs.state = rhs.state; }
+{ return lhs.state == rhs.state; }
template<typename Range, typename Alloc, typename Hash, typename Equal>
constexpr void
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/const_container.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/const_container.cc
new file mode 100644
index 0000000..3da1e33
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/const_container.cc
@@ -0,0 +1,22 @@
+// { dg-do compile { target c++11 } }
+
+#include <unordered_map>
+
+#include <testsuite_hooks.h>
+
+// PR c++/116369
+const std::unordered_multimap<int, int> umm
+ {
+ { 0, 1 },
+ { 0, 1 },
+ { 2, 3 },
+ { 2, 3 },
+ { 4, 5 },
+ { 4, 5 }
+ };
+
+int main()
+{
+ VERIFY( umm.size() == 6 );
+ VERIFY( umm.find(0) != umm.end() );
+}
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multiset/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 d44598d..ff05471 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
@@ -85,11 +85,11 @@ constexpr bool is_equal(std::equal_to<T>, std::equal_to<U>)
{ return true; }
constexpr bool is_equal(StateHash lhs, StateHash rhs)
-{ return lhs.state = rhs.state; }
+{ return lhs.state == rhs.state; }
constexpr bool is_equal(StateEq lhs, StateEq rhs)
-{ return lhs.state = rhs.state; }
+{ return lhs.state == rhs.state; }
template<typename Range, typename Alloc, typename Hash, typename Equal>
constexpr void
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multiset/const_container.cc b/libstdc++-v3/testsuite/23_containers/unordered_multiset/const_container.cc
new file mode 100644
index 0000000..841d25a
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multiset/const_container.cc
@@ -0,0 +1,15 @@
+// { dg-do compile { target c++11 } }
+
+#include <unordered_set>
+
+#include <testsuite_hooks.h>
+
+// PR c++/116369
+const std::unordered_multiset<int> ums
+ { 0, 0, 1, 1, 2, 2 };
+
+int main()
+{
+ VERIFY( ums.size() == 6 );
+ VERIFY( ums.find(0) != ums.end() );
+}
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/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 8259be8..e00e2fb 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
@@ -84,11 +84,11 @@ constexpr bool is_equal(std::equal_to<T>, std::equal_to<U>)
{ return true; }
constexpr bool is_equal(StateHash lhs, StateHash rhs)
-{ return lhs.state = rhs.state; }
+{ return lhs.state == rhs.state; }
constexpr bool is_equal(StateEq lhs, StateEq rhs)
-{ return lhs.state = rhs.state; }
+{ return lhs.state == rhs.state; }
template<typename Range, typename Alloc, typename Hash, typename Equal>
constexpr void
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/const_container.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/const_container.cc
new file mode 100644
index 0000000..ffdbbad
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_set/const_container.cc
@@ -0,0 +1,14 @@
+// { dg-do compile { target c++11 } }
+
+#include <unordered_set>
+
+#include <testsuite_hooks.h>
+
+// PR c++/116369
+const std::unordered_set<int> us { 0, 1, 2 };
+
+int main()
+{
+ VERIFY( us.size() == 3 );
+ VERIFY( us.find(0) != us.end() );
+}
diff --git a/libstdc++-v3/testsuite/23_containers/vector/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 339c06bd..516d888 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
@@ -42,14 +42,16 @@ do_test(Alloc alloc)
}
template<typename Range>
-void
+constexpr void
do_test_a()
{
do_test<Range>(std::allocator<bool>());
- do_test<Range>(__gnu_test::uneq_allocator<bool>(42));
+ if not consteval {
+ do_test<Range>(__gnu_test::uneq_allocator<bool>(42));
+ }
}
-bool
+constexpr bool
test_ranges()
{
using namespace __gnu_test;
@@ -71,9 +73,9 @@ test_ranges()
// Not lvalue-convertible to bool
struct C {
- C(bool v) : val(v) { }
- operator bool() && { return val; }
- bool operator==(bool b) const { return b == val; }
+ constexpr C(bool v) : val(v) { }
+ constexpr operator bool() && { return val; }
+ constexpr bool operator==(bool b) const { return b == val; }
bool val;
};
using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>;
@@ -82,16 +84,8 @@ test_ranges()
return true;
}
-constexpr bool
-test_constexpr()
-{
- // XXX: this doesn't test the non-forward_range code paths are constexpr.
- do_test<std::span<bool>>(std::allocator<bool>());
- return true;
-}
-
int main()
{
test_ranges();
- static_assert( test_constexpr() );
+ static_assert( test_ranges() );
}
diff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/format.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/format.cc
index eb24b66..833727f 100644
--- a/libstdc++-v3/testsuite/23_containers/vector/bool/format.cc
+++ b/libstdc++-v3/testsuite/23_containers/vector/bool/format.cc
@@ -7,6 +7,7 @@
static_assert(!std::formattable<std::vector<bool>::reference, int>);
static_assert(!std::formattable<std::vector<bool>::reference, char32_t>);
+static_assert(std::enable_nonlocking_formatter_optimization<std::vector<bool>::reference>);
template<typename... Args>
bool
@@ -21,7 +22,7 @@ is_format_string_for(const char* str, Args&&... args)
}
#define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S)
-#define WIDEN(S) WIDEN_(_CharT, S)
+#define WIDEN(S) WIDEN_(CharT, S)
void
test_format_string()
@@ -34,11 +35,11 @@ test_format_string()
VERIFY( !is_format_string_for("{:{}}", v[0], 1.0f) );
}
-template<typename _CharT>
+template<typename CharT>
void
test_output()
{
- std::basic_string<_CharT> res;
+ std::basic_string<CharT> res;
size_t size = 0;
std::vector<bool> v{true, false};
diff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/assign/assign_range.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/assign/assign_range.cc
index 7e58700..ced7efe 100644
--- a/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/assign/assign_range.cc
+++ b/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/assign/assign_range.cc
@@ -59,14 +59,14 @@ do_test()
}
template<typename Range>
-void
+constexpr void
do_test_a()
{
do_test<Range, std::allocator<bool>>();
do_test<Range, __gnu_test::SimpleAllocator<bool>>();
}
-bool
+constexpr bool
test_ranges()
{
using namespace __gnu_test;
@@ -88,9 +88,9 @@ test_ranges()
// Not lvalue-convertible to bool
struct C {
- C(bool v) : val(v) { }
- operator bool() && { return val; }
- bool operator==(bool b) const { return b == val; }
+ constexpr C(bool v) : val(v) { }
+ constexpr operator bool() && { return val; }
+ constexpr bool operator==(bool b) const { return b == val; }
bool val;
};
using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>;
@@ -99,16 +99,8 @@ test_ranges()
return true;
}
-constexpr bool
-test_constexpr()
-{
- // XXX: this doesn't test the non-forward_range code paths are constexpr.
- do_test<std::span<short>, std::allocator<bool>>();
- return true;
-}
-
int main()
{
test_ranges();
- static_assert( test_constexpr() );
+ static_assert( test_ranges() );
}
diff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/insert/append_range.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/insert/append_range.cc
index 43a698f..c2e2186 100644
--- a/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/insert/append_range.cc
+++ b/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/insert/append_range.cc
@@ -38,14 +38,14 @@ do_test()
}
template<typename Range>
-void
+constexpr void
do_test_a()
{
do_test<Range, std::allocator<bool>>();
do_test<Range, __gnu_test::SimpleAllocator<bool>>();
}
-bool
+constexpr bool
test_ranges()
{
using namespace __gnu_test;
@@ -67,9 +67,9 @@ test_ranges()
// Not lvalue-convertible to bool
struct C {
- C(bool v) : val(v) { }
- operator bool() && { return val; }
- bool operator==(bool b) const { return b == val; }
+ constexpr C(bool v) : val(v) { }
+ constexpr operator bool() && { return val; }
+ constexpr bool operator==(bool b) const { return b == val; }
bool val;
};
using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>;
@@ -81,8 +81,7 @@ test_ranges()
constexpr bool
test_constexpr()
{
- // XXX: this doesn't test the non-forward_range code paths are constexpr.
- do_test<std::span<short>, std::allocator<bool>>();
+ test_ranges();
// Some basic tests for overlapping ranges in constant expressions.
using I = std::vector<bool>::iterator;
diff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/insert/insert_range.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/insert/insert_range.cc
index 5c65610..2ec91b0 100644
--- a/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/insert/insert_range.cc
+++ b/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/insert/insert_range.cc
@@ -55,14 +55,14 @@ do_test()
}
template<typename Range>
-void
+constexpr void
do_test_a()
{
do_test<Range, std::allocator<bool>>();
do_test<Range, __gnu_test::SimpleAllocator<bool>>();
}
-bool
+constexpr bool
test_ranges()
{
using namespace __gnu_test;
@@ -84,9 +84,9 @@ test_ranges()
// Not lvalue-convertible to bool
struct C {
- C(bool v) : val(v) { }
- operator bool() && { return val; }
- bool operator==(bool b) const { return b == val; }
+ constexpr C(bool v) : val(v) { }
+ constexpr operator bool() && { return val; }
+ constexpr bool operator==(bool b) const { return b == val; }
bool val;
};
using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>;
@@ -95,16 +95,8 @@ test_ranges()
return true;
}
-constexpr bool
-test_constexpr()
-{
- // XXX: this doesn't test the non-forward_range code paths are constexpr.
- do_test<std::span<bool>, std::allocator<bool>>();
- return true;
-}
-
int main()
{
test_ranges();
- static_assert( test_constexpr() );
+ static_assert( test_ranges() );
}
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 7a62645..be3e699 100644
--- a/libstdc++-v3/testsuite/23_containers/vector/cons/from_range.cc
+++ b/libstdc++-v3/testsuite/23_containers/vector/cons/from_range.cc
@@ -58,14 +58,16 @@ do_test(Alloc alloc)
}
template<typename Range>
-void
+constexpr void
do_test_a()
{
do_test<Range>(std::allocator<int>());
- do_test<Range>(__gnu_test::uneq_allocator<int>(42));
+ if not consteval {
+ do_test<Range>(__gnu_test::uneq_allocator<int>(42));
+ }
}
-bool
+constexpr bool
test_ranges()
{
using namespace __gnu_test;
@@ -87,9 +89,9 @@ test_ranges()
// Not lvalue-convertible to int
struct C {
- C(int v) : val(v) { }
- operator int() && { return val; }
- bool operator==(int b) const { return b == val; }
+ constexpr C(int v) : val(v) { }
+ constexpr operator int() && { return val; }
+ constexpr bool operator==(int b) const { return b == val; }
int val;
};
using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>;
@@ -98,16 +100,30 @@ test_ranges()
return true;
}
-constexpr bool
-test_constexpr()
+void
+test_pr120367()
{
- // XXX: this doesn't test the non-forward_range code paths are constexpr.
- do_test<std::span<short>>(std::allocator<int>());
- return true;
+#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() );
+ static_assert( test_ranges() );
+ test_pr120367();
}
diff --git a/libstdc++-v3/testsuite/23_containers/vector/debug/erase.cc b/libstdc++-v3/testsuite/23_containers/vector/debug/erase.cc
new file mode 100644
index 0000000..d2b412d
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/vector/debug/erase.cc
@@ -0,0 +1,27 @@
+// { dg-do run { target c++20 } }
+// { dg-require-debug-mode "" }
+
+#include <vector>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+ std::vector<int> v;
+
+ for (int i = 0; i != 10; ++i)
+ v.push_back(i);
+
+ auto before = v.begin() + 4;
+ auto last = v.end() - 1;
+
+ VERIFY( std::erase(v, 6) == 1 );
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(last._M_singular());
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/vector/debug/invalidation/erase.cc b/libstdc++-v3/testsuite/23_containers/vector/debug/invalidation/erase.cc
new file mode 100644
index 0000000..38326a7
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/vector/debug/invalidation/erase.cc
@@ -0,0 +1,28 @@
+// { dg-do run { target c++20 } }
+
+#include <debug/vector>
+#include <testsuite_hooks.h>
+
+using __gnu_debug::vector;
+
+void test01()
+{
+ vector<int> v;
+
+ for (int i = 0; i != 10; ++i)
+ v.push_back(i);
+
+ auto before = v.begin() + 4;
+ auto last = v.end() -1;
+
+ VERIFY( std::erase(v, 6) == 1 );
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(last._M_singular());
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/vector/debug/mutex_association.cc b/libstdc++-v3/testsuite/23_containers/vector/debug/mutex_association.cc
index ba2ede0..792ed45 100644
--- a/libstdc++-v3/testsuite/23_containers/vector/debug/mutex_association.cc
+++ b/libstdc++-v3/testsuite/23_containers/vector/debug/mutex_association.cc
@@ -25,7 +25,7 @@ class container : public __gnu_debug::_Safe_sequence<container>
{
public:
__gnu_cxx::__mutex&
- get_mutex()
+ get_mutex() const
{ return this->_M_get_mutex(); }
};
diff --git a/libstdc++-v3/testsuite/23_containers/vector/modifiers/append_range.cc b/libstdc++-v3/testsuite/23_containers/vector/modifiers/append_range.cc
index be097e2..f5b21df 100644
--- a/libstdc++-v3/testsuite/23_containers/vector/modifiers/append_range.cc
+++ b/libstdc++-v3/testsuite/23_containers/vector/modifiers/append_range.cc
@@ -42,14 +42,14 @@ do_test()
}
template<typename Range>
-void
+constexpr void
do_test_a()
{
do_test<Range, std::allocator<int>>();
do_test<Range, __gnu_test::SimpleAllocator<int>>();
}
-bool
+constexpr bool
test_ranges()
{
using namespace __gnu_test;
@@ -71,9 +71,9 @@ test_ranges()
// Not lvalue-convertible to int
struct C {
- C(int v) : val(v) { }
- operator int() && { return val; }
- bool operator==(int b) const { return b == val; }
+ constexpr C(int v) : val(v) { }
+ constexpr operator int() && { return val; }
+ constexpr bool operator==(int b) const { return b == val; }
int val;
};
using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>;
@@ -82,7 +82,7 @@ test_ranges()
return true;
}
-void
+constexpr void
test_overlapping()
{
using __gnu_test::test_input_range;
@@ -199,64 +199,14 @@ test_overlapping()
}
}
-constexpr bool
-test_constexpr()
+int main()
{
- // XXX: this doesn't test the non-forward_range code paths are constexpr.
- do_test<std::span<short>, std::allocator<int>>();
-
- // Some basic tests for overlapping ranges in constant expressions.
- struct InputRange
- {
- struct Sent { const void* end; };
-
- struct Iter
- {
- using value_type = int;
- using difference_type = int;
- constexpr explicit Iter(int* p) : ptr(p) { }
- constexpr Iter& operator++() { ++ptr; return *this; }
- constexpr Iter operator++(int) { auto i = *this; ++ptr; return i; }
- constexpr int operator*() const { return *ptr; }
- constexpr bool operator==(const Iter&) const = default;
- constexpr bool operator==(const Sent& s) const { return ptr == s.end; }
- int* ptr;
- };
-
- Iter iter;
- Sent sent;
-
- constexpr InputRange(int* f, int* l) : iter{f}, sent{l} { }
- constexpr Iter begin() const { return iter; }
- constexpr Sent end() const { return sent; }
+ auto test_all = [] {
+ test_ranges();
+ test_overlapping();
+ return true;
};
- static_assert( std::ranges::input_range<InputRange> );
- static_assert( ! std::ranges::forward_range<InputRange> );
-
- std::vector<int> vec(5);
-
- // Test overlapping input ranges
- vec.resize(vec.capacity());
- vec.append_range(InputRange(vec.data(), vec.data() + 3)); // no capacity
- vec.reserve(vec.capacity() + 2);
- vec.append_range(InputRange(vec.data(), vec.data() + 4)); // some capacity
- vec.reserve(vec.capacity() + 6);
- vec.append_range(InputRange(vec.data(), vec.data() + 5)); // enough capacity
-
- // Test overlapping forward ranges
- vec.resize(vec.capacity());
- vec.append_range(std::span<int>(vec)); // no capacity
- vec.reserve(vec.size() + 2);
- vec.append_range(std::span<int>(vec).subspan(1, 4)); // some capacity
- vec.reserve(vec.size() + 6);
- vec.append_range(std::span<int>(vec).subspan(1, 5)); // enough capacity
- return true;
-}
-
-int main()
-{
- test_ranges();
- test_overlapping();
- static_assert( test_constexpr() );
+ test_all();
+ static_assert( test_all() );
}
diff --git a/libstdc++-v3/testsuite/23_containers/vector/modifiers/assign/assign_range.cc b/libstdc++-v3/testsuite/23_containers/vector/modifiers/assign/assign_range.cc
index db3b06c..26d33bc 100644
--- a/libstdc++-v3/testsuite/23_containers/vector/modifiers/assign/assign_range.cc
+++ b/libstdc++-v3/testsuite/23_containers/vector/modifiers/assign/assign_range.cc
@@ -63,14 +63,14 @@ do_test()
}
template<typename Range>
-void
+constexpr void
do_test_a()
{
do_test<Range, std::allocator<int>>();
do_test<Range, __gnu_test::SimpleAllocator<int>>();
}
-bool
+constexpr bool
test_ranges()
{
using namespace __gnu_test;
@@ -92,9 +92,9 @@ test_ranges()
// Not lvalue-convertible to int
struct C {
- C(int v) : val(v) { }
- operator int() && { return val; }
- bool operator==(int b) const { return b == val; }
+ constexpr C(int v) : val(v) { }
+ constexpr operator int() && { return val; }
+ constexpr bool operator==(int b) const { return b == val; }
int val;
};
using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>;
@@ -103,16 +103,8 @@ test_ranges()
return true;
}
-constexpr bool
-test_constexpr()
-{
- // XXX: this doesn't test the non-forward_range code paths are constexpr.
- do_test<std::span<short>, std::allocator<int>>();
- return true;
-}
-
int main()
{
test_ranges();
- static_assert( test_constexpr() );
+ static_assert( test_ranges() );
}
diff --git a/libstdc++-v3/testsuite/23_containers/vector/modifiers/insert/insert_range.cc b/libstdc++-v3/testsuite/23_containers/vector/modifiers/insert/insert_range.cc
index 5907143..e4b5982 100644
--- a/libstdc++-v3/testsuite/23_containers/vector/modifiers/insert/insert_range.cc
+++ b/libstdc++-v3/testsuite/23_containers/vector/modifiers/insert/insert_range.cc
@@ -59,14 +59,14 @@ do_test()
}
template<typename Range>
-void
+constexpr void
do_test_a()
{
do_test<Range, std::allocator<int>>();
do_test<Range, __gnu_test::SimpleAllocator<int>>();
}
-bool
+constexpr bool
test_ranges()
{
using namespace __gnu_test;
@@ -88,9 +88,9 @@ test_ranges()
// Not lvalue-convertible to int
struct C {
- C(int v) : val(v) { }
- operator int() && { return val; }
- bool operator==(int b) const { return b == val; }
+ constexpr C(int v) : val(v) { }
+ constexpr operator int() && { return val; }
+ constexpr bool operator==(int b) const { return b == val; }
int val;
};
using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>;
@@ -99,16 +99,58 @@ test_ranges()
return true;
}
-constexpr bool
-test_constexpr()
+struct SelfAssignChecker {
+ static int moveCounter;
+ static int copyCounter;
+
+ SelfAssignChecker() = default;
+ constexpr SelfAssignChecker(int v) : val(v) { }
+ SelfAssignChecker(const SelfAssignChecker&) = default;
+ SelfAssignChecker(SelfAssignChecker&&) = default;
+
+ SelfAssignChecker operator=(const SelfAssignChecker& rhs)
+ {
+ if (this == &rhs)
+ ++copyCounter;
+ this->val = rhs.val;
+ return *this;
+ }
+
+ SelfAssignChecker operator=(SelfAssignChecker&& rhs)
+ {
+ if (this == &rhs)
+ ++moveCounter;
+ this->val = rhs.val;
+ return *this;
+ }
+
+ int val;
+
+ friend bool operator==(SelfAssignChecker, SelfAssignChecker) = default;
+};
+
+int SelfAssignChecker::moveCounter = 0;
+int SelfAssignChecker::copyCounter = 0;
+
+void
+test_pr121313()
{
- // XXX: this doesn't test the non-forward_range code paths are constexpr.
- do_test<std::span<short>, std::allocator<int>>();
- return true;
+ using namespace __gnu_test;
+
+ SelfAssignChecker::copyCounter = SelfAssignChecker::moveCounter = 0;
+ do_test<test_forward_range<int>, std::allocator<SelfAssignChecker>>();
+ VERIFY( SelfAssignChecker::moveCounter == 0 );
+ VERIFY( SelfAssignChecker::copyCounter == 0 );
+
+ SelfAssignChecker::copyCounter = SelfAssignChecker::moveCounter = 0;
+ do_test<test_input_range<int>, std::allocator<SelfAssignChecker>>();
+ VERIFY( SelfAssignChecker::moveCounter == 0 );
+ VERIFY( SelfAssignChecker::copyCounter == 0 );
}
int main()
{
test_ranges();
- static_assert( test_constexpr() );
+ test_pr121313();
+ static_assert( test_ranges() );
}
diff --git a/libstdc++-v3/testsuite/23_containers/vector/modifiers/moveable.cc b/libstdc++-v3/testsuite/23_containers/vector/modifiers/moveable.cc
index 8d0f9ae..343a298 100644
--- a/libstdc++-v3/testsuite/23_containers/vector/modifiers/moveable.cc
+++ b/libstdc++-v3/testsuite/23_containers/vector/modifiers/moveable.cc
@@ -109,9 +109,11 @@ test05()
// when it doesn't reallocate the buffer.
VERIFY(copycounter::copycount == 20 + 1);
a.insert(a.end(), 50, c);
- VERIFY(copycounter::copycount == 70 + 2);
+ // expect when inserting at the end (appending), where existing
+ // elements are not modified
+ VERIFY(copycounter::copycount == 70 + 1);
a.insert(a.begin() + 50, 100, c);
- VERIFY(copycounter::copycount == 170 + 3);
+ VERIFY(copycounter::copycount == 170 + 2);
}
diff --git a/libstdc++-v3/testsuite/23_containers/vector/modifiers/resize.cc b/libstdc++-v3/testsuite/23_containers/vector/modifiers/resize.cc
new file mode 100644
index 0000000..026b0f7
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/vector/modifiers/resize.cc
@@ -0,0 +1,69 @@
+// { dg-do run }
+
+#include <vector>
+#include <testsuite_hooks.h>
+
+struct NoAssign
+{
+ NoAssign(int p) : val(p) {}
+ const int val;
+};
+
+struct PrivateAssign
+{
+ PrivateAssign(int p) : val(p) {}
+ PrivateAssign(const PrivateAssign& rhs) : val(rhs.val) {}
+
+ int val;
+
+private:
+ PrivateAssign& operator=(const PrivateAssign&);
+};
+
+#if __cplusplus >= 201102L
+struct DeletedAssign
+{
+ DeletedAssign(int p) : val(p) {}
+ DeletedAssign(const DeletedAssign& rhs) : val(rhs.val) {}
+
+ DeletedAssign& operator=(const DeletedAssign&) = delete;
+
+ int val;
+};
+#endif
+
+template<typename T>
+void
+testPR90129()
+{
+ std::vector<T> v;
+ v.resize(5, T(5));
+ VERIFY( v.size() == 5 );
+ VERIFY( v.front().val == 5 );
+ VERIFY( v.back().val == 5 );
+
+ v.resize(10, T(10));
+ VERIFY( v.size() == 10 );
+ VERIFY( v.front().val == 5 );
+ VERIFY( v.back().val == 10 );
+
+ v.resize(7, T(7));
+ VERIFY( v.size() == 7 );
+ VERIFY( v.front().val == 5 );
+ VERIFY( v.back().val == 10 );
+
+ v.resize(3, T(3));
+ VERIFY( v.size() == 3 );
+ VERIFY( v.front().val == 5 );
+ VERIFY( v.back().val == 5 );
+}
+
+int main()
+{
+ testPR90129<NoAssign>();
+ testPR90129<PrivateAssign>();
+#if __cplusplus >= 201102L
+ testPR90129<DeletedAssign>();
+#endif
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/24_iterators/const_iterator/1.cc b/libstdc++-v3/testsuite/24_iterators/const_iterator/1.cc
index fe952bf..f2bcad4 100644
--- a/libstdc++-v3/testsuite/24_iterators/const_iterator/1.cc
+++ b/libstdc++-v3/testsuite/24_iterators/const_iterator/1.cc
@@ -42,12 +42,13 @@ test01()
}
}
-template<class Range, bool Const>
+template<class Range, bool Const, bool Constable = Const>
void
test02()
{
if constexpr (Const)
{
+ static_assert(Constable);
static_assert( ranges::constant_range<Range> );
static_assert( std::same_as<ranges::const_iterator_t<Range>, ranges::iterator_t<Range>> );
static_assert( std::same_as<ranges::const_sentinel_t<Range>, ranges::sentinel_t<Range>> );
@@ -64,9 +65,21 @@ test02()
static_assert( !ranges::constant_range<Range> );
using Wrapped = std::basic_const_iterator<ranges::iterator_t<Range>>;
- static_assert( std::same_as<ranges::const_iterator_t<Range>, Wrapped> );
- if constexpr (ranges::common_range<Range>)
- static_assert( std::same_as<ranges::const_sentinel_t<Range>, Wrapped> );
+ if constexpr (Constable)
+ {
+ // Verify LWG 3946 changes to const_iterator/sentinel_t (PR122842).
+ static_assert( std::same_as<ranges::const_iterator_t<Range>,
+ ranges::iterator_t<const Range>> );
+ static_assert( std::same_as<ranges::const_sentinel_t<Range>,
+ ranges::sentinel_t<const Range>> );
+ }
+ else
+ {
+ static_assert( std::same_as<ranges::const_iterator_t<Range>, Wrapped> );
+ if constexpr (ranges::common_range<Range>)
+ static_assert( std::same_as<ranges::const_sentinel_t<Range>, Wrapped> );
+ }
+
static_assert( std::same_as<ranges::range_const_reference_t<Range>,
std::iter_reference_t<Wrapped>> );
@@ -138,13 +151,14 @@ main()
test01<std::string_view::iterator, true>();
test01<std::vector<bool>::const_iterator, true>();
- test02<int[42], false>();
+ test02<int[42], false, true>();
test02<test_input_range<int>, false>();
test02<test_forward_range<int>, false>();
test02<test_bidirectional_range<int>, false>();
test02<test_random_access_range<int>, false>();
- test02<std::array<int, 3>, false>();
- test02<std::vector<bool>, false>();
+ test02<std::array<int, 3>, false, true>();
+ test02<std::vector<bool>, false, true>();
+ test02<std::string, false, true>();
test02<const int[42], true>();
test02<test_input_range<const int>, true>();
@@ -155,6 +169,7 @@ main()
test02<const std::array<int, 3>, true>();
test02<std::string_view, true>();
test02<const std::vector<bool>, true>();
+ test02<const std::string, true>();
test03();
test04();
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/cxx20_iterators.cc b/libstdc++-v3/testsuite/24_iterators/operations/cxx20_iterators.cc
new file mode 100644
index 0000000..b613c37
--- /dev/null
+++ b/libstdc++-v3/testsuite/24_iterators/operations/cxx20_iterators.cc
@@ -0,0 +1,60 @@
+// { dg-do run { target c++20 } }
+
+#include <ranges>
+#include <testsuite_iterators.h>
+#include <testsuite_hooks.h>
+
+// Bug 102181 std::advance and std::views::iota<std::int64_t> don't work
+void
+test_pr102181()
+{
+#ifdef __SIZEOF_INT128__
+ using type = unsigned __int128;
+#else
+ using type = unsigned long;
+#endif
+ auto v = std::ranges::iota_view(type(0), type(10));
+ auto b = v.begin();
+ VERIFY( std::distance(b, std::next(b)) == 1 );
+ std::advance(b, std::iter_difference_t<decltype(b)>(1));
+ VERIFY( *b == 1 );
+ VERIFY( std::distance(b, v.end()) == 9 );
+}
+
+// https://stackoverflow.com/questions/68100775/rangesviewtransform-produces-an-inputiterator-preventing-the-use-of-stdpre
+void
+test_transform_view_iterator()
+{
+ int a[] = {0, 1, 2, 3};
+ __gnu_test::random_access_container<int> rr(a);
+ auto rx = std::ranges::views::transform(rr, std::identity{});
+ auto re = rx.end();
+ VERIFY( *std::prev(re) == 3 );
+ VERIFY( std::distance(rx.begin(), re) == 4 );
+
+ __gnu_test::bidirectional_container<int> br(a);
+ auto bx = std::ranges::views::transform(br, std::identity{});
+ auto be = bx.end();
+ VERIFY( *std::prev(be) == 3 );
+ VERIFY( std::distance(bx.begin(), be) == 4 );
+
+ __gnu_test::forward_container<int> fr(a);
+ auto fx = std::ranges::views::transform(br, std::identity{});
+ auto fb = fx.begin();
+ VERIFY( *std::next(fb) == 1 );
+ VERIFY( std::distance(fb, fx.end()) == 4 );
+
+ __gnu_test::test_input_range<int> ir(a);
+ auto ix = std::ranges::views::transform(ir, std::identity{});
+ auto ii = ix.begin();
+ std::advance(ii, 1);
+ VERIFY( *ii == 1 );
+ // N.B. cannot use std::distance or std::next here because there is no
+ // iterator_traits<decltype(ii)>::difference_type for this iterator.
+}
+
+int main()
+{
+ test_pr102181();
+ test_transform_view_iterator();
+}
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/random_access/string_vector_iterators.cc b/libstdc++-v3/testsuite/24_iterators/random_access/string_vector_iterators.cc
index a8dbe51..d6b95d6 100644
--- a/libstdc++-v3/testsuite/24_iterators/random_access/string_vector_iterators.cc
+++ b/libstdc++-v3/testsuite/24_iterators/random_access/string_vector_iterators.cc
@@ -17,238 +17,162 @@
// along with this program; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
-
#include <string>
#include <vector>
#include <testsuite_hooks.h>
-int
+void
string_stuff()
{
- int failures(0);
-
std::string s("abcde");
std::string::iterator i1(s.begin());
- if (*i1 != 'a')
- ++failures;
+ VERIFY( *i1 == 'a' );
++i1;
- if (*i1 != 'b')
- ++failures;
+ VERIFY( *i1 == 'b' );
- if (*i1++ != 'b')
- ++failures;
- if (*i1 != 'c')
- ++failures;
+ VERIFY( *i1++ == 'b' );
+ VERIFY( *i1 == 'c' );
++ ++i1;
- if (*i1 != 'e')
- ++failures;
+ VERIFY( *i1 == 'e' );
--i1;
- if (*i1 != 'd')
- ++failures;
+ VERIFY( *i1 == 'd' );
- if (*i1-- != 'd')
- ++failures;
- if (*i1 != 'c')
- ++failures;
+ VERIFY( *i1-- == 'd' );
+ VERIFY( *i1 == 'c' );
-- --i1;
- if (*i1 != 'a')
- ++failures;
+ VERIFY( *i1 == 'a' );
std::string::iterator i2;
i2 = s.end();
std::iterator_traits<std::string::iterator>::difference_type d1;
d1 = i2 - i1;
- if (d1 != 5)
- ++failures;
+ VERIFY( d1 == 5 );
std::iterator_traits<std::string::iterator>::value_type v1;
v1 = i1[0];
- if (v1 != 'a')
- ++failures;
+ VERIFY( v1 == 'a' );
std::iterator_traits<std::string::iterator>::reference r1(i1[0]);
- if (r1 != 'a')
- ++failures;
+ VERIFY( r1 == 'a' );
r1 = 'x';
- if (r1 != 'x')
- ++failures;
+ VERIFY( r1 == 'x' );
r1 = 'a';
- if ((i1 != i2) != true)
- ++failures;
- if ((i1 == i2) != false)
- ++failures;
- if ((i1 < i2) != true)
- ++failures;
- if ((i1 > i2) != false)
- ++failures;
- if ((i1 <= i2) != true)
- ++failures;
- if ((i1 >= i2) != false)
- ++failures;
+ VERIFY( (i1 != i2) == true );
+ VERIFY( (i1 == i2) == false );
+ VERIFY( (i1 < i2) == true );
+ VERIFY( (i1 > i2) == false );
+ VERIFY( (i1 <= i2) == true );
+ VERIFY( (i1 >= i2) == false );
std::string::iterator i3;
i3 = i1;
- if ((i3 == i1) != true)
- ++failures;
+ VERIFY( (i3 == i1) == true );
i3 += 5;
- if ((i3 == i2) != true)
- ++failures;
+ VERIFY( (i3 == i2) == true );
i3 -= 5;
- if ((i3 == i1) != true)
- ++failures;
-
- if (i3 + 5 != i2)
- ++failures;
-
- if (5 + i3 != i2)
- ++failures;
+ VERIFY( (i3 == i1) == true );
- if (i2 - 5 != i3)
- ++failures;
+ VERIFY( i3 + 5 == i2 );
+ VERIFY( 5 + i3 == i2 );
+ VERIFY( i2 - 5 == i3 );
- if (i1[0] != 'a')
- ++failures;
+ VERIFY( i1[0] == 'a' );
i1[4] = 'x';
- if (i2[-1] != 'x')
- ++failures;
+ VERIFY( i2[-1] == 'x' );
i1[4] = 'e';
i1[2] = 'x';
- if (i2[-3] != 'x')
- ++failures;
+ VERIFY( i2[-3] == 'x' );
i1[2] = 'c';
std::string::const_iterator ci1(s.begin());
- if (*ci1 != 'a')
- ++failures;
+ VERIFY( *ci1 == 'a' );
++ci1;
- if (*ci1 != 'b')
- ++failures;
+ VERIFY( *ci1 == 'b' );
- if (*ci1++ != 'b')
- ++failures;
- if (*ci1 != 'c')
- ++failures;
+ VERIFY( *ci1++ == 'b' );
+ VERIFY( *ci1 == 'c' );
++ ++ci1;
- if (*ci1 != 'e')
- ++failures;
+ VERIFY( *ci1 == 'e' );
--ci1;
- if (*ci1 != 'd')
- ++failures;
+ VERIFY( *ci1 == 'd' );
- if (*ci1-- != 'd')
- ++failures;
- if (*ci1 != 'c')
- ++failures;
+ VERIFY( *ci1-- == 'd' );
+ VERIFY( *ci1 == 'c' );
-- --ci1;
- if (*ci1 != 'a')
- ++failures;
+ VERIFY( *ci1 == 'a' );
std::string::const_iterator ci2;
ci2 = s.end();
std::iterator_traits<std::string::const_iterator>::difference_type d2;
d2 = ci2 - ci1;
- if (d2 != 5)
- ++failures;
+ VERIFY( d2 == 5 );
std::iterator_traits<std::string::const_iterator>::value_type v2;
v2 = ci1[0];
- if (v2 != 'a')
- ++failures;
+ VERIFY( v2 == 'a' );
std::iterator_traits<std::string::const_iterator>::reference r2(ci1[0]);
- if (r2 != 'a')
- ++failures;
-
- if ((ci1 != ci2) != true)
- ++failures;
- if ((ci1 == ci2) != false)
- ++failures;
- if ((ci1 < ci2) != true)
- ++failures;
- if ((ci1 > ci2) != false)
- ++failures;
- if ((ci1 <= ci2) != true)
- ++failures;
- if ((ci1 >= ci2) != false)
- ++failures;
+ VERIFY( r2 == 'a' );
+
+ VERIFY( (ci1 != ci2) == true );
+ VERIFY( (ci1 == ci2) == false );
+ VERIFY( (ci1 < ci2) == true );
+ VERIFY( (ci1 > ci2) == false );
+ VERIFY( (ci1 <= ci2) == true );
+ VERIFY( (ci1 >= ci2) == false );
std::string::const_iterator ci3;
ci3 = ci1;
- if ((ci3 == ci1) != true)
- ++failures;
+ VERIFY( ci3 == ci1 );
ci3 += 5;
- if ((ci3 == ci2) != true)
- ++failures;
+ VERIFY( ci3 == ci2 );
ci3 -= 5;
- if ((ci3 == ci1) != true)
- ++failures;
-
- if (ci3 + 5 != ci2)
- ++failures;
-
- if (5 + ci3 != ci2)
- ++failures;
-
- if (ci2 - 5 != ci3)
- ++failures;
+ VERIFY( ci3 == ci1 );
- if (ci1[2] != 'c')
- ++failures;
+ VERIFY( ci3 + 5 == ci2 );
+ VERIFY( 5 + ci3 == ci2 );
+ VERIFY( ci2 - 5 == ci3 );
- if (ci2[-1] != 'e')
- ++failures;
+ VERIFY( ci1[2] == 'c' );
+ VERIFY( ci2[-1] == 'e' );
// iterator and const_iterator
std::string::const_iterator ci4(i1);
- if ((ci4 == i1) != true)
- ++failures;
- if ((ci4 != i1) != false)
- ++failures;
- if ((ci4 < i1) != false)
- ++failures;
- if ((ci4 > i1) != false)
- ++failures;
- if ((ci4 <= i1) != true)
- ++failures;
- if ((ci4 >= i1) != true)
- ++failures;
+ VERIFY( (ci4 == i1) == true );
+ VERIFY( (ci4 != i1) == false );
+ VERIFY( (ci4 < i1) == false );
+ VERIFY( (ci4 > i1) == false );
+ VERIFY( (ci4 <= i1) == true );
+ VERIFY( (ci4 >= i1) == true );
ci4 = i2;
- if ((i2 == ci4) != true)
- ++failures;
- if ((i2 < ci4) != false)
- ++failures;
- if ((i2 > ci4) != false)
- ++failures;
- if ((i2 <= ci4) != true)
- ++failures;
- if ((i2 >= ci4) != true)
- ++failures;
+ VERIFY( (i2 == ci4) == true );
+ VERIFY( (i2 < ci4) == false );
+ VERIFY( (i2 > ci4) == false );
+ VERIFY( (i2 <= ci4) == true );
+ VERIFY( (i2 >= ci4) == true );
const std::string cs("ABCDE");
std::string::const_iterator ci5(cs.begin());
- if (ci5[0] != 'A')
- ++failures;
-
- return failures;
+ VERIFY( ci5[0] == 'A' );
}
-int
+void
vector_stuff()
{
int failures(0);
@@ -261,347 +185,191 @@ vector_stuff()
v.push_back(int(5));
std::vector<int>::iterator i1(v.begin());
- if (*i1 != 1)
- ++failures;
+ VERIFY( *i1 == 1 );
++i1;
- if (*i1 != 2)
- ++failures;
+ VERIFY( *i1 == 2 );
- if (*i1++ != 2)
- ++failures;
- if (*i1 != 3)
- ++failures;
+ VERIFY( *i1++ == 2 );
+ VERIFY( *i1 == 3 );
++ ++i1;
- if (*i1 != 5)
- ++failures;
+ VERIFY( *i1 == 5 );
--i1;
- if (*i1 != 4)
- ++failures;
+ VERIFY( *i1 == 4 );
- if (*i1-- != 4)
- ++failures;
- if (*i1 != 3)
- ++failures;
+ VERIFY( *i1-- == 4 );
+ VERIFY( *i1 == 3 );
-- --i1;
- if (*i1 != 1)
- ++failures;
+ VERIFY( *i1 == 1 );
std::vector<int>::iterator i2;
i2 = v.end();
std::iterator_traits<std::vector<int>::iterator>::difference_type d1;
d1 = i2 - i1;
- if (d1 != 5)
- ++failures;
+ VERIFY( d1 == 5 );
std::iterator_traits<std::vector<int>::iterator>::value_type v1;
v1 = i1[0];
- if (v1 != 1)
- ++failures;
+ VERIFY( v1 == 1 );
std::iterator_traits<std::vector<int>::iterator>::reference r1(i1[0]);
- if (r1 != 1)
- ++failures;
+ VERIFY( r1 == 1 );
r1 = 9;
- if (r1 != 9)
- ++failures;
+ VERIFY( r1 == 9 );
r1 = 1;
- if ((i1 != i2) != true)
- ++failures;
- if ((i1 == i2) != false)
- ++failures;
- if ((i1 < i2) != true)
- ++failures;
- if ((i1 > i2) != false)
- ++failures;
- if ((i1 <= i2) != true)
- ++failures;
- if ((i1 >= i2) != false)
- ++failures;
+ VERIFY( (i1 != i2) == true );
+ VERIFY( (i1 == i2) == false );
+ VERIFY( (i1 < i2) == true );
+ VERIFY( (i1 > i2) == false );
+ VERIFY( (i1 <= i2) == true );
+ VERIFY( (i1 >= i2) == false );
std::vector<int>::iterator i3;
i3 = i1;
- if ((i3 == i1) != true)
- ++failures;
+ VERIFY( (i3 == i1) == true );
i3 += 5;
- if ((i3 == i2) != true)
- ++failures;
+ VERIFY( (i3 == i2) == true );
i3 -= 5;
- if ((i3 == i1) != true)
- ++failures;
-
- if (i3 + 5 != i2)
- ++failures;
-
- if (5 + i3 != i2)
- ++failures;
+ VERIFY( (i3 == i1) == true );
- if (i2 - 5 != i3)
- ++failures;
+ VERIFY( i3 + 5 == i2 );
+ VERIFY( 5 + i3 == i2 );
+ VERIFY( i2 - 5 == i3 );
- if (i1[0] != 1)
- ++failures;
+ VERIFY( i1[0] == 1 );
i1[4] = 9;
- if (i2[-1] != 9)
- ++failures;
+ VERIFY( i2[-1] == 9 );
i1[4] = 5;
i1[2] = 9;
- if (i2[-3] != 9)
- ++failures;
+ VERIFY( i2[-3] == 9 );
i1[2] = 3;
std::vector<int>::const_iterator ci1(v.begin());
- if (*ci1 != 1)
- ++failures;
+ VERIFY( *ci1 == 1 );
++ci1;
- if (*ci1 != 2)
- ++failures;
+ VERIFY( *ci1 == 2 );
- if (*ci1++ != 2)
- ++failures;
- if (*ci1 != 3)
- ++failures;
+ VERIFY( *ci1++ == 2 );
+ VERIFY( *ci1 == 3 );
++ ++ci1;
- if (*ci1 != 5)
- ++failures;
+ VERIFY( *ci1 == 5 );
--ci1;
- if (*ci1 != 4)
- ++failures;
+ VERIFY( *ci1 == 4 );
- if (*ci1-- != 4)
- ++failures;
- if (*ci1 != 3)
- ++failures;
+ VERIFY( *ci1-- == 4 );
+ VERIFY( *ci1 == 3 );
-- --ci1;
- if (*ci1 != 1)
- ++failures;
+ VERIFY( *ci1 == 1 );
std::vector<int>::const_iterator ci2;
ci2 = v.end();
std::iterator_traits<std::vector<int>::const_iterator>::difference_type d2;
d2 = ci2 - ci1;
- if (d2 != 5)
- ++failures;
+ VERIFY( d2 == 5 );
std::iterator_traits<std::vector<int>::const_iterator>::value_type v2;
v2 = ci1[0];
- if (v2 != 1)
- ++failures;
+ VERIFY( v2 == 1 );
std::iterator_traits<std::vector<int>::const_iterator>::reference
r2(ci1[0]);
- if (r2 != 1)
- ++failures;
-
- if ((ci1 != ci2) != true)
- ++failures;
- if ((ci1 == ci2) != false)
- ++failures;
- if ((ci1 < ci2) != true)
- ++failures;
- if ((ci1 > ci2) != false)
- ++failures;
- if ((ci1 <= ci2) != true)
- ++failures;
- if ((ci1 >= ci2) != false)
- ++failures;
+ VERIFY( r2 == 1 );
+
+ VERIFY( (ci1 != ci2) == true );
+ VERIFY( (ci1 == ci2) == false );
+ VERIFY( (ci1 < ci2) == true );
+ VERIFY( (ci1 > ci2) == false );
+ VERIFY( (ci1 <= ci2) == true );
+ VERIFY( (ci1 >= ci2) == false );
std::vector<int>::const_iterator ci3;
ci3 = ci1;
- if ((ci3 == ci1) != true)
- ++failures;
+ VERIFY( (ci3 == ci1) == true );
ci3 += 5;
- if ((ci3 == ci2) != true)
- ++failures;
+ VERIFY( (ci3 == ci2) == true );
ci3 -= 5;
- if ((ci3 == ci1) != true)
- ++failures;
-
- if (ci3 + 5 != ci2)
- ++failures;
+ VERIFY( (ci3 == ci1) == true );
- if (5 + ci3 != ci2)
- ++failures;
+ VERIFY( ci3 + 5 == ci2 );
+ VERIFY( 5 + ci3 == ci2 );
+ VERIFY( ci2 - 5 == ci3 );
- if (ci2 - 5 != ci3)
- ++failures;
+ VERIFY( ci1[2] == 3 );
- if (ci1[2] != 3)
- ++failures;
-
- if (ci2[-1] != 5)
- ++failures;
+ VERIFY( ci2[-1] == 5 );
// iterator to const_iterator
std::vector<int>::const_iterator ci4(i1);
- if ((ci4 == i1) != true)
- ++failures;
- if ((ci4 != i1) != false)
- ++failures;
- if ((ci4 < i1) != false)
- ++failures;
- if ((ci4 > i1) != false)
- ++failures;
- if ((ci4 <= i1) != true)
- ++failures;
- if ((ci4 >= i1) != true)
- ++failures;
+ VERIFY( (ci4 == i1) == true );
+ VERIFY( (ci4 != i1) == false );
+ VERIFY( (ci4 < i1) == false );
+ VERIFY( (ci4 > i1) == false );
+ VERIFY( (ci4 <= i1) == true );
+ VERIFY( (ci4 >= i1) == true );
ci4 = i2;
- if ((i2 == ci4) != true)
- ++failures;
- if ((i2 < ci4) != false)
- ++failures;
- if ((i2 > ci4) != false)
- ++failures;
- if ((i2 <= ci4) != true)
- ++failures;
- if ((i2 >= ci4) != true)
- ++failures;
+ VERIFY( (i2 == ci4) == true );
+ VERIFY( (i2 < ci4) == false );
+ VERIFY( (i2 > ci4) == false );
+ VERIFY( (i2 <= ci4) == true );
+ VERIFY( (i2 >= ci4) == true );
const std::vector<int> cv(v);
std::vector<int>::const_iterator ci5(cv.begin());
- if (ci5[0] != 1)
- ++failures;
+ VERIFY( ci5[0] == 1 );
std::vector<std::string> vs;
vs.push_back(std::string("abc"));
std::vector<std::string>::iterator ivs(vs.begin());
- if (ivs->c_str()[1] != 'b')
- ++failures;
-
- return failures;
+ VERIFY( ivs->c_str()[1] == 'b' );
}
-int
+void
reverse_stuff()
{
- int failures(0);
-
std::string s("abcde");
std::string::reverse_iterator ri(s.rbegin());
- if (*ri != 'e')
- ++failures;
+ VERIFY( *ri == 'e' );
std::iterator_traits<std::string::reverse_iterator>::difference_type d;
d = s.rend() - ri;
- if (d != 5)
- ++failures;
+ VERIFY( d == 5 );
const std::string cs("abcde");
std::string::const_reverse_iterator cri(cs.rend());
- if (cri - 5 != cs.rbegin())
- ++failures;
-
- return failures;
-}
-
-// the following should be compiler errors
-// flag runtime errors in case they slip through the compiler
-int
-wrong_stuff()
-{
- int failures(0);
-
-#ifdef ITER24_F1
- extern void f(std::vector<std::string*>::iterator);
- std::vector<std::string*> vs[2];
- f(vs); // address of array is not an iterator
- failures++;
-#endif
-
-#ifdef ITER24_F2
- std::string s;
- char *i = s.begin(); // begin() doesn't return a pointer
- failures++;
-#endif
-
-#ifdef ITER24_F3
- std::string::const_iterator ci;
- std::string::iterator i;
- if (i - ci) // remove const_ is a warning
- i++;
- // failures++; only a warning
-#endif
-
-#ifdef ITER24_F4
- std::vector<char>::iterator iv;
- std::string::iterator is(iv);// vector<char> is not string
- failures++;
-#endif
-
-#ifdef ITER24_F5
- std::vector<char>::iterator iv;
- std::string::iterator is;
- if (iv == is) // vector<char> is not string
- ++iv;
- failures++;
-#endif
-
-#ifdef ITER24_F6
- std::vector<char>::const_iterator ci;
- std::vector<char>::iterator i = ci; // remove const_ is a warning
- ++i;
- // failures++; only a warning
-#endif
-
-#ifdef ITER24_F7
- std::vector<int> v(1);
- std::vector<int>::const_iterator ci(v.begin());
- *ci = 1; // cannot assign through const_iterator
- failures++;
-#endif
-
-#ifdef ITER24_F8
- std::vector<const int> v(1);
- std::vector<const int>::reference r(v.begin()[0]);
- r = 1; // cannot assign through reference to const
- failures++;
-#endif
-
- return failures;
+ VERIFY( cri - 5 == cs.rbegin() );
}
// libstdc++/6642
-int
+void
test6642()
{
std::string s;
std::string::iterator it = s.begin();
std::string::const_iterator cit = s.begin();
-
- return it - cit;
+ VERIFY( (it - cit) == 0 );
}
int
main()
{
- int failures(0);
-
- failures += string_stuff();
-
- failures += vector_stuff();
-
- failures += reverse_stuff();
-
- failures += wrong_stuff();
-
- failures += test6642();
-
- VERIFY(failures == 0);
+ string_stuff();
+ vector_stuff();
+ reverse_stuff();
+ test6642();
return 0;
}
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/24_iterators/range_generators/lwg3900.cc b/libstdc++-v3/testsuite/24_iterators/range_generators/lwg3900.cc
index 957879e..08fd5c2 100644
--- a/libstdc++-v3/testsuite/24_iterators/range_generators/lwg3900.cc
+++ b/libstdc++-v3/testsuite/24_iterators/range_generators/lwg3900.cc
@@ -13,4 +13,5 @@ bar(std::allocator_arg_t, std::pmr::memory_resource& mr) // { dg-error "here" }
}
// { dg-error "static assertion failed" "" { target *-*-* } 0 }
-// { dg-error "no matching function .*memory_resource&" "" { target *-*-* } 0 }
+// { dg-error "could not convert 'const std::pmr::memory_resource'" "" { target *-*-* } 0 }
+// { dg-error "no matching function \[^\n\r\]*memory_resource&" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/24_iterators/range_operations/122224.cc b/libstdc++-v3/testsuite/24_iterators/range_operations/122224.cc
new file mode 100644
index 0000000..62bea92
--- /dev/null
+++ b/libstdc++-v3/testsuite/24_iterators/range_operations/122224.cc
@@ -0,0 +1,100 @@
+// { dg-do run { target c++11 } }
+// { dg-add-options no_pch }
+
+// Undefine these if present in runtest flags.
+#undef _GLIBCXX_ASSERTIONS
+#undef _GLIBCXX_DEBUG
+
+// Prevent assertions from being automatically enabled at -O0
+#define _GLIBCXX_NO_ASSERTIONS
+
+#include <iterator>
+#include <testsuite_iterators.h>
+#include <testsuite_hooks.h>
+
+template<typename Container>
+void
+test_advance()
+{
+ int a[] = { 1, 2, 3 };
+ Container c(a);
+ auto iter = c.begin();
+
+ // This call violates the precondition for std::advance,
+ // but with assertions disabled we do not diagnose it.
+ std::advance(iter, -1);
+
+ // However we do guarantee that erroneously decrementing
+ // an input iterator is a no-op and does no harm.
+ VERIFY( *iter == 1 );
+
+ ++iter;
+ std::advance(iter, -999);
+ VERIFY( *iter == 2 );
+
+ std::advance(iter, 0);
+ VERIFY( *iter == 2 );
+ std::advance(iter, 1);
+ VERIFY( *iter == 3 );
+}
+
+template<typename Container>
+void
+test_prev()
+{
+ int a[] = { 1, 2, 3 };
+ Container c(a);
+ auto iter = c.begin();
+
+ // This calls std::advance(iter, -1), which violates the precondition.
+ iter = std::prev(iter);
+
+ // As above, we turn the std::prev call into a no-op.
+ VERIFY( *iter == 1 );
+
+ ++iter;
+ iter = std::prev(iter, 999);
+ VERIFY( *iter == 2 );
+
+ iter = std::prev(iter, 0);
+ VERIFY( *iter == 2 );
+ iter = std::prev(iter, -1);
+ VERIFY( *iter == 3 );
+}
+
+template<typename Container>
+void
+test_next()
+{
+ int a[] = { 1, 2, 3 };
+ Container c(a);
+ auto iter = c.begin();
+
+ // This calls std::advance(iter, -1), which violates the precondition.
+ iter = std::next(iter, -1);
+
+ // As above, we turn the std::prev call into a no-op.
+ VERIFY( *iter == 1 );
+
+ ++iter;
+ iter = std::next(iter, -999);
+ VERIFY( *iter == 2 );
+
+ iter = std::next(iter, 0);
+ VERIFY( *iter == 2 );
+ iter = std::next(iter);
+ VERIFY( *iter == 3 );
+}
+
+int main()
+{
+ using InputContainer = __gnu_test::input_container<int>;
+ test_advance<InputContainer>();
+ test_prev<InputContainer>();
+ test_next<InputContainer>();
+
+ using ForwardContainer = __gnu_test::forward_container<int>;
+ test_advance<ForwardContainer>();
+ test_prev<ForwardContainer>();
+ test_next<ForwardContainer>();
+}
diff --git a/libstdc++-v3/testsuite/24_iterators/range_operations/advance.cc b/libstdc++-v3/testsuite/24_iterators/range_operations/advance.cc
index 2f48181..8229b1e 100644
--- a/libstdc++-v3/testsuite/24_iterators/range_operations/advance.cc
+++ b/libstdc++-v3/testsuite/24_iterators/range_operations/advance.cc
@@ -42,7 +42,7 @@ test01()
std::ranges::advance(iter, -2);
VERIFY( iter == r.begin() );
- std::ranges::advance(iter, r.begin() + 1);
+ std::ranges::advance(iter, std::ranges::next(r.begin()));
VERIFY( iter != r.begin() );
VERIFY( iter != r.end() );
std::ranges::advance(iter, r.begin());
diff --git a/libstdc++-v3/testsuite/25_algorithms/copy/debug/constexpr_neg.cc b/libstdc++-v3/testsuite/25_algorithms/copy/debug/constexpr_neg.cc
index 0e80977..3840524 100644
--- a/libstdc++-v3/testsuite/25_algorithms/copy/debug/constexpr_neg.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/copy/debug/constexpr_neg.cc
@@ -33,7 +33,7 @@ test1()
}
static_assert(test1()); // { dg-error "non-constant condition" }
-// { dg-error "_Error_formatter::_M_error()" "" { target *-*-* } 0 }
+// { dg-error "_Error_formatter::(_M_error|_S_at)" "" { target *-*-* } 0 }
constexpr bool
test2()
diff --git a/libstdc++-v3/testsuite/25_algorithms/copy_backward/debug/constexpr_neg.cc b/libstdc++-v3/testsuite/25_algorithms/copy_backward/debug/constexpr_neg.cc
index 410c235..d5d84b1 100644
--- a/libstdc++-v3/testsuite/25_algorithms/copy_backward/debug/constexpr_neg.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/copy_backward/debug/constexpr_neg.cc
@@ -35,4 +35,4 @@ test()
static_assert(test()); // { dg-error "non-constant condition" }
-// { dg-prune-output "_Error_formatter::_M_error()" }
+// { dg-prune-output "_Error_formatter::(_M_error|_S_at)" }
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/equal/debug/constexpr_neg.cc b/libstdc++-v3/testsuite/25_algorithms/equal/debug/constexpr_neg.cc
index cbc7509..6c1531d 100644
--- a/libstdc++-v3/testsuite/25_algorithms/equal/debug/constexpr_neg.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/equal/debug/constexpr_neg.cc
@@ -32,7 +32,7 @@ test01()
}
static_assert(test01()); // { dg-error "non-constant condition" }
-// { dg-error "_Error_formatter::_M_error()" "" { target *-*-* } 0 }
+// { dg-error "_Error_formatter::(_M_error|_S_at)" "" { target *-*-* } 0 }
constexpr bool
test02()
diff --git a/libstdc++-v3/testsuite/25_algorithms/fill_n/diff_type.cc b/libstdc++-v3/testsuite/25_algorithms/fill_n/diff_type.cc
new file mode 100644
index 0000000..7265d39
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/fill_n/diff_type.cc
@@ -0,0 +1,13 @@
+// { dg-do compile { target c++11 } }
+
+#include <algorithm>
+#include <testsuite_iterators.h>
+
+void
+test_pr121890()
+{
+ // algorithms do not use iterator's difference_type for arithmetic
+ int a[1];
+ __gnu_test::random_access_container<int> c(a);
+ std::fill_n(c.begin(), 1U, 0);
+}
diff --git a/libstdc++-v3/testsuite/25_algorithms/heap/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/heap/constrained.cc
index 8037a2d..2f818e2 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>
@@ -52,17 +53,17 @@ test01()
iter = ranges::pop_heap(rx, pred, proj);
VERIFY( iter == rx.end() );
- VERIFY( *(iter-1) == 50 );
- VERIFY( ranges::is_heap_until(rx, pred, proj) == iter-1 );
+ VERIFY( *ranges::prev(iter) == 50 );
+ VERIFY( ranges::is_heap_until(rx, pred, proj) == ranges::prev(iter) );
- iter = ranges::pop_heap(rx.begin(), iter-1, pred, proj);
- VERIFY( iter+1 == rx.end() );
- VERIFY( *(iter-1) == 49 );
- VERIFY( ranges::is_heap_until(rx, pred, proj) == iter-1 );
+ iter = ranges::pop_heap(rx.begin(), ranges::prev(iter), pred, proj);
+ VERIFY( ranges::next(iter) == rx.end() );
+ VERIFY( *ranges::prev(iter) == 49 );
+ VERIFY( ranges::is_heap_until(rx, pred, proj) == ranges::prev(iter) );
- *(iter-1) = i;
+ *ranges::prev(iter) = i;
iter = ranges::push_heap(rx.begin(), iter, pred, proj);
- VERIFY( iter+1 == rx.end() );
+ VERIFY( ranges::next(iter) == rx.end() );
VERIFY( ranges::is_heap_until(rx, pred, proj) == iter );
*iter = 2*i;
@@ -70,9 +71,9 @@ test01()
VERIFY( iter == rx.end() );
VERIFY( ranges::is_heap_until(rx, pred, proj) == iter );
- *(rx.begin()+1) *= -1;
+ *ranges::next(rx.begin()) *= -1;
VERIFY( !ranges::is_heap(rx, pred, proj) );
- *(rx.begin()+1) *= -1;
+ *ranges::next(rx.begin()) *= -1;
VERIFY( ranges::is_heap(rx, pred, proj) );
iter = ranges::sort_heap(rx, pred, proj);
@@ -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/lexicographical_compare/diff_type.cc b/libstdc++-v3/testsuite/25_algorithms/lexicographical_compare/diff_type.cc
new file mode 100644
index 0000000..b790197
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/lexicographical_compare/diff_type.cc
@@ -0,0 +1,57 @@
+// { dg-do compile { target c++11 } }
+
+#include <algorithm>
+#include <testsuite_iterators.h>
+
+struct Iter
+{
+ using value_type = int;
+ using difference_type = short;
+ using iterator_category = std::random_access_iterator_tag;
+ using pointer = const value_type*;
+ using reference = const value_type&;
+
+ Iter() : p(nullptr) { }
+ explicit Iter(pointer p) : p(p) { }
+ reference operator*() const { return *p; }
+ pointer operator->() const { return p; }
+ reference operator[](difference_type n) const { return p[n]; }
+ Iter& operator++() { ++p; return *this; }
+ Iter& operator--() { --p; return *this; }
+ Iter operator++(int) { return Iter(p++); }
+ Iter operator--(int) { return Iter(p--); }
+ Iter& operator+=(difference_type n) { p += n; return *this; }
+ Iter& operator-=(difference_type n) { p -= n; return *this; }
+
+ friend Iter operator+(Iter i, difference_type n) { return i += n; }
+ friend Iter operator+(difference_type n, Iter i) { return i += n; }
+ friend Iter operator-(Iter i, difference_type n) { return i -= n; }
+ friend difference_type operator-(Iter i, Iter j) { return i.p - j.p; }
+
+ template<typename D> void operator[](D) const = delete;
+ template<typename D> void operator+=(D) = delete;
+ template<typename D> void operator-=(D) = delete;
+ template<typename D> friend void operator+(Iter, difference_type) = delete;
+ template<typename D> friend void operator+(difference_type, Iter) = delete;
+ template<typename D> friend void operator-(Iter, difference_type) = delete;
+
+ friend bool operator==(Iter i, Iter j) { return i.p == j.p; }
+ friend bool operator!=(Iter i, Iter j) { return i.p != j.p; }
+ friend bool operator<(Iter i, Iter j) { return i.p < j.p; }
+ friend bool operator<=(Iter i, Iter j) { return i.p <= j.p; }
+ friend bool operator>(Iter i, Iter j) { return i.p > j.p; }
+ friend bool operator>=(Iter i, Iter j) { return i.p >= j.p; }
+
+private:
+ pointer p;
+};
+
+void
+test_pr121890()
+{
+ // algorithms do not use iterator's difference_type for arithmetic
+ int a[1] = { };
+ __gnu_test::random_access_container<int> c(a);
+ (void) std::lexicographical_compare(c.begin(), c.end(), Iter(a), Iter(a+1));
+ (void) std::lexicographical_compare(Iter(a), Iter(a+1), c.begin(), c.end());
+}
diff --git a/libstdc++-v3/testsuite/25_algorithms/lower_bound/debug/constexpr_partitioned_neg.cc b/libstdc++-v3/testsuite/25_algorithms/lower_bound/debug/constexpr_partitioned_neg.cc
index c07145c..b44cb4b 100644
--- a/libstdc++-v3/testsuite/25_algorithms/lower_bound/debug/constexpr_partitioned_neg.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/lower_bound/debug/constexpr_partitioned_neg.cc
@@ -43,5 +43,5 @@ test()
static_assert(test()); // { dg-error "" }
-// { dg-prune-output "_Error_formatter::_M_error()" }
+// { dg-prune-output "_Error_formatter::(_M_error|_S_at)" }
// { dg-prune-output "in 'constexpr'" }
diff --git a/libstdc++-v3/testsuite/25_algorithms/lower_bound/debug/constexpr_partitioned_pred_neg.cc b/libstdc++-v3/testsuite/25_algorithms/lower_bound/debug/constexpr_partitioned_pred_neg.cc
index 09ae26f..7835b30 100644
--- a/libstdc++-v3/testsuite/25_algorithms/lower_bound/debug/constexpr_partitioned_pred_neg.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/lower_bound/debug/constexpr_partitioned_pred_neg.cc
@@ -33,4 +33,4 @@ test()
static_assert(test()); // { dg-error "" }
-// { dg-prune-output "_Error_formatter::_M_error()" }
+// { dg-prune-output "_Error_formatter::(_M_error|_S_at)" }
diff --git a/libstdc++-v3/testsuite/25_algorithms/lower_bound/debug/constexpr_valid_range_neg.cc b/libstdc++-v3/testsuite/25_algorithms/lower_bound/debug/constexpr_valid_range_neg.cc
index 20eb026..911880b 100644
--- a/libstdc++-v3/testsuite/25_algorithms/lower_bound/debug/constexpr_valid_range_neg.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/lower_bound/debug/constexpr_valid_range_neg.cc
@@ -46,5 +46,5 @@ test2()
static_assert(test2()); // { dg-error "" }
-// { dg-prune-output "_Error_formatter::_M_error()" }
+// { dg-prune-output "_Error_formatter::(_M_error|_S_at)" }
diff --git a/libstdc++-v3/testsuite/25_algorithms/max/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/max/constrained.cc
index c3cd288..c6759f8 100644
--- a/libstdc++-v3/testsuite/25_algorithms/max/constrained.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/max/constrained.cc
@@ -87,12 +87,12 @@ test04()
int m;
};
A r[5] = {5, 4, 3, 2, 1};
- ranges::max(r, ranges::less{}, &A::m);
+ (void)ranges::max(r, ranges::less{}, &A::m);
VERIFY( copies == 1 );
VERIFY( moves == 0 );
copies = moves = 0;
A s[5] = {1, 2, 3, 4, 5};
- ranges::max(s, ranges::less{}, &A::m);
+ (void)ranges::max(s, ranges::less{}, &A::m);
VERIFY( copies == 5 );
VERIFY( moves == 0 );
}
diff --git a/libstdc++-v3/testsuite/25_algorithms/min/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/min/constrained.cc
index d5de040..7d4fa58 100644
--- a/libstdc++-v3/testsuite/25_algorithms/min/constrained.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/min/constrained.cc
@@ -87,12 +87,12 @@ test04()
int m;
};
A r[5] = {5, 4, 3, 2, 1};
- ranges::min(r, ranges::less{}, &A::m);
+ (void)ranges::min(r, ranges::less{}, &A::m);
VERIFY( copies == 5 );
VERIFY( moves == 0 );
copies = moves = 0;
A s[5] = {1, 2, 3, 4, 5};
- ranges::min(s, ranges::less{}, &A::m);
+ (void)ranges::min(s, ranges::less{}, &A::m);
VERIFY( copies == 1 );
VERIFY( moves == 0 );
}
diff --git a/libstdc++-v3/testsuite/25_algorithms/minmax/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/minmax/constrained.cc
index 5a5d341..8f8df43 100644
--- a/libstdc++-v3/testsuite/25_algorithms/minmax/constrained.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/minmax/constrained.cc
@@ -99,20 +99,28 @@ test04()
struct counted_less
{ bool operator()(int a, int b) { ++counter; return a < b; } };
- ranges::minmax({1,2}, counted_less{});
+ auto p = ranges::minmax({1,2}, counted_less{});
VERIFY( counter == 1 );
+ VERIFY( p.min == 1 );
+ VERIFY( p.max == 2 );
counter = 0;
- ranges::minmax({1,2,3}, counted_less{});
+ p = ranges::minmax({1,2,3}, counted_less{});
VERIFY( counter == 3 );
+ VERIFY( p.min == 1 );
+ VERIFY( p.max == 3 );
counter = 0;
- ranges::minmax({1,2,3,4,5,6,7,8,9,10}, counted_less{});
+ p = ranges::minmax({1,2,3,4,5,6,7,8,9,10}, counted_less{});
VERIFY( counter <= 15 );
+ VERIFY( p.min == 1 );
+ VERIFY( p.max == 10 );
counter = 0;
- ranges::minmax({10,9,8,7,6,5,4,3,2,1}, counted_less{});
+ p = ranges::minmax({10,9,8,7,6,5,4,3,2,1}, counted_less{});
VERIFY( counter <= 15 );
+ VERIFY( p.min == 1 );
+ VERIFY( p.max == 10 );
}
void
diff --git a/libstdc++-v3/testsuite/25_algorithms/minmax_element/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/minmax_element/constrained.cc
index 99ebf03..1eaaf07 100644
--- a/libstdc++-v3/testsuite/25_algorithms/minmax_element/constrained.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/minmax_element/constrained.cc
@@ -70,21 +70,29 @@ test02()
{ bool operator()(int a, int b) { ++counter; return a < b; } };
int x[] = {1,2,3,4,5,6,7,8,9,10};
- ranges::minmax_element(x, x+2, counted_less{});
+ auto p = ranges::minmax_element(x, x+2, counted_less{});
VERIFY( counter == 1 );
+ VERIFY( p.min == x+0 );
+ VERIFY( p.max == x+1 );
counter = 0;
- ranges::minmax_element(x, x+3, counted_less{});
+ p = ranges::minmax_element(x, x+3, counted_less{});
VERIFY( counter == 3 );
+ VERIFY( p.min == x+0 );
+ VERIFY( p.max == x+2 );
counter = 0;
- ranges::minmax_element(x, counted_less{});
+ p = ranges::minmax_element(x, counted_less{});
VERIFY( counter <= 15 );
+ VERIFY( p.min == x+0 );
+ VERIFY( p.max == x+9 );
ranges::reverse(x);
counter = 0;
- ranges::minmax_element(x, counted_less{});
+ p = ranges::minmax_element(x, counted_less{});
VERIFY( counter <= 15 );
+ VERIFY( p.min == x+9 );
+ VERIFY( p.max == x+0 );
}
int
diff --git a/libstdc++-v3/testsuite/25_algorithms/nth_element/58800.cc b/libstdc++-v3/testsuite/25_algorithms/nth_element/58800.cc
index 3989ee0..ff86c63 100644
--- a/libstdc++-v3/testsuite/25_algorithms/nth_element/58800.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/nth_element/58800.cc
@@ -43,7 +43,7 @@ void test01()
Container con(v.data(), v.data() + 7);
- std::nth_element(con.begin(), con.begin() + 3, con.end());
+ std::nth_element(con.begin(), std::next(con.begin(), 3), con.end());
}
int main()
diff --git a/libstdc++-v3/testsuite/25_algorithms/nth_element/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/nth_element/constrained.cc
index 3189b22..8d3a057 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>
@@ -37,7 +38,7 @@ test01()
auto pred = std::greater{};
auto proj = [] (int a) { return -a; };
- for (int i = 0; i < 50; i++)
+ for (std::ptrdiff_t i = 0; i < 50; i++)
{
test_range<int, random_access_iterator_wrapper> rx(x);
std::ranlux48_base g(i);
@@ -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/nth_element/random_test.cc b/libstdc++-v3/testsuite/25_algorithms/nth_element/random_test.cc
index 2e9d4b3..9eaef61 100644
--- a/libstdc++-v3/testsuite/25_algorithms/nth_element/random_test.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/nth_element/random_test.cc
@@ -37,9 +37,9 @@ struct testNthElement
template<typename Container, typename RandomGen>
void operator()(Container con, RandomGen& rg)
{
- const int size = con.end() - con.begin();
+ const auto size = con.end() - con.begin();
auto dist = std::uniform_int_distribution<>(0, size);
- const int element = dist(rg);
+ const decltype(size) element = dist(rg);
std::nth_element(con.begin(), con.begin() + element, con.end());
diff --git a/libstdc++-v3/testsuite/25_algorithms/partial_sort/check_compare_by_value.cc b/libstdc++-v3/testsuite/25_algorithms/partial_sort/check_compare_by_value.cc
index 05f4f1c..e1ba840 100644
--- a/libstdc++-v3/testsuite/25_algorithms/partial_sort/check_compare_by_value.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/partial_sort/check_compare_by_value.cc
@@ -43,7 +43,7 @@ test01()
17, 8, 18, 9, 19 };
const int N = sizeof(s1) / sizeof(V);
Container con(s1, s1 + N);
- std::partial_sort(con.begin(), con.begin() + 10, con.end());
+ std::partial_sort(con.begin(), std::next(con.begin(), 10), con.end());
VERIFY( s1[0].ok );
for(int i = 1; i < 10; ++i)
VERIFY( s1[i].val > s1[i - 1].val && s1[i].ok );
@@ -59,7 +59,7 @@ test02()
17, 8, 18, 9, 19 };
const int N = sizeof(s1) / sizeof(V);
Container con(s1, s1 + N);
- std::partial_sort(con.begin(), con.begin() + 10, con.end(),
+ std::partial_sort(con.begin(), std::next(con.begin(), 10), con.end(),
__gnu_test::order);
VERIFY( s1[0].ok );
for(int i = 1; i < 10; ++i)
diff --git a/libstdc++-v3/testsuite/25_algorithms/partial_sort/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/partial_sort/constrained.cc
index 032ffe7..554a8d7 100644
--- a/libstdc++-v3/testsuite/25_algorithms/partial_sort/constrained.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/partial_sort/constrained.cc
@@ -47,7 +47,8 @@ test01()
ranges::shuffle(c, g1);
ranges::shuffle(ranges::begin(r), ranges::end(r), g2);
- for (unsigned middle = 0; middle < std::min(size, 10U); ++middle)
+ for (std::ptrdiff_t middle = 0, end = std::min(size, 10U);
+ middle < end; ++middle)
{
auto res1 = ranges::partial_sort(c.begin(), c.begin()+middle, c.end(),
{}, std::negate<>{});
diff --git a/libstdc++-v3/testsuite/25_algorithms/partial_sort/random_test.cc b/libstdc++-v3/testsuite/25_algorithms/partial_sort/random_test.cc
index 89eb992..4e69000 100644
--- a/libstdc++-v3/testsuite/25_algorithms/partial_sort/random_test.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/partial_sort/random_test.cc
@@ -37,9 +37,9 @@ struct testPartialSort
template<typename Container, typename RandomGen>
void operator()(Container con, RandomGen& rg)
{
- const int size = con.end() - con.begin();
+ const auto size = con.end() - con.begin();
auto dist = std::uniform_int_distribution<>(0, size);
- const int element = dist(rg);
+ const decltype(size) element = dist(rg);
std::partial_sort(con.begin(), con.begin() + element, con.end());
diff --git a/libstdc++-v3/testsuite/25_algorithms/partial_sort_copy/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/partial_sort_copy/constrained.cc
index a0bd48b..38b2dda 100644
--- a/libstdc++-v3/testsuite/25_algorithms/partial_sort_copy/constrained.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/partial_sort_copy/constrained.cc
@@ -35,7 +35,7 @@ namespace ranges = std::ranges;
void
test01()
{
- for (unsigned size = 0; size < 50; ++size)
+ for (std::ptrdiff_t size = 0; size < 50; ++size)
{
std::vector<int> vref(size);
std::iota(vref.begin(), vref.end(), 0);
@@ -45,7 +45,7 @@ test01()
ranges::shuffle(v1, g1);
ranges::shuffle(v2, g2);
- for (unsigned middle = 0; middle < 10; ++middle)
+ for (std::ptrdiff_t middle = 0; middle < 10; ++middle)
{
test_container<int, forward_iterator_wrapper> c
= {v1.data(), v1.data() + size};
diff --git a/libstdc++-v3/testsuite/25_algorithms/partial_sort_copy/random_test.cc b/libstdc++-v3/testsuite/25_algorithms/partial_sort_copy/random_test.cc
index 2c0b8bc..be033a2 100644
--- a/libstdc++-v3/testsuite/25_algorithms/partial_sort_copy/random_test.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/partial_sort_copy/random_test.cc
@@ -38,9 +38,9 @@ struct testPartialSortCopy
template<typename Container, typename RandomGen>
void operator()(Container con, RandomGen& rg)
{
- const int size = con.end() - con.begin();
+ const auto size = con.end() - con.begin();
auto dist = std::uniform_int_distribution<>(0, size);
- const int element = dist(rg);
+ const decltype(size) element = dist(rg);
std::vector<int> outvec(element + 1); // add +1 to avoid empty issues
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/rotate/121913.cc b/libstdc++-v3/testsuite/25_algorithms/rotate/121913.cc
new file mode 100644
index 0000000..d648699
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/rotate/121913.cc
@@ -0,0 +1,45 @@
+// { dg-do compile { target c++20 } }
+
+// Bug libstdc++/121913 ranges::rotate should use ranges::iter_move
+
+#include <algorithm>
+
+struct A { };
+
+struct B
+{
+ B& operator=(const B&) = delete;
+ B& operator=(const A&) const;
+
+ operator A() const;
+};
+
+struct I
+{
+ using value_type = A;
+ using difference_type = int;
+ B operator*() const;
+ B operator[](int) const;
+ I& operator++();
+ I operator++(int);
+ I& operator--();
+ I operator--(int);
+ I& operator+=(int);
+ I& operator-=(int);
+
+ auto operator<=>(const I&) const = default;
+
+ friend A iter_move(const I&);
+ friend I operator+(I, int);
+ friend I operator-(I, int);
+ friend I operator+(int, I);
+ friend int operator-(I, I);
+};
+
+static_assert( std::random_access_iterator<I> );
+
+void
+test_pr121913()
+{
+ std::ranges::rotate(I{}, I{}, I{});
+}
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/shift_left/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/shift_left/constrained.cc
new file mode 100644
index 0000000..73d0614
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/shift_left/constrained.cc
@@ -0,0 +1,105 @@
+// 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++23 } }
+// This test is based on shift_left/1.cc.
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+using __gnu_test::test_range;
+using __gnu_test::forward_iterator_wrapper;
+using __gnu_test::bidirectional_iterator_wrapper;
+using __gnu_test::random_access_iterator_wrapper;
+
+struct X
+{
+ int a = -1;
+ bool moved_from = false;
+
+ X() = default;
+
+ X(int a)
+ : a(a)
+ { }
+
+ X(const X&) = delete;
+ X& operator=(const X&) = delete;
+
+ X(X&& other)
+ {
+ if (this != &other)
+ *this = std::move(other);
+ }
+
+ X&
+ operator=(X&& other)
+ {
+ a = other.a;
+ other.moved_from = true;
+ moved_from = false;
+ return *this;
+ }
+};
+
+template<int N, template<typename> typename Wrapper>
+void
+test01()
+{
+ for (int n = 0; n < N+5; n++)
+ {
+ X x[N];
+ for (int i = 0; i < N; i++)
+ x[i] = X{i};
+ test_range<X, Wrapper> rx(x);
+ auto [first,out] = std::ranges::shift_left(rx.begin(), rx.end(), n);
+ VERIFY( first == rx.begin() );
+ if (n < N)
+ {
+ VERIFY( out.ptr == x+(N-n) );
+ for (int i = 0; i < N-n; i++)
+ {
+ VERIFY( x[i].a == n+i );
+ VERIFY( !x[i].moved_from );
+ }
+ for (int i = std::max(n, N-n); i < N; i++)
+ VERIFY( x[i].moved_from );
+ }
+ else
+ {
+ VERIFY( out.ptr == x );
+ for (int i = 0; i < N; i++)
+ {
+ VERIFY( x[i].a == i );
+ VERIFY( !x[i].moved_from );
+ }
+ }
+ }
+}
+
+int
+main()
+{
+ test01<23, forward_iterator_wrapper>();
+ test01<23, bidirectional_iterator_wrapper>();
+ test01<23, random_access_iterator_wrapper>();
+
+ test01<24, forward_iterator_wrapper>();
+ test01<24, bidirectional_iterator_wrapper>();
+ test01<24, random_access_iterator_wrapper>();
+}
diff --git a/libstdc++-v3/testsuite/25_algorithms/shift_right/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/shift_right/constrained.cc
new file mode 100644
index 0000000..0d53707
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/shift_right/constrained.cc
@@ -0,0 +1,104 @@
+// 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++23 } }
+// This test is based on shift_right/1.cc.
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+using __gnu_test::test_range;
+using __gnu_test::forward_iterator_wrapper;
+using __gnu_test::bidirectional_iterator_wrapper;
+using __gnu_test::random_access_iterator_wrapper;
+
+struct X
+{
+ int a = -1;
+ bool moved_from = false;
+
+ X() = default;
+
+ X(int a)
+ : a(a)
+ { }
+
+ X(const X&) = delete;
+ X& operator=(const X&) = delete;
+
+ X(X&& other)
+ {
+ if (this != &other)
+ *this = std::move(other);
+ }
+
+ X&
+ operator=(X&& other)
+ {
+ a = other.a;
+ other.moved_from = true;
+ moved_from = false;
+ return *this;
+ }
+};
+
+template<int N, template<typename> typename Wrapper>
+void
+test01()
+{
+ for (int n = 0; n < N+5; n++)
+ {
+ X x[N];
+ for (int i = 0; i < N; i++)
+ x[i] = X(i);
+ test_range<X, Wrapper> rx(x);
+ auto [out,last] = std::ranges::shift_right(rx.begin(), rx.end(), n);
+ VERIFY( last == rx.end() );
+ if (n < N)
+ {
+ VERIFY( out.ptr == x+n );
+ for (int i = n; i < N; i++)
+ VERIFY( x[i].a == i-n );
+ for (int i = 0; i < std::min(n, N-n); i++)
+ VERIFY( x[i].moved_from );
+ for (int i = std::min(n, N-n); i < std::max(n, N-n); i++)
+ VERIFY( !x[i].moved_from );
+ }
+ else
+ {
+ VERIFY( out.ptr == x+N );
+ for (int i = 0; i < N; i++)
+ {
+ VERIFY( x[i].a == i );
+ VERIFY( !x[i].moved_from );
+ }
+ }
+ }
+}
+
+int
+main()
+{
+ test01<23, forward_iterator_wrapper>();
+ test01<23, bidirectional_iterator_wrapper>();
+ test01<23, random_access_iterator_wrapper>();
+
+ test01<24, forward_iterator_wrapper>();
+ test01<24, bidirectional_iterator_wrapper>();
+ test01<24, random_access_iterator_wrapper>();
+}
diff --git a/libstdc++-v3/testsuite/25_algorithms/shuffle/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/shuffle/constrained.cc
index d0977a2..4d63356 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,50 @@ 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);
+}
+
+struct non_default_sentinel_t { };
+
+template<std::input_or_output_iterator I>
+bool operator==(const I& i, non_default_sentinel_t)
+{ return i == std::default_sentinel; }
+
+void
+test03()
+{
+ // PR libstdc++/121917 - ranges::shuffle incorrectly requires its arguments
+ // to model sized_sentinel_for
+ int a[2]{};
+ std::counted_iterator iter(a, 2);
+ std::default_random_engine e;
+ std::ranges::shuffle(iter, non_default_sentinel_t{}, e);
+}
+
int
main()
{
test01();
+ test02();
+ test03();
}
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/25_algorithms/upper_bound/debug/constexpr_partitioned_neg.cc b/libstdc++-v3/testsuite/25_algorithms/upper_bound/debug/constexpr_partitioned_neg.cc
index ffe5d77..950d432 100644
--- a/libstdc++-v3/testsuite/25_algorithms/upper_bound/debug/constexpr_partitioned_neg.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/upper_bound/debug/constexpr_partitioned_neg.cc
@@ -43,4 +43,4 @@ test()
static_assert(test()); // { dg-error "" }
-// { dg-prune-output "_Error_formatter::_M_error()" }
+// { dg-prune-output "_Error_formatter::(_M_error|_S_at)" }
diff --git a/libstdc++-v3/testsuite/25_algorithms/upper_bound/debug/constexpr_partitioned_pred_neg.cc b/libstdc++-v3/testsuite/25_algorithms/upper_bound/debug/constexpr_partitioned_pred_neg.cc
index a1c2ce6..41eb00c 100644
--- a/libstdc++-v3/testsuite/25_algorithms/upper_bound/debug/constexpr_partitioned_pred_neg.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/upper_bound/debug/constexpr_partitioned_pred_neg.cc
@@ -33,4 +33,4 @@ test()
static_assert(test()); // { dg-error "" }
-// { dg-prune-output "_Error_formatter::_M_error()" }
+// { dg-prune-output "_Error_formatter::(_M_error|_S_at)" }
diff --git a/libstdc++-v3/testsuite/25_algorithms/upper_bound/debug/constexpr_valid_range_neg.cc b/libstdc++-v3/testsuite/25_algorithms/upper_bound/debug/constexpr_valid_range_neg.cc
index c7c9e3b..032c8d3 100644
--- a/libstdc++-v3/testsuite/25_algorithms/upper_bound/debug/constexpr_valid_range_neg.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/upper_bound/debug/constexpr_valid_range_neg.cc
@@ -46,4 +46,4 @@ test2()
static_assert(test2()); // { dg-error "" }
-// { dg-prune-output "_Error_formatter::_M_error()" }
+// { dg-prune-output "_Error_formatter::(_M_error|_S_at)" }
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/philox4x32.cc b/libstdc++-v3/testsuite/26_numerics/random/philox4x32.cc
new file mode 100644
index 0000000..33842bb
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/random/philox4x32.cc
@@ -0,0 +1,26 @@
+// { dg-do run { target c++26 } }
+// { dg-require-cpp-feature-test __cpp_lib_philox_engine }
+
+// N5014 29.5.6 Engines and engine adaptors with predefined parameters
+
+#include <random>
+#include <testsuite_hooks.h>
+
+using test_type = std::philox_engine<std::uint_fast32_t, 32, 4, 10,
+ 0xCD9E8D57, 0x9E3779B9,
+ 0xD2511F53, 0xBB67AE85>;
+static_assert( std::is_same_v<test_type, std::philox4x32> );
+
+void
+test01()
+{
+ std::philox4x32 a;
+ a.discard(9999);
+
+ VERIFY( a() == 1955073260 );
+}
+
+int main()
+{
+ test01();
+}
diff --git a/libstdc++-v3/testsuite/26_numerics/random/philox4x64.cc b/libstdc++-v3/testsuite/26_numerics/random/philox4x64.cc
new file mode 100644
index 0000000..11a5691
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/random/philox4x64.cc
@@ -0,0 +1,26 @@
+// { dg-do run { target c++26 } }
+// { dg-require-cpp-feature-test __cpp_lib_philox_engine }
+
+// N5014 29.5.6 Engines and engine adaptors with predefined parameters
+
+#include <random>
+#include <testsuite_hooks.h>
+
+using test_type = std::philox_engine<std::uint_fast64_t, 64, 4, 10,
+ 0xCA5A826395121157, 0x9E3779B97F4A7C15,
+ 0xD2E7470EE14C6C93, 0xBB67AE8584CAA73B>;
+static_assert( std::is_same_v<test_type, std::philox4x64> );
+
+void
+test01()
+{
+ std::philox4x64 a;
+ a.discard(9999);
+
+ VERIFY( a() == 3409172418970261260 );
+}
+
+int main()
+{
+ test01();
+}
diff --git a/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/copy.cc b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/copy.cc
new file mode 100644
index 0000000..163aec0
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/copy.cc
@@ -0,0 +1,27 @@
+// { dg-do run { target c++26 } }
+// { dg-require-cpp-feature-test __cpp_lib_philox_engine }
+
+// N5014 29.5.4 Random Number Engine Class Templates
+// N5014 29.5.4.5 Class Template philox_engine
+
+#include <random>
+#include <testsuite_hooks.h>
+
+void
+test01(unsigned long seed)
+{
+
+ std::philox_engine<std::uint_fast32_t, 32, 4, 10, 0xCD9E8D57,
+ 0x9E3779B9, 0xD2511F53, 0xBB67AE85> e(seed);
+
+ const auto f(e);
+ VERIFY( f == e );
+ auto g(f);
+ VERIFY( g == f );
+}
+
+int main()
+{
+ test01(1ul);
+ test01(111ul);
+}
diff --git a/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/default.cc b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/default.cc
new file mode 100644
index 0000000..183ca82
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/default.cc
@@ -0,0 +1,49 @@
+// { dg-do run { target c++26 } }
+// { dg-require-cpp-feature-test __cpp_lib_philox_engine }
+
+// N5014 29.5.4.5 Class Template philox_engine
+
+#include <random>
+#include <testsuite_hooks.h>
+
+void
+test_default_ctor()
+{
+ std::philox_engine<std::uint_fast32_t,
+ 32, 4, 10, 0xCD9E8D57,
+ 0x9E3779B9, 0xD2511F53,
+ 0xBB67AE85> philox4x32nullkey(0);
+
+ VERIFY( philox4x32nullkey.min() == 0 );
+ VERIFY( philox4x32nullkey.max() == (1ul << 31 | (1ul << 31) - 1) );
+ VERIFY( philox4x32nullkey() == 0x6627e8d5ul );
+}
+
+void
+test_seed()
+{
+ unsigned long seed = 2;
+ std::philox4x32 seeded(seed);
+
+ std::philox4x32 default_init;
+ VERIFY( seeded != default_init );
+
+ std::philox4x32 default_seeded(std::philox4x32::default_seed);
+ VERIFY( default_seeded == default_init );
+}
+
+void
+test_seed_seq()
+{
+ std::seed_seq sseq{ 1, 2, 3, 4 };
+ std::philox4x32 seeded(sseq);
+ std::philox4x32 default_init;
+ VERIFY( seeded != default_init );
+}
+
+int main()
+{
+ test_default_ctor();
+ test_seed();
+ test_seed_seq();
+}
diff --git a/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/seed.cc b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/seed.cc
new file mode 100644
index 0000000..2b667b2
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/cons/seed.cc
@@ -0,0 +1,51 @@
+// { dg-do run { target c++26 } }
+// { dg-require-cpp-feature-test __cpp_lib_philox_engine }
+
+#include <random>
+#include <testsuite_hooks.h>
+
+int f(int x)
+{
+ std::seed_seq sq(&x, &x + 1);
+ auto rnd = std::philox4x32(sq);
+ return std::uniform_int_distribution<int>()(rnd);
+}
+
+int g(int x)
+{
+ std::seed_seq sq(&x, &x + 1);
+ auto rnd = std::philox4x32();
+ rnd.seed(sq);
+ return std::uniform_int_distribution<int>()(rnd);
+}
+
+void
+test01()
+{
+ const int f1 = f(0);
+ const int f2 = f(0);
+
+ const int g1 = g(0);
+ const int g2 = g(0);
+
+ VERIFY( f1 == f2 );
+ VERIFY( g1 == g2 );
+ VERIFY( f1 == g1 );
+}
+
+void
+test02()
+{
+ std::philox4x64 e1(25);
+ std::philox4x64 e2;
+ VERIFY( e2 != e1 );
+ e2.seed(25);
+ VERIFY( e2 == e1 );
+
+}
+
+int main()
+{
+ test01();
+ test02();
+}
diff --git a/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/equal.cc b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/equal.cc
new file mode 100644
index 0000000..cca1654
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/equal.cc
@@ -0,0 +1,33 @@
+// { dg-do run { target c++26 } }
+// { dg-require-cpp-feature-test __cpp_lib_philox_engine }
+
+// N5014 29.5.4.5 Class Template philox_engine
+
+#include <random>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+ std::philox_engine<std::uint_fast32_t,
+ 32, 4, 10, 0xCD9E8D57,
+ 0x9E3779B9, 0xD2511F53,
+ 0xBB67AE85> x, y;
+
+ VERIFY ( x == y);
+ x.discard(100);
+ y.discard(100);
+
+ VERIFY (x == y);
+
+ x.discard(2);
+ VERIFY (x != y);
+ y.discard(2);
+ VERIFY (x == y);
+}
+
+int
+main()
+{
+ test01();
+}
diff --git a/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/serialize.cc b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/serialize.cc
new file mode 100644
index 0000000..4bd40e7
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/operators/serialize.cc
@@ -0,0 +1,46 @@
+// { dg-do run { target c++26 } }
+// { dg-require-cpp-feature-test __cpp_lib_philox_engine }
+
+// N5014 29.5.4.5 Class Template philox_engine
+
+#include <sstream>
+#include <random>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+ std::stringstream str;
+ std::philox_engine<std::uint_fast32_t,
+ 32, 4, 10, 0xCD9E8D57,
+ 0x9E3779B9, 0xD2511F53,
+ 0xBB67AE85> x, y;
+
+ x();
+ str << x;
+
+ VERIFY ( !(x == y) );
+ str >> y;
+ VERIFY ( x == y );
+ for (unsigned long i = 0; i < 100; ++i)
+ {
+ VERIFY (x() == y());
+ }
+ str.clear();
+ str << y;
+ x();
+ x();
+ x();
+ str >> x;
+ VERIFY ( x == y );
+ for (unsigned long i = 0; i < 1000; ++i)
+ {
+ VERIFY (x() == y());
+ }
+}
+
+int
+main()
+{
+ test01();
+}
diff --git a/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constants.cc b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constants.cc
new file mode 100644
index 0000000..a3cb24e
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/constants.cc
@@ -0,0 +1,48 @@
+// { dg-do compile { target c++26 } }
+// { dg-require-cpp-feature-test __cpp_lib_philox_engine }
+
+// N5014 29.5.4.5 Class Template philox_engine
+
+#include <random>
+
+namespace test1
+{
+ using P = std::philox_engine<std::uint32_t, 32, 4, 5, 9, 99, 999, 9999>;
+ constexpr std::same_as<std::uint32_t> auto min = P::min();
+ static_assert( min == 0 );
+ constexpr std::same_as<std::uint32_t> auto max = P::max();
+ static_assert( max == 0xffffffff );
+ constexpr std::same_as<std::size_t> auto w = P::word_size;
+ static_assert( w == 32 );
+ constexpr std::same_as<std::size_t> auto n = P::word_count;
+ static_assert( n == 4 );
+ constexpr std::same_as<std::size_t> auto r = P::round_count;
+ static_assert( r == 5 );
+ constexpr std::array<std::uint32_t, 2> muls = P::multipliers;
+ static_assert( muls[0] == 9 && muls[1] == 999 );
+ constexpr std::array<std::uint32_t, 2> consts = P::round_consts;
+ static_assert( consts[0] == 99 && consts[1] == 9999 );
+ constexpr std::same_as<std::uint32_t> auto def = P::default_seed;
+ static_assert( def == 20111115u );
+}
+
+namespace test2
+{
+ using P = std::philox_engine<std::uint64_t, 64, 2, 12, 77, 777>;
+ constexpr std::same_as<std::uint64_t> auto min = P::min();
+ static_assert( min == 0 );
+ constexpr std::same_as<std::uint64_t> auto max = P::max();
+ static_assert( max == 0xffffffffffffffff );
+ constexpr std::same_as<std::size_t> auto w = P::word_size;
+ static_assert( w == 64 );
+ constexpr std::same_as<std::size_t> auto n = P::word_count;
+ static_assert( n == 2 );
+ constexpr std::same_as<std::size_t> auto r = P::round_count;
+ static_assert( r == 12 );
+ constexpr std::array<std::uint64_t, 1> muls = P::multipliers;
+ static_assert( muls[0] == 77 );
+ constexpr std::array<std::uint64_t, 1> consts = P::round_consts;
+ static_assert( consts[0] == 777 );
+ constexpr std::same_as<std::uint64_t> auto def = P::default_seed;
+ static_assert( def == 20111115u );
+}
diff --git a/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/typedefs.cc b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/typedefs.cc
new file mode 100644
index 0000000..1fc8fed
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/random/philox_engine/requirements/typedefs.cc
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++26 } }
+// { dg-require-cpp-feature-test __cpp_lib_philox_engine }
+
+// N5014 29.5.4.5 Class Template philox_engine
+
+#include <random>
+
+void
+test01()
+{
+ typedef std::philox_engine<std::uint_fast32_t,
+ 32, 4, 10, 0xCD9E8D57,
+ 0x9E3779B9, 0xD2511F53,
+ 0xBB67AE85> testType;
+
+ typedef testType::result_type result_type;
+ static_assert( std::is_same_v<result_type, std::uint_fast32_t> );
+}
+
+void
+test02()
+{
+ typedef std::philox_engine<std::uint_fast64_t,
+ 64, 4, 10, 0xCA5A826395121157,
+ 0x9E3779B97F4A7C15, 0xD2E7470EE14C6C93,
+ 0xBB67AE8584CAA73B> testType;
+
+ typedef testType::result_type result_type;
+ static_assert( std::is_same_v<result_type, std::uint_fast64_t> );
+}
diff --git a/libstdc++-v3/testsuite/26_numerics/random/piecewise_linear_distribution/cons/122062.cc b/libstdc++-v3/testsuite/26_numerics/random/piecewise_linear_distribution/cons/122062.cc
new file mode 100644
index 0000000..0f0caa7
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/random/piecewise_linear_distribution/cons/122062.cc
@@ -0,0 +1,16 @@
+// { dg-do compile { target c++11 } }
+
+// PR libstdc++/122062
+// piecewise_linear_distribution(firstB, lastB, firstW) invokes comma operator
+
+#include <random>
+#include <testsuite_iterators.h>
+
+void
+test_pr122062()
+{
+ double b[1]{};
+ double w[1]{};
+ __gnu_test::random_access_container<double> B(b), W(w);
+ std::piecewise_linear_distribution<double> p(B.begin(), B.end(), W.begin());
+}
diff --git a/libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc b/libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc
index 3c5aa7f..4b36f75 100644
--- a/libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc
+++ b/libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc
@@ -10,6 +10,6 @@ std::__detail::_Adaptor<std::mt19937, unsigned long> aurng(urng);
auto x = std::generate_canonical<std::size_t,
std::numeric_limits<std::size_t>::digits>(urng);
-// { 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 *-*-* } 271 }
-// { 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 *-*-* } 3480 }
diff --git a/libstdc++-v3/testsuite/26_numerics/saturation/extended.cc b/libstdc++-v3/testsuite/26_numerics/saturation/extended.cc
new file mode 100644
index 0000000..fbef628
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/saturation/extended.cc
@@ -0,0 +1,55 @@
+// { dg-do compile { target c++26 } }
+
+#include <numeric>
+#include <limits>
+
+template<typename T>
+constexpr bool
+test()
+{
+ using S = std::make_signed_t<T>;
+ using U = std::make_unsigned_t<T>;
+
+ constexpr S smax = std::numeric_limits<S>::max();
+ constexpr S smin = std::numeric_limits<S>::min();
+ constexpr U umax = std::numeric_limits<U>::max();
+
+ static_assert( std::add_sat(smax, (S)1) == smax );
+ static_assert( std::add_sat(smin, (S)-2) == smin );
+ static_assert( std::add_sat(umax, (U)3) == umax );
+
+ static_assert( std::sub_sat(smax, (S)-1) == smax );
+ static_assert( std::sub_sat(smin, (S)2) == smin );
+ static_assert( std::sub_sat((U)0, (U)3) == (U)0 );
+
+ static_assert( std::mul_sat((S)(smax >> 1), (S)3) == smax );
+ static_assert( std::mul_sat((S)(smin >> 1), (S)5) == smin );
+ static_assert( std::mul_sat((U)(umax >> 1), (U)7) == umax );
+
+ static_assert( std::div_sat(smax, (S)2) == (smax >> 1) );
+ static_assert( std::div_sat(smin, (S)4) == (smin >> 2) );
+ static_assert( std::div_sat(smin, (S)-1) == smax );
+ static_assert( std::div_sat(umax, (U)8) == (umax >> 3) );
+
+ return true;
+}
+
+#ifdef __SIZEOF_INT128__
+static_assert(test<__int128>());
+#endif
+
+#ifdef __GLIBCXX_TYPE_INT_N_0
+static_assert(test<__GLIBCXX_TYPE_INT_N_0>());
+#endif
+
+#ifdef __GLIBCXX_TYPE_INT_N_1
+static_assert(test<__GLIBCXX_TYPE_INT_N_1>());
+#endif
+
+#ifdef __GLIBCXX_TYPE_INT_N_2
+static_assert(test<__GLIBCXX_TYPE_INT_N_2>());
+#endif
+
+#ifdef __GLIBCXX_TYPE_INT_N_3
+static_assert(test<__GLIBCXX_TYPE_INT_N_3>());
+#endif
diff --git a/libstdc++-v3/testsuite/26_numerics/stdckdint/extended.cc b/libstdc++-v3/testsuite/26_numerics/stdckdint/extended.cc
new file mode 100644
index 0000000..efc0792
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/stdckdint/extended.cc
@@ -0,0 +1,65 @@
+// { dg-do run { target c++26 } }
+
+#include <stdckdint.h>
+#include <limits>
+#include <testsuite_hooks.h>
+
+template<typename T>
+void
+test()
+{
+ using S = std::make_signed_t<T>;
+ using U = std::make_unsigned_t<T>;
+
+ constexpr S smax = std::numeric_limits<S>::max();
+ constexpr S smin = std::numeric_limits<S>::min();
+ constexpr U umax = std::numeric_limits<U>::max();
+ S sout{};
+ U uout{};
+
+ VERIFY( ckd_add(&sout, smax, (S)1) );
+ VERIFY( ! ckd_add(&uout, smax, (U)1) && uout == ((U)smax + (U)1) );
+ VERIFY( ! ckd_add(&sout, smin, (S)99) && sout == (smin + 99) );
+ VERIFY( ckd_add(&uout, smin, (S)99) );
+ VERIFY( ckd_add(&sout, smin, (S)-2) );
+ VERIFY( ckd_add(&uout, umax, (U)3) );
+ VERIFY( ! ckd_add(&sout, (U)9, (U)3) && sout == 12 );
+
+ VERIFY( ckd_sub(&sout, smax, (S)-1) );
+ VERIFY( ! ckd_sub(&uout, smax, (S)-1) && uout == ((U)smax + (U)1) );
+ VERIFY( ckd_sub(&sout, smin, (S)2) );
+ VERIFY( ! ckd_sub(&sout, smin, (S)-2) && sout == (smin + 2) );
+ VERIFY( ! ckd_sub(&sout, (U)0, (U)3) && sout == -3 );
+ VERIFY( ckd_sub(&uout, (U)0, (U)3) );
+
+ VERIFY( ! ckd_mul(&sout, (S)(smax >> 2), (S)3) && sout == (smax/4*3) );
+ VERIFY( ckd_mul(&sout, (S)(smax >> 1), (S)3) );
+ VERIFY( ! ckd_mul(&uout, (S)(smax >> 1), (S)3) );
+ VERIFY( ckd_mul(&sout, (S)(smin >> 1), (S)5) );
+ VERIFY( ! ckd_mul(&uout, (U)(umax >> 2), (U)3) );
+ VERIFY( ckd_mul(&sout, (U)(umax >> 2), (U)3) );
+ VERIFY( ckd_mul(&uout, (U)(umax >> 1), (U)7) );
+}
+
+int main()
+{
+#ifdef __SIZEOF_INT128__
+ test<__int128>();
+#endif
+
+#ifdef __GLIBCXX_TYPE_INT_N_0
+ test<__GLIBCXX_TYPE_INT_N_0>();
+#endif
+
+#ifdef __GLIBCXX_TYPE_INT_N_1
+ test<__GLIBCXX_TYPE_INT_N_1>();
+#endif
+
+#ifdef __GLIBCXX_TYPE_INT_N_2
+ test<__GLIBCXX_TYPE_INT_N_2>();
+#endif
+
+#ifdef __GLIBCXX_TYPE_INT_N_3
+ test<__GLIBCXX_TYPE_INT_N_3>();
+#endif
+}
diff --git a/libstdc++-v3/testsuite/26_numerics/valarray/108951.cc b/libstdc++-v3/testsuite/26_numerics/valarray/108951.cc
new file mode 100644
index 0000000..929a1d4
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/valarray/108951.cc
@@ -0,0 +1,22 @@
+// { dg-do run { target c++11 } }
+// { dg-additional-options "-faligned-new" { target c++14_down } }
+
+#include <valarray>
+#include <cstdint>
+#include <testsuite_hooks.h>
+
+struct alignas(64) Num
+{
+ Num()
+ {
+ VERIFY(reinterpret_cast<std::uintptr_t>(this) % alignof(*this) == 0);
+ }
+
+ double val{};
+};
+
+int main()
+{
+ std::valarray<Num> v(2);
+ v.resize(4, {});
+}
diff --git a/libstdc++-v3/testsuite/27_io/basic_filebuf/seekoff/wchar_t/9875_seekoff.cc b/libstdc++-v3/testsuite/27_io/basic_filebuf/seekoff/wchar_t/9875_seekoff.cc
index 052d80f..474a49f 100644
--- a/libstdc++-v3/testsuite/27_io/basic_filebuf/seekoff/wchar_t/9875_seekoff.cc
+++ b/libstdc++-v3/testsuite/27_io/basic_filebuf/seekoff/wchar_t/9875_seekoff.cc
@@ -66,7 +66,7 @@ protected:
virtual int
do_length(std::mbstate_t&, const char* from, const char* end,
- std::size_t max)
+ std::size_t max) const
{
std::size_t len = (end - from) / sizeof(wchar_t);
return std::min(len, max) * sizeof(wchar_t);
diff --git a/libstdc++-v3/testsuite/27_io/basic_filebuf/seekpos/wchar_t/9875_seekpos.cc b/libstdc++-v3/testsuite/27_io/basic_filebuf/seekpos/wchar_t/9875_seekpos.cc
index 5767f8a..f0d3b59 100644
--- a/libstdc++-v3/testsuite/27_io/basic_filebuf/seekpos/wchar_t/9875_seekpos.cc
+++ b/libstdc++-v3/testsuite/27_io/basic_filebuf/seekpos/wchar_t/9875_seekpos.cc
@@ -66,7 +66,7 @@ protected:
virtual int
do_length(std::mbstate_t&, const char* from, const char* end,
- std::size_t max)
+ std::size_t max) const
{
std::size_t len = (end - from) / sizeof(wchar_t);
return std::min(len, max) * sizeof(wchar_t);
diff --git a/libstdc++-v3/testsuite/27_io/basic_filebuf/underflow/char/1.cc b/libstdc++-v3/testsuite/27_io/basic_filebuf/underflow/char/1.cc
index a0396a4..6d4c71f 100644
--- a/libstdc++-v3/testsuite/27_io/basic_filebuf/underflow/char/1.cc
+++ b/libstdc++-v3/testsuite/27_io/basic_filebuf/underflow/char/1.cc
@@ -35,7 +35,7 @@ protected:
virtual result
do_in(state_type&, const char* from, const char*, const char*& from_next,
- char* to, char*, char*& to_next)
+ char* to, char*, char*& to_next) const
{
from_next = from;
to_next = to;
diff --git a/libstdc++-v3/testsuite/27_io/basic_filebuf/underflow/wchar_t/11603.cc b/libstdc++-v3/testsuite/27_io/basic_filebuf/underflow/wchar_t/11603.cc
index fcd95a9..c62ad02 100644
--- a/libstdc++-v3/testsuite/27_io/basic_filebuf/underflow/wchar_t/11603.cc
+++ b/libstdc++-v3/testsuite/27_io/basic_filebuf/underflow/wchar_t/11603.cc
@@ -119,7 +119,7 @@ protected:
{ return width; }
virtual int
- do_length(const StateT&, const extern_type* from,
+ do_length(StateT&, const extern_type* from,
const extern_type* end, size_t max) const
{
size_t len = std::min(max,
diff --git a/libstdc++-v3/testsuite/27_io/basic_istream/ignore/char/4.cc b/libstdc++-v3/testsuite/27_io/basic_istream/ignore/char/4.cc
new file mode 100644
index 0000000..6f0b643
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/basic_istream/ignore/char/4.cc
@@ -0,0 +1,22 @@
+// { dg-do run { target c++26 } }
+
+#include <istream>
+#include <sstream>
+#include <string>
+#include <testsuite_hooks.h>
+
+void test01() {
+ std::istringstream in("\xF0\x9F\xA4\xA1 Clown Face");
+ in.ignore(100, '\xA1');
+ VERIFY(in.gcount() == 4);
+ VERIFY(in.peek() == ' ');
+
+ std::string str;
+ in >> str;
+ VERIFY(str == "Clown");
+}
+
+int main() {
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/27_io/basic_istream/ignore/char/93672.cc b/libstdc++-v3/testsuite/27_io/basic_istream/ignore/char/93672.cc
index 9673748..608b794 100644
--- a/libstdc++-v3/testsuite/27_io/basic_istream/ignore/char/93672.cc
+++ b/libstdc++-v3/testsuite/27_io/basic_istream/ignore/char/93672.cc
@@ -20,9 +20,9 @@ test_pr93672() // std::basic_istream::ignore hangs if delim MSB is set
VERIFY( in.gcount() == 3 );
VERIFY( ! in.eof() );
- // This only works if char is unsigned.
+ // Prior to C++26 (P3223R2), this only works if char is unsigned.
in.ignore(100, '\xfe');
- if (std::numeric_limits<char>::is_signed)
+ if (std::numeric_limits<char>::is_signed && __cplusplus <= 202302L)
{
// When char is signed, '\xfe' != traits_type::to_int_type('\xfe')
// so the delimiter does not match the character in the input sequence,
@@ -69,9 +69,9 @@ test_primary_template()
VERIFY( in.gcount() == 3 );
VERIFY( ! in.eof() );
- // This only works if char is unsigned.
+ // Prior to C++26 (P3223R2), this only works if char is unsigned.
in.ignore(100, '\xfe');
- if (std::numeric_limits<char>::is_signed)
+ if (std::numeric_limits<char>::is_signed && __cplusplus <= 202302L)
{
// When char is signed, '\xfe' != traits_type::to_int_type('\xfe')
// so the delimiter does not match the character in the input sequence,
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/operations/rename.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/rename.cc
index 00e088a..fef2547 100644
--- a/libstdc++-v3/testsuite/27_io/filesystem/operations/rename.cc
+++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/rename.cc
@@ -170,10 +170,20 @@ test_directories()
fs::remove_all(dir, ec);
}
+void
+test_pr122726()
+{
+ std::error_code ec;
+ const auto nonesuch = __gnu_test::nonexistent_path();
+ fs::rename(nonesuch, "new-name", ec);
+ VERIFY( ec == std::make_error_code(std::errc::no_such_file_or_directory) );
+}
+
int
main()
{
test01();
test_symlinks();
test_directories();
+ test_pr122726();
}
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/27_io/ios_base/types/fmtflags/case_label.cc b/libstdc++-v3/testsuite/27_io/ios_base/types/fmtflags/case_label.cc
index c72e00f..6f0390b 100644
--- a/libstdc++-v3/testsuite/27_io/ios_base/types/fmtflags/case_label.cc
+++ b/libstdc++-v3/testsuite/27_io/ios_base/types/fmtflags/case_label.cc
@@ -68,12 +68,6 @@ case_labels(bitmask_type b)
break;
case std::ios_base::floatfield:
break;
- case std::_S_ios_fmtflags_end:
- break;
- case __INT_MAX__:
- break;
- case ~__INT_MAX__:
- break;
}
using underlying_type = std::underlying_type<bitmask_type>::type;
static_assert( sizeof(underlying_type) == sizeof(int),
diff --git a/libstdc++-v3/testsuite/27_io/ios_base/types/iostate/case_label.cc b/libstdc++-v3/testsuite/27_io/ios_base/types/iostate/case_label.cc
index 6a1dd90..410f746 100644
--- a/libstdc++-v3/testsuite/27_io/ios_base/types/iostate/case_label.cc
+++ b/libstdc++-v3/testsuite/27_io/ios_base/types/iostate/case_label.cc
@@ -40,12 +40,6 @@ case_labels(bitmask_type b)
break;
case std::ios_base::failbit:
break;
- case std::_S_ios_iostate_end:
- break;
- case __INT_MAX__:
- break;
- case ~__INT_MAX__:
- break;
}
using underlying_type = std::underlying_type<bitmask_type>::type;
static_assert( sizeof(underlying_type) == sizeof(int),
diff --git a/libstdc++-v3/testsuite/27_io/ios_base/types/openmode/case_label.cc b/libstdc++-v3/testsuite/27_io/ios_base/types/openmode/case_label.cc
index e132070..44b84a9 100644
--- a/libstdc++-v3/testsuite/27_io/ios_base/types/openmode/case_label.cc
+++ b/libstdc++-v3/testsuite/27_io/ios_base/types/openmode/case_label.cc
@@ -48,12 +48,6 @@ case_labels(bitmask_type b)
case std::ios_base::noreplace:
break;
#endif
- case std::_S_ios_openmode_end:
- break;
- case __INT_MAX__:
- break;
- case ~__INT_MAX__:
- break;
}
using underlying_type = std::underlying_type<bitmask_type>::type;
static_assert( sizeof(underlying_type) == sizeof(int),
diff --git a/libstdc++-v3/testsuite/27_io/ios_base/types/seekdir/case_label.cc b/libstdc++-v3/testsuite/27_io/ios_base/types/seekdir/case_label.cc
index c7b9817..2dd1560 100644
--- a/libstdc++-v3/testsuite/27_io/ios_base/types/seekdir/case_label.cc
+++ b/libstdc++-v3/testsuite/27_io/ios_base/types/seekdir/case_label.cc
@@ -38,7 +38,5 @@ case_labels(test_type b)
break;
case std::ios_base::end:
break;
- case std::_S_ios_fmtflags_end:
- break;
}
}
diff --git a/libstdc++-v3/testsuite/27_io/manipulators/extended/get_time/wchar_t/1.cc b/libstdc++-v3/testsuite/27_io/manipulators/extended/get_time/wchar_t/1.cc
index 0f37282..ee3e84d 100644
--- a/libstdc++-v3/testsuite/27_io/manipulators/extended/get_time/wchar_t/1.cc
+++ b/libstdc++-v3/testsuite/27_io/manipulators/extended/get_time/wchar_t/1.cc
@@ -36,8 +36,8 @@ void test01()
tm time1;
iss >> get_time(&time1, L"%H:%M:%S %Y");
VERIFY( static_cast<bool>(iss) );
- VERIFY(time1.tm_hour = 12);
- VERIFY(time1.tm_min = 1);
+ VERIFY(time1.tm_hour == 12);
+ VERIFY(time1.tm_min == 1);
VERIFY(time1.tm_sec == 30);
VERIFY(time1.tm_year == 71);
}
diff --git a/libstdc++-v3/testsuite/27_io/print/1.cc b/libstdc++-v3/testsuite/27_io/print/1.cc
index 2a74e50..58f1eb1 100644
--- a/libstdc++-v3/testsuite/27_io/print/1.cc
+++ b/libstdc++-v3/testsuite/27_io/print/1.cc
@@ -68,15 +68,22 @@ test_print_raw()
void
test_vprint_nonunicode()
{
- std::vprint_nonunicode("{0} in \xc0 {0} out\n",
+ std::vprint_nonunicode_buffered("{0} in \xc0 {0} out\n",
std::make_format_args("garbage"));
- // { dg-output "garbage in . garbage out" }
+ // { dg-output "garbage in . garbage out\r?\n" }
+ std::vprint_nonunicode_buffered(stdout, "{0} in \xc3 {0} out\n",
+ std::make_format_args("junk"));
+ // { dg-output "junk in . junk out\r?\n" }
+ std::vprint_nonunicode(stdout, "{0} in \xc2 {0} out\n",
+ std::make_format_args("trash"));
+ // { dg-output "trash in . trash out\r?\n" }
+
}
+#ifdef __cpp_exceptions
void
test_errors()
{
-#ifdef __cpp_exceptions
try
{
std::print(stdin, "{}", "nope");
@@ -85,9 +92,47 @@ test_errors()
catch (const std::system_error&)
{
}
-#endif
}
+struct ThrowOnFormat
+{};
+
+template<typename CharT>
+struct std::formatter<ThrowOnFormat, CharT>
+{
+ constexpr typename std::basic_format_parse_context<CharT>::iterator
+ parse(const std::basic_format_parse_context<CharT>& pc) const
+ { return pc.begin(); }
+
+ template<typename Out>
+ typename std::basic_format_context<Out, CharT>::iterator
+ format(ThrowOnFormat, const std::basic_format_context<Out, CharT>&) const
+ { throw ThrowOnFormat{}; }
+};
+
+void
+test_buffered()
+{
+ __gnu_test::scoped_file f;
+ FILE* strm = std::fopen(f.path.string().c_str(), "w");
+ VERIFY( strm );
+ try
+ {
+ std::string s = "Test";
+ ThrowOnFormat tf;
+ std::vprint_unicode_buffered(strm, "{} {} {} {}", std::make_format_args(s, s, s, tf));
+ VERIFY(false);
+ }
+ catch (ThrowOnFormat)
+ { }
+ std::fclose(strm);
+
+ std::ifstream in(f.path);
+ std::string txt(std::istreambuf_iterator<char>(in), {});
+ VERIFY( txt.empty() );
+}
+#endif
+
int main()
{
test_print_default();
@@ -96,5 +141,8 @@ int main()
test_println_file();
test_print_raw();
test_vprint_nonunicode();
+#ifdef __cpp_exceptions
test_errors();
+ test_buffered();
+#endif
}
diff --git a/libstdc++-v3/testsuite/28_regex/algorithms/regex_match/multiline.cc b/libstdc++-v3/testsuite/28_regex/algorithms/regex_match/multiline.cc
index a1982fc..f4b3cf0 100644
--- a/libstdc++-v3/testsuite/28_regex/algorithms/regex_match/multiline.cc
+++ b/libstdc++-v3/testsuite/28_regex/algorithms/regex_match/multiline.cc
@@ -27,11 +27,11 @@ test01()
VERIFY(std::regex_search("x\nab\nx", ml));
ml.assign("a$\n^b$\n^c", ECMAScript|__multiline);
- VERIFY( ml.flags() == ECMAScript|__multiline );
+ VERIFY( ml.flags() == (ECMAScript|__multiline) );
VERIFY( regex_search("a\nb\nc", ml) );
ml.assign("a$\n^b$\n^c", ECMAScript|__multiline|icase);
- VERIFY( ml.flags() == ECMAScript|__multiline|icase );
+ VERIFY( ml.flags() == (ECMAScript|__multiline|icase) );
VERIFY( regex_search("A\nB\nC", ml) );
}
diff --git a/libstdc++-v3/testsuite/28_regex/basic_regex/assign/wchar_t/pstring.cc b/libstdc++-v3/testsuite/28_regex/basic_regex/assign/wchar_t/pstring.cc
index 2e9dea1..91e5512 100644
--- a/libstdc++-v3/testsuite/28_regex/basic_regex/assign/wchar_t/pstring.cc
+++ b/libstdc++-v3/testsuite/28_regex/basic_regex/assign/wchar_t/pstring.cc
@@ -23,6 +23,7 @@
// [28.8.3] class template basic_regex assign()
#include <regex>
+#include <cwchar>
// Tests assign operation from a Pascal-style counted-string.
void test01()
@@ -31,7 +32,7 @@ void test01()
const wchar_t cs[] = L"aab";
test_type re;
- re.assign(cs, sizeof(cs)-1, std::regex_constants::basic);
+ re.assign(cs, std::wcslen(cs), std::regex_constants::basic);
}
int
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/lwg3220.cc b/libstdc++-v3/testsuite/29_atomics/atomic/lwg3220.cc
index 217db7c..a8b7851 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic/lwg3220.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/lwg3220.cc
@@ -1,4 +1,4 @@
-// { dg-options "-Wno-deprecated" }
+// { dg-options "-Wno-deprecated-declarations" }
// { dg-do compile { target c++11 } }
// std::shared_ptr is not freestanding.
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/operators/pointer_partial_void.cc b/libstdc++-v3/testsuite/29_atomics/atomic/operators/pointer_partial_void.cc
index e959418a1..1e2f71e 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic/operators/pointer_partial_void.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/operators/pointer_partial_void.cc
@@ -1,6 +1,7 @@
// { dg-do run { target { c++11_only || c++14_only } } }
// { dg-require-atomic-builtins "" }
// { dg-require-effective-target hosted }
+// { dg-additional-options "-Wsystem-headers" }
// Copyright (C) 2012-2025 Free Software Foundation, Inc.
//
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/requirements/types_neg.cc b/libstdc++-v3/testsuite/29_atomics/atomic/requirements/types_neg.cc
index 5aa3243..b910548 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic/requirements/types_neg.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/requirements/types_neg.cc
@@ -19,7 +19,10 @@
#include <atomic>
-std::atomic<const int> a; // { dg-error "here" }
+std::atomic<const int> ca; // { dg-error "here" }
+std::atomic<volatile int> va; // { dg-error "here" }
+std::atomic<const volatile int> cva; // { dg-error "here" }
+// { dg-error "assignment to read-only type" "" { target *-*-* } 0 }
struct MoveOnly
{
@@ -40,3 +43,4 @@ struct NoMove
std::atomic<NoMove> c; // { dg-error "here" }
// { dg-error "static assertion failed" "" { target *-*-* } 0 }
+// { dg-error "use of deleted function" "" { target *-*-* } 0 }
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/29_atomics/atomic_ref/address.cc b/libstdc++-v3/testsuite/29_atomics/atomic_ref/address.cc
new file mode 100644
index 0000000..e2eda50
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_ref/address.cc
@@ -0,0 +1,42 @@
+// { dg-do run { target c++26 } }
+// { dg-require-atomic-cmpxchg-word "" }
+// { dg-add-options libatomic }
+
+#include <atomic>
+#include <memory>
+#include <type_traits>
+
+#include <testsuite_hooks.h>
+
+template <typename T>
+void testAtomicRefAddress()
+{
+ T x(T(42));
+ const std::atomic_ref<T> a(x);
+
+ static_assert( noexcept(a.address()) );
+ static_assert( std::is_same_v<decltype(a.address()), T*> );
+ VERIFY( std::addressof(x) == a.address() );
+}
+
+template <typename T>
+void testAtomicRefAddressForCV()
+{
+ testAtomicRefAddress<T>();
+ testAtomicRefAddress<const T>();
+ if constexpr (std::atomic_ref<T>::is_always_lock_free)
+ {
+ testAtomicRefAddress<volatile T>();
+ testAtomicRefAddress<const volatile T>();
+ }
+}
+
+int
+main ()
+{
+ struct X { int c; };
+ testAtomicRefAddressForCV<X>();
+ testAtomicRefAddressForCV<int>();
+ testAtomicRefAddressForCV<float>();
+ testAtomicRefAddressForCV<char*>();
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_ref/bool.cc b/libstdc++-v3/testsuite/29_atomics/atomic_ref/bool.cc
index 4702932..76ba9fd 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic_ref/bool.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_ref/bool.cc
@@ -1,15 +1,89 @@
-// { dg-do compile { target c++20 } }
+// Copyright (C) 2019-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-require-atomic-cmpxchg-word "" }
+// { dg-add-options libatomic }
#include <atomic>
+#include <testsuite_hooks.h>
+#include <type_traits>
+
+template<typename T>
+using volatile_
+ = std::conditional_t<std::atomic_ref<T>::is_always_lock_free, volatile T, T>;
+
+void
+test01()
+{
+ bool value;
+ {
+ const auto mo = std::memory_order_relaxed;
+ std::atomic_ref<bool> a(value);
+ bool ok = a.is_lock_free();
+ if constexpr (std::atomic_ref<bool>::is_always_lock_free)
+ VERIFY( ok );
+ a = false;
+ VERIFY( !a.load() );
+ VERIFY( !a.load(mo) );
+ a.store(true);
+ VERIFY( a.load() );
+ auto v = a.exchange(false);
+ VERIFY( !a.load() );
+ VERIFY( v );
+ v = a.exchange(true, mo);
+ VERIFY( a.load() );
+ VERIFY( !v );
+
+ auto expected = a.load();
+ while (!a.compare_exchange_weak(expected, false, mo, mo))
+ { /* weak form can fail spuriously */ }
+ VERIFY( !a.load() );
+ VERIFY( expected );
+
+ ok = a.compare_exchange_strong(expected, true);
+ VERIFY( !ok && !a.load() && !expected );
+
+ ok = a.compare_exchange_strong(expected, true);
+ VERIFY( ok && a.load() && !expected );
+ }
+}
+
+void
+test02()
+{
+ bool b = false;
+ std::atomic_ref<bool> a0(b);
+ std::atomic_ref<bool> a1(b);
+ std::atomic_ref<const bool> a1c(b);
+ std::atomic_ref<volatile_<bool>> a1v(b);
+ std::atomic_ref<volatile_<const bool>> a1cv(b);
+ std::atomic_ref<bool> a2(a0);
+ b = true;
+ VERIFY( a1.load() );
+ VERIFY( a1c.load() );
+ VERIFY( a1v.load() );
+ VERIFY( a1cv.load() );
+ VERIFY( a2.load() );
+}
-template<class T> concept has_and = requires (T& a) { a &= false; };
-template<class T> concept has_or = requires (T& a) { a |= false; };
-template<class T> concept has_xor = requires (T& a) { a ^= false; };
-template<class T> concept has_fetch_add = requires (T& a) { a.fetch_add(true); };
-template<class T> concept has_fetch_sub = requires (T& a) { a.fetch_sub(true); };
-
-static_assert( not has_and<std::atomic_ref<bool>> );
-static_assert( not has_or<std::atomic_ref<bool>> );
-static_assert( not has_xor<std::atomic_ref<bool>> );
-static_assert( not has_fetch_add<std::atomic_ref<bool>> );
-static_assert( not has_fetch_sub<std::atomic_ref<bool>> );
+int
+main()
+{
+ test01();
+ test02();
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_ref/cv_qual.cc b/libstdc++-v3/testsuite/29_atomics/atomic_ref/cv_qual.cc
new file mode 100644
index 0000000..dfc6a55
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_ref/cv_qual.cc
@@ -0,0 +1,94 @@
+// Copyright (C) 2019-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-require-atomic-cmpxchg-word "" }
+// { dg-add-options libatomic }
+
+#include <atomic>
+#include <testsuite_hooks.h>
+
+struct X
+{
+ X() = default;
+ X(int i) : i(i) { }
+ int i;
+
+ friend bool
+ operator==(X, X) = default;
+};
+
+template<typename V>
+void
+test01(V v0, V v1)
+{
+ V value;
+
+ if constexpr (std::atomic_ref<V>::is_always_lock_free)
+ {
+ std::atomic_ref<volatile V> a(value);
+ VERIFY( a.is_lock_free() );
+
+ a = v0;
+ VERIFY( V(a) == v0 );
+ VERIFY( a.load() == v0 );
+
+ a.store(v1);
+ VERIFY( a.load() == v1 );
+
+ V last = a.exchange(v0);
+ VERIFY( a.load() == v0 );
+ VERIFY( last == v1 );
+
+ V expected = a.load();
+ while (!a.compare_exchange_weak(expected, v1))
+ { /* weak form can fail spuriously */ }
+ VERIFY( a.load() == v1 );
+ VERIFY( expected == v0 );
+
+ bool ok;
+ ok = a.compare_exchange_strong(expected, v0);
+ VERIFY( !ok && a.load() == v1 && expected == v1 );
+
+ ok = a.compare_exchange_strong(expected, v0);
+ VERIFY( ok && a.load() == v0 && expected == v1 );
+
+ std::atomic_ref<const volatile V> cva(value);
+ VERIFY( cva.is_lock_free() );
+ VERIFY( V(cva) == v0 );
+ VERIFY( cva.load() == v0 );
+ }
+
+ value = v0;
+ std::atomic_ref<const V> ca(value);
+ bool lf = ca.is_lock_free();
+ if constexpr (std::atomic_ref<V>::is_always_lock_free)
+ VERIFY( lf );
+ VERIFY( V(ca) == v0 );
+ VERIFY( ca.load() == v0 );
+}
+
+int
+main()
+{
+ int x;
+ test01<bool>(false, true);
+ test01<int>(1, 2);
+ test01<float>(1.2, 3.4);
+ test01<int*>(&x, &x+1);
+ test01<X>(12, 13);
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_ref/deduction.cc b/libstdc++-v3/testsuite/29_atomics/atomic_ref/deduction.cc
index f67190e..bfc2080 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic_ref/deduction.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_ref/deduction.cc
@@ -19,22 +19,32 @@
#include <atomic>
+template <typename T>
void
-test01()
+test_impl(T v)
{
- int i = 0;
- std::atomic_ref a0(i);
- static_assert(std::is_same_v<decltype(a0), std::atomic_ref<int>>);
-
- float f = 1.0f;
- std::atomic_ref a1(f);
- static_assert(std::is_same_v<decltype(a1), std::atomic_ref<float>>);
+ std::atomic_ref a(v);
+ static_assert(std::is_same_v<decltype(a), std::atomic_ref<T>>);
+}
- int* p = &i;
- std::atomic_ref a2(p);
- static_assert(std::is_same_v<decltype(a2), std::atomic_ref<int*>>);
+template <typename T>
+void
+test(T v)
+{
+ test_impl<T>(v);
+ test_impl<const T>(v);
+ if constexpr (std::atomic_ref<T>::is_always_lock_free)
+ {
+ test_impl<volatile T>(v);
+ test_impl<const volatile T>(v);
+ }
+}
+int main()
+{
+ test<int>(0);
+ test<float>(1.0f);
+ test<int*>(nullptr);
struct X { } x;
- std::atomic_ref a3(x);
- static_assert(std::is_same_v<decltype(a3), std::atomic_ref<X>>);
+ test<X>(x);
}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_ref/float.cc b/libstdc++-v3/testsuite/29_atomics/atomic_ref/float.cc
index 5773d14..5736668 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic_ref/float.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_ref/float.cc
@@ -19,6 +19,11 @@
#include <atomic>
#include <testsuite_hooks.h>
+#include <type_traits>
+
+template<typename T>
+using volatile_
+ = std::conditional_t<std::atomic_ref<T>::is_always_lock_free, volatile T, T>;
void
test01()
@@ -297,17 +302,19 @@ test03()
void
test04()
{
- if constexpr (std::atomic_ref<float>::is_always_lock_free)
- {
- float i = 0;
- float* ptr = 0;
- std::atomic_ref<float*> a0(ptr);
- std::atomic_ref<float*> a1(ptr);
- std::atomic_ref<float*> a2(a0);
- a0 = &i;
- VERIFY( a1 == &i );
- VERIFY( a2 == &i );
- }
+ float i = 0.0f;
+ std::atomic_ref<float> a0(i);
+ std::atomic_ref<float> a1(i);
+ std::atomic_ref<const float> a1c(i);
+ std::atomic_ref<volatile_<float>> a1v(i);
+ std::atomic_ref<volatile_<const float>> a1cv(i);
+ std::atomic_ref<float> a2(a0);
+ a0 = 1.0f;
+ VERIFY( a1 == 1.0f );
+ VERIFY( a1c == 1.0f );
+ VERIFY( a1v == 1.0f );
+ VERIFY( a1cv == 1.0f );
+ VERIFY( a2 == 1.0f );
}
int
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_ref/generic.cc b/libstdc++-v3/testsuite/29_atomics/atomic_ref/generic.cc
index 2e6fa0f..7bdecdd 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic_ref/generic.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_ref/generic.cc
@@ -22,6 +22,11 @@
#include <atomic>
#include <limits.h>
#include <testsuite_hooks.h>
+#include <type_traits>
+
+template<typename T>
+using volatile_
+ = std::conditional_t<std::atomic_ref<T>::is_always_lock_free, volatile T, T>;
struct X
{
@@ -108,9 +113,15 @@ test02()
X i;
std::atomic_ref<X> a0(i);
std::atomic_ref<X> a1(i);
+ std::atomic_ref<const X> a1c(i);
+ std::atomic_ref<volatile_<X>> a1v(i);
+ std::atomic_ref<volatile_<const X>> a1cv(i);
std::atomic_ref<X> a2(a0);
a0 = 42;
VERIFY( a1.load() == 42 );
+ VERIFY( a1c.load() == 42 );
+ VERIFY( a1v.load() == 42 );
+ VERIFY( a1cv.load() == 42 );
VERIFY( a2.load() == 42 );
}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_ref/integral.cc b/libstdc++-v3/testsuite/29_atomics/atomic_ref/integral.cc
index f6b68eb..010b40b 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic_ref/integral.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_ref/integral.cc
@@ -22,6 +22,11 @@
#include <atomic>
#include <limits.h>
#include <testsuite_hooks.h>
+#include <type_traits>
+
+template<typename T>
+using volatile_
+ = std::conditional_t<std::atomic_ref<T>::is_always_lock_free, volatile T, T>;
void
test01()
@@ -302,9 +307,15 @@ test03()
int i = 0;
std::atomic_ref<int> a0(i);
std::atomic_ref<int> a1(i);
+ std::atomic_ref<const int> a1c(i);
+ std::atomic_ref<volatile_<int>> a1v(i);
+ std::atomic_ref<volatile_<const int>> a1cv(i);
std::atomic_ref<int> a2(a0);
a0 = 42;
VERIFY( a1 == 42 );
+ VERIFY( a1c == 42 );
+ VERIFY( a1v == 42 );
+ VERIFY( a1cv == 42 );
VERIFY( a2 == 42 );
}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_ref/op_support.cc b/libstdc++-v3/testsuite/29_atomics/atomic_ref/op_support.cc
new file mode 100644
index 0000000..3afa0bb
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_ref/op_support.cc
@@ -0,0 +1,127 @@
+// { dg-do compile { target c++20 } }
+
+#include <atomic>
+
+template<typename T>
+concept is_supported
+ = !std::is_volatile_v<T>
+ || std::atomic_ref<std::remove_cv_t<T>>::is_always_lock_free;
+
+template<class T> concept has_and = requires (T& a) { a &= false; };
+template<class T> concept has_or = requires (T& a) { a |= false; };
+template<class T> concept has_xor = requires (T& a) { a ^= false; };
+template<class T> concept has_fetch_add = requires (T& a) { a.fetch_add(true); };
+template<class T> concept has_fetch_sub = requires (T& a) { a.fetch_sub(true); };
+
+static constexpr std::memory_order mo = std::memory_order_seq_cst;
+
+#define HAS(op) (requires (std::atomic_ref<T> a, T t) { op; })
+
+template<typename T>
+void
+no_stores()
+{
+ if constexpr (is_supported<T>)
+ {
+ static_assert( !HAS(a = t) );
+ static_assert( !HAS(a.store(t)) );
+ static_assert( !HAS(a.store(t, mo)) );
+ static_assert( !HAS(a.exchange(t)) );
+ static_assert( !HAS(a.exchange(t, mo)) );
+
+ static_assert( !HAS(a.compare_exchange_weak(t, t)) );
+ static_assert( !HAS(a.compare_exchange_weak(t, t, mo)) );
+ static_assert( !HAS(a.compare_exchange_weak(t, t, mo, mo)) );
+
+ static_assert( !HAS(a.compare_exchange_strong(t, t)) );
+ static_assert( !HAS(a.compare_exchange_strong(t, t, mo)) );
+ static_assert( !HAS(a.compare_exchange_strong(t, t, mo, mo)) );
+ }
+}
+
+template<typename T>
+void
+no_additions()
+{
+ if constexpr (is_supported<T>)
+ {
+ static_assert( !HAS(a++) );
+ static_assert( !HAS(++a) );
+ static_assert( !HAS(a += t) );
+ static_assert( !HAS(a.fetch_add(t)) );
+ static_assert( !HAS(a.fetch_add(t, mo)) );
+
+ static_assert( !HAS(a--) );
+ static_assert( !HAS(--a) );
+ static_assert( !HAS(a -= t) );
+ static_assert( !HAS(a.fetch_sub(t)) );
+ static_assert( !HAS(a.fetch_sub(t, mo)) );
+ }
+}
+
+template<typename T>
+void
+no_bitops()
+{
+ if constexpr (is_supported<T>)
+ {
+ static_assert( !HAS(a &= t) );
+ static_assert( !HAS(a.fetch_and(t)) );
+ static_assert( !HAS(a.fetch_and(t, mo)) );
+
+ static_assert( !HAS(a |= t) );
+ static_assert( !HAS(a.fetch_or(t)) );
+ static_assert( !HAS(a.fetch_or(t, mo)) );
+
+ static_assert( !HAS(a ^= t) );
+ static_assert( !HAS(a.fetch_xor(t)) );
+ static_assert( !HAS(a.fetch_xor(t, mo)) );
+ }
+}
+
+template<typename T>
+void
+no_math()
+{
+ no_additions<T>();
+ no_bitops<T>();
+}
+
+template<typename T>
+void
+no_mutations()
+{
+ no_stores<T>();
+ no_math<T>();
+}
+
+struct S
+{
+ int x;
+ int y;
+};
+
+int main()
+{
+ no_mutations<const int>();
+ no_mutations<const volatile int>();
+
+ no_bitops<float>();
+ no_bitops<volatile float>();
+ no_mutations<const float>();
+
+ no_bitops<int*>();
+ no_bitops<int* volatile>();
+ no_mutations<int* const>();
+ no_mutations<int* const volatile>();
+
+ no_math<bool>();
+ no_math<volatile bool>();
+ no_mutations<const bool>();
+ no_mutations<const volatile bool>();
+
+ no_math<S>();
+ no_math<volatile S>();
+ no_mutations<const S>();
+ no_mutations<const volatile S>();
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_ref/pointer.cc b/libstdc++-v3/testsuite/29_atomics/atomic_ref/pointer.cc
index d1789af..c503b33 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic_ref/pointer.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_ref/pointer.cc
@@ -21,6 +21,11 @@
#include <atomic>
#include <testsuite_hooks.h>
+#include <type_traits>
+
+template<typename T>
+using volatile_
+ = std::conditional_t<std::atomic_ref<T>::is_always_lock_free, volatile T, T>;
void
test01()
@@ -210,9 +215,15 @@ test03()
int* ptr = 0;
std::atomic_ref<int*> a0(ptr);
std::atomic_ref<int*> a1(ptr);
+ std::atomic_ref<int* const> a1c(ptr);
+ std::atomic_ref<volatile_<int*>> a1v(ptr);
+ std::atomic_ref<volatile_<int* const>> a1cv(ptr);
std::atomic_ref<int*> a2(a0);
a0 = &i;
VERIFY( a1 == &i );
+ VERIFY( a1c == &i );
+ VERIFY( a1v == &i );
+ VERIFY( a1cv == &i );
VERIFY( a2 == &i );
}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_ref/requirements.cc b/libstdc++-v3/testsuite/29_atomics/atomic_ref/requirements.cc
index 3b92956..5d67c77 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic_ref/requirements.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_ref/requirements.cc
@@ -18,56 +18,109 @@
// { dg-do compile { target c++20 } }
#include <atomic>
+#include <type_traits>
+template<typename T>
+concept is_supported
+ = !std::is_volatile_v<T>
+ || std::atomic_ref<std::remove_cv_t<T>>::is_always_lock_free;
+
+template <class T>
void
-test01()
+test_generic()
{
- struct X { int c; };
- using A = std::atomic_ref<X>;
- static_assert( std::is_standard_layout_v<A> );
- static_assert( std::is_nothrow_copy_constructible_v<A> );
- static_assert( std::is_trivially_destructible_v<A> );
- static_assert( std::is_same_v<A::value_type, X> );
- static_assert( !std::is_copy_assignable_v<A> );
- static_assert( !std::is_move_assignable_v<A> );
+ if constexpr (is_supported<T>)
+ {
+ using A = std::atomic_ref<T>;
+ static_assert( std::is_standard_layout_v<A> );
+ static_assert( std::is_nothrow_copy_constructible_v<A> );
+ static_assert( std::is_trivially_destructible_v<A> );
+ static_assert( std::is_same_v<typename A::value_type, std::remove_cv_t<T>> );
+ static_assert( !requires { typename A::difference_type; } );
+ static_assert( !std::is_copy_assignable_v<A> );
+ static_assert( !std::is_move_assignable_v<A> );
+ }
}
+template <class T>
void
-test02()
+test_integral()
{
- using A = std::atomic_ref<int>;
- static_assert( std::is_standard_layout_v<A> );
- static_assert( std::is_nothrow_copy_constructible_v<A> );
- static_assert( std::is_trivially_destructible_v<A> );
- static_assert( std::is_same_v<A::value_type, int> );
- static_assert( std::is_same_v<A::difference_type, A::value_type> );
- static_assert( !std::is_copy_assignable_v<A> );
- static_assert( !std::is_move_assignable_v<A> );
+ if constexpr (is_supported<T>)
+ {
+ using A = std::atomic_ref<T>;
+ static_assert( std::is_standard_layout_v<A> );
+ static_assert( std::is_nothrow_copy_constructible_v<A> );
+ static_assert( std::is_trivially_destructible_v<A> );
+ static_assert( std::is_same_v<typename A::value_type, std::remove_cv_t<T>> );
+ static_assert( std::is_same_v<typename A::difference_type, typename A::value_type> );
+ static_assert( !std::is_copy_assignable_v<A> );
+ static_assert( !std::is_move_assignable_v<A> );
+ }
}
+template <class T>
void
-test03()
+test_floating_point()
{
- using A = std::atomic_ref<double>;
- static_assert( std::is_standard_layout_v<A> );
- static_assert( std::is_nothrow_copy_constructible_v<A> );
- static_assert( std::is_trivially_destructible_v<A> );
- static_assert( std::is_same_v<A::value_type, double> );
- static_assert( std::is_same_v<A::difference_type, A::value_type> );
- static_assert( !std::is_copy_assignable_v<A> );
- static_assert( !std::is_move_assignable_v<A> );
+ if constexpr (is_supported<T>)
+ {
+ using A = std::atomic_ref<T>;
+ static_assert( std::is_standard_layout_v<A> );
+ static_assert( std::is_nothrow_copy_constructible_v<A> );
+ static_assert( std::is_trivially_destructible_v<A> );
+ static_assert( std::is_same_v<typename A::value_type, std::remove_cv_t<T>> );
+ static_assert( std::is_same_v<typename A::difference_type, typename A::value_type> );
+ static_assert( !std::is_copy_assignable_v<A> );
+ static_assert( !std::is_move_assignable_v<A> );
+ }
}
+template <class T>
void
-test04()
+test_pointer()
+{
+ if constexpr (is_supported<T>)
+ {
+ using A = std::atomic_ref<T>;
+ static_assert( std::is_standard_layout_v<A> );
+ static_assert( std::is_nothrow_copy_constructible_v<A> );
+ static_assert( std::is_trivially_destructible_v<A> );
+ static_assert( std::is_same_v<typename A::value_type, std::remove_cv_t<T>> );
+ static_assert( std::is_same_v<typename A::difference_type, std::ptrdiff_t> );
+ static_assert( std::is_nothrow_copy_constructible_v<A> );
+ static_assert( !std::is_copy_assignable_v<A> );
+ static_assert( !std::is_move_assignable_v<A> );
+ }
+}
+
+int
+main()
{
- using A = std::atomic_ref<int*>;
- static_assert( std::is_standard_layout_v<A> );
- static_assert( std::is_nothrow_copy_constructible_v<A> );
- static_assert( std::is_trivially_destructible_v<A> );
- static_assert( std::is_same_v<A::value_type, int*> );
- static_assert( std::is_same_v<A::difference_type, std::ptrdiff_t> );
- static_assert( std::is_nothrow_copy_constructible_v<A> );
- static_assert( !std::is_copy_assignable_v<A> );
- static_assert( !std::is_move_assignable_v<A> );
+ struct X { int c; };
+ test_generic<X>();
+ test_generic<const X>();
+ test_generic<volatile X>();
+ test_generic<const volatile X>();
+
+ // atomic_ref excludes (cv) `bool` from the set of integral types
+ test_generic<bool>();
+ test_generic<const bool>();
+ test_generic<volatile bool>();
+ test_generic<const volatile bool>();
+
+ test_integral<int>();
+ test_integral<const int>();
+ test_integral<volatile int>();
+ test_integral<const volatile int>();
+
+ test_floating_point<double>();
+ test_floating_point<const double>();
+ test_floating_point<volatile double>();
+ test_floating_point<const volatile double>();
+
+ test_pointer<int*>();
+ test_pointer<int* const>();
+ test_pointer<int* volatile>();
+ test_pointer<int* const volatile>();
}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_ref/requirements_neg.cc b/libstdc++-v3/testsuite/29_atomics/atomic_ref/requirements_neg.cc
new file mode 100644
index 0000000..8b0abbd
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_ref/requirements_neg.cc
@@ -0,0 +1,34 @@
+// { dg-do compile { target c++20 } }
+
+#include <atomic>
+
+template<size_t N>
+struct NonTrivial
+{
+ NonTrivial() = default;
+ NonTrivial(NonTrivial const&) { };
+};
+
+template<size_t N>
+NonTrivial<N> ntv;
+
+std::atomic_ref<NonTrivial<0>> nt(ntv<0>); // { dg-error "here" }
+std::atomic_ref<const NonTrivial<1>> cnt(ntv<1>); // { dg-error "here" }
+std::atomic_ref<volatile NonTrivial<2>> vnt(ntv<2>); // { dg-error "here" }
+std::atomic_ref<const volatile NonTrivial<3>> cvnt(ntv<3>); // { dg-error "here" }
+
+template<size_t N>
+struct NonLockFree
+{
+ char c[1024 + N];
+};
+
+template<size_t N>
+NonLockFree<N> nlfv;
+
+std::atomic_ref<NonLockFree<0>> nlf(nlfv<0>);
+std::atomic_ref<const NonLockFree<1>> cnlf(nlfv<1>);
+std::atomic_ref<volatile NonLockFree<2>> vnlf(nlfv<2>); // { dg-error "here" }
+std::atomic_ref<const volatile NonLockFree<3>> cvnlf(nlfv<3>); // { dg-error "here" }
+
+// { dg-error "static assertion failed" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_ref/wait_notify.cc b/libstdc++-v3/testsuite/29_atomics/atomic_ref/wait_notify.cc
index ecabeec..db20a19 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic_ref/wait_notify.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_ref/wait_notify.cc
@@ -41,6 +41,16 @@ template<typename S>
});
a.wait(va);
t.join();
+
+ std::atomic_ref<const S> b{ aa };
+ b.wait(va);
+ std::thread t2([&]
+ {
+ a.store(va);
+ a.notify_one();
+ });
+ b.wait(vb);
+ t2.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/condition_variable/members/116586.cc b/libstdc++-v3/testsuite/30_threads/condition_variable/members/116586.cc
new file mode 100644
index 0000000..e8c3e16
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/condition_variable/members/116586.cc
@@ -0,0 +1,63 @@
+// { dg-do run { target c++11 } }
+// { dg-additional-options "-pthread" { target pthread } }
+// { dg-require-gthreads "" }
+// { dg-require-effective-target hosted }
+
+#include <condition_variable>
+#include <chrono>
+#include <mutex>
+#include <initializer_list>
+#include <testsuite_hooks.h>
+
+namespace chrono = std::chrono;
+
+// thread.timedmutex.requirements.general:
+// If abs_time has already passed, the function attempts to obtain
+// ownership without blocking (as if by calling try_lock()).
+
+template <typename Clock>
+void
+test_absolute(chrono::nanoseconds offset)
+{
+ std::mutex mtx;
+ std::condition_variable cv;
+ chrono::time_point<Clock> tp(offset);
+ std::unique_lock<std::mutex> lock(mtx);
+ // Doesn't cope with spurious wakeup
+ VERIFY(cv.wait_until(lock, tp) == std::cv_status::timeout);
+}
+
+// The type of clock used for the actual wait depends on whether
+// _GLIBCXX_USE_PTHREAD_MUTEX_CLOCKLOCK is defined. We might as well just test
+// both steady_clock and system_clock.
+template <typename Clock>
+void
+test_relative(chrono::nanoseconds offset)
+{
+ std::mutex mtx;
+ std::condition_variable cv;
+ const auto d = -Clock::now().time_since_epoch() + offset;
+ std::unique_lock<std::mutex> lock(mtx);
+ // Doesn't cope with spurious wakeup
+ VERIFY(cv.wait_for(lock, d) == std::cv_status::timeout);
+}
+
+int main()
+{
+ // It's not really possible to arrange for the relative calls to have
+ // tv_nsec == 0 due to time advancing.
+ for (const chrono::nanoseconds offset : {
+ // tv_sec == 0, tv_nsec == 0
+ chrono::nanoseconds{0},
+ // tv_sec == 0, tv_nsec < 0
+ chrono::duration_cast<chrono::nanoseconds>(chrono::milliseconds{-10}),
+ // tv_sec < 0
+ chrono::duration_cast<chrono::nanoseconds>(chrono::seconds{-10})
+ }) {
+ test_absolute<chrono::system_clock>(offset);
+ test_relative<chrono::system_clock>(offset);
+
+ test_absolute<chrono::steady_clock>(offset);
+ test_relative<chrono::steady_clock>(offset);
+ }
+}
diff --git a/libstdc++-v3/testsuite/30_threads/future/members/116586.cc b/libstdc++-v3/testsuite/30_threads/future/members/116586.cc
new file mode 100644
index 0000000..82f1e5c
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/future/members/116586.cc
@@ -0,0 +1,58 @@
+// { dg-do run { target c++11 } }
+// { dg-additional-options "-pthread" { target pthread } }
+// { dg-require-gthreads "" }
+// { dg-require-effective-target hosted }
+
+#include <future>
+#include <chrono>
+#include <initializer_list>
+#include <testsuite_hooks.h>
+
+namespace chrono = std::chrono;
+
+// thread.timedmutex.requirements.general:
+// If abs_time has already passed, the function attempts to obtain
+// ownership without blocking (as if by calling try_lock()).
+
+template <typename Clock>
+void
+test_absolute(chrono::nanoseconds offset)
+{
+ std::promise<int> p;
+ std::future<int> f = p.get_future();
+ const chrono::time_point<Clock> tp(offset);
+ VERIFY(f.wait_until(tp) == std::future_status::timeout);
+}
+
+// The type of clock used for the actual wait depends on whether
+// _GLIBCXX_HAVE_LINUX_FUTEX is defined. We might as well just test both
+// steady_clock and system_clock.
+template <typename Clock>
+void
+test_relative(chrono::nanoseconds offset)
+{
+ std::promise<int> p;
+ std::future<int> f = p.get_future();
+ const auto d = -Clock::now().time_since_epoch() + offset;
+ VERIFY(f.wait_for(d) == std::future_status::timeout);
+}
+
+int main()
+{
+ // It's not really possible to arrange for the relative calls to have tv_nsec
+ // == 0 due to time advancing.
+ for (const chrono::nanoseconds offset : {
+ // tv_sec == 0, tv_nsec == 0
+ chrono::nanoseconds{0},
+ // tv_sec == 0, tv_nsec < 0
+ chrono::duration_cast<chrono::nanoseconds>(chrono::milliseconds{-10}),
+ // tv_sec < 0
+ chrono::duration_cast<chrono::nanoseconds>(chrono::seconds{-10})
+ }) {
+ test_absolute<chrono::system_clock>(offset);
+ test_relative<chrono::system_clock>(offset);
+
+ test_absolute<chrono::steady_clock>(offset);
+ test_relative<chrono::steady_clock>(offset);
+ }
+}
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..30e05b0 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
@@ -1,4 +1,5 @@
// { dg-do compile { target c++11 } }
+// { dg-additional-options "-Wsystem-headers" }
#include <future>
// C++20 [futures.task.members]
@@ -8,6 +9,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/recursive_timed_mutex/try_lock_until/116586.cc b/libstdc++-v3/testsuite/30_threads/recursive_timed_mutex/try_lock_until/116586.cc
new file mode 100644
index 0000000..25a78e7
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/recursive_timed_mutex/try_lock_until/116586.cc
@@ -0,0 +1,75 @@
+// { dg-do run { target c++11 } }
+// { dg-additional-options "-pthread" { target pthread } }
+// { dg-require-gthreads "" }
+// { dg-require-effective-target hosted }
+
+#include <mutex>
+#include <chrono>
+#include <future>
+#include <initializer_list>
+#include <testsuite_hooks.h>
+
+namespace chrono = std::chrono;
+
+// thread.timedmutex.requirements.general:
+// If abs_time has already passed, the function attempts to obtain
+// ownership without blocking (as if by calling try_lock()).
+
+template <typename Clock>
+void
+test_absolute(chrono::nanoseconds offset)
+{
+ std::recursive_timed_mutex mtx;
+ chrono::time_point<Clock> tp(offset);
+ VERIFY(mtx.try_lock_until(tp));
+
+ {
+ // To test failing to lock a recursive mutex we need to try to lock on a
+ // different thread.
+ auto t = std::async(std::launch::async, [&mtx, tp]() {
+ VERIFY(!mtx.try_lock_until(tp));
+ });
+ }
+}
+
+// The type of clock used for the actual wait depends on whether
+// _GLIBCXX_USE_PTHREAD_MUTEX_CLOCKLOCK is defined. We might as well just test
+// both steady_clock and system_clock.
+template <typename Clock>
+void
+test_relative(chrono::nanoseconds offset)
+{
+ std::recursive_timed_mutex mtx;
+ const auto d = -Clock::now().time_since_epoch() + offset;
+ VERIFY(mtx.try_lock_for(d));
+
+ {
+ // To test failing to lock a recursive mutex we need to try to lock on a
+ // different thread.
+ auto t = std::async(std::launch::async, [&mtx, d]() {
+ VERIFY(!mtx.try_lock_for(d));
+ });
+ }
+}
+
+int main()
+{
+ // Try once with an offset that ought to result in tv_sec == 0, tv_nsec < 0
+ // and one with an offset that ought to result in tv_sec < 0, tv_nsec == 0
+ // for the absolute calls at least. It's not really possible to arrange for
+ // the relative calls to have tv_nsec == 0 due to time advancing.
+ for (const chrono::nanoseconds offset : {
+ // tv_sec == 0, tv_nsec == 0
+ chrono::nanoseconds{0},
+ // tv_sec == 0, tv_nsec < 0
+ chrono::duration_cast<chrono::nanoseconds>(chrono::milliseconds{-10}),
+ // tv_sec < 0
+ chrono::duration_cast<chrono::nanoseconds>(chrono::seconds{-10})
+ }) {
+ test_absolute<chrono::system_clock>(offset);
+ test_relative<chrono::system_clock>(offset);
+
+ test_absolute<chrono::steady_clock>(offset);
+ test_relative<chrono::steady_clock>(offset);
+ }
+}
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.cc b/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value.cc
new file mode 100644
index 0000000..67fa125
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/least_max_value.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>
+
+std::counting_semaphore<> sem(0);
+std::counting_semaphore<> sem2(2);
+std::counting_semaphore sem3(3);
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_for.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
index 39681c7..94acb25 100644
--- a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_for.cc
@@ -24,6 +24,7 @@
#include <chrono>
#include <thread>
#include <atomic>
+#include <initializer_list>
#include <testsuite_hooks.h>
void test01()
@@ -90,9 +91,30 @@ test03()
s.try_acquire_for(timeout);
}
+// Prove semaphore doesn't suffer from PR116586
+template <typename Clock>
+void
+test_relative(std::chrono::nanoseconds offset)
+{
+ std::binary_semaphore sem(1);
+ VERIFY(sem.try_acquire_for(offset));
+ VERIFY(!sem.try_acquire_for(offset));
+}
+
int main()
{
test01();
test02();
test03();
+ using namespace std::chrono;
+ for (const nanoseconds offset : {
+ nanoseconds{0},
+ nanoseconds{-10ms},
+ nanoseconds{-10s}
+ }) {
+ test_relative<std::chrono::system_clock>(offset);
+ test_relative<std::chrono::system_clock>(offset - std::chrono::system_clock::now().time_since_epoch());
+ test_relative<std::chrono::steady_clock>(offset);
+ test_relative<std::chrono::steady_clock>(offset - std::chrono::steady_clock::now().time_since_epoch());
+ }
}
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/semaphore/try_acquire_until.cc b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
index de0068d..ed6bd11 100644
--- a/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/try_acquire_until.cc
@@ -24,6 +24,7 @@
#include <chrono>
#include <thread>
#include <atomic>
+#include <initializer_list>
#include <testsuite_hooks.h>
void test01()
@@ -87,8 +88,31 @@ void test02()
b.wait(1);
}
+// Prove semaphore doesn't suffer from PR116586
+template <typename Clock>
+void
+test_absolute(std::chrono::nanoseconds offset)
+{
+ std::binary_semaphore sem(1);
+ std::chrono::time_point<Clock> tp(offset);
+ VERIFY(sem.try_acquire_until(tp));
+ VERIFY(!sem.try_acquire_until(tp));
+}
+
int main()
{
test01();
test02();
+ using namespace std::chrono;
+ for (const nanoseconds offset : {
+ // tv_sec == 0, tv_nsec == 0
+ nanoseconds{0},
+ // tv_sec == 0, tv_nsec < 0
+ nanoseconds{-10ms},
+ // tv_sec < 0
+ nanoseconds{-10s}
+ }) {
+ test_absolute<std::chrono::system_clock>(offset);
+ test_absolute<std::chrono::steady_clock>(offset);
+ }
}
diff --git a/libstdc++-v3/testsuite/30_threads/shared_timed_mutex/try_lock_until/116586.cc b/libstdc++-v3/testsuite/30_threads/shared_timed_mutex/try_lock_until/116586.cc
new file mode 100644
index 0000000..da9b653
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/shared_timed_mutex/try_lock_until/116586.cc
@@ -0,0 +1,125 @@
+// { dg-do run { target c++14 } }
+// { dg-additional-options "-pthread" { target pthread } }
+// { dg-require-gthreads "" }
+// { dg-require-effective-target hosted }
+
+#include <shared_mutex>
+#include <chrono>
+#include <future>
+#include <initializer_list>
+#include <testsuite_hooks.h>
+
+namespace chrono = std::chrono;
+
+// [thread.timedmutex.requirements.general]:
+// If abs_time has already passed, the function attempts to obtain
+// ownership without blocking (as if by calling try_lock()).
+
+// C++14 [thread.sharedtimedmutex.class] 3.2 says it's undefined for a thread
+// to attempt to recursively gain any ownership of a shared_timed_mutex.
+// This isn't just theoretical, as Glibc's pthread_rwlock_timedrdlock will
+// return EDEADLK if called on the same thread that already holds the
+// exclusive (write) lock.
+#define VERIFY_IN_NEW_THREAD(X) \
+ (void) std::async(std::launch::async, [&] { VERIFY(X); })
+
+// Unfortunately POSIX says that pthread_rwlock_clockwrlock,
+// pthread_rwlock_clockrdlock, pthread_rwlock_timedwrlock and
+// pthread_rwlock_timedrdlock are allowed to deadlock rather than return
+// EDEADLK or just time out if the thread already has the associated lock. This
+// means that we can't enable the deadlock tests by default. The glibc
+// implementation does return EDEADLK and __shared_mutex_cv times out so we can
+// test both of them.
+#if (defined(__GLIBC__) || ! (_GLIBCXX_USE_PTHREAD_RWLOCK_T && _GTHREAD_USE_MUTEX_TIMEDLOCK)) \
+ && ! defined(_GLIBCXX_ASSERTIONS)
+#define DEADLOCK_VERIFY(X) \
+ VERIFY(X)
+#else
+#define DEADLOCK_VERIFY(X) \
+ do {} while(0)
+#endif
+
+template <typename Clock>
+void
+test_exclusive_absolute(chrono::nanoseconds offset)
+{
+ std::shared_timed_mutex stm;
+ chrono::time_point<Clock> tp(offset);
+ VERIFY(stm.try_lock_until(tp));
+
+ // Trying to acquire the same long on the same thread
+ DEADLOCK_VERIFY(!stm.try_lock_until(tp));
+
+ // Check that false is returned on timeouts even if the implementation
+ // returned EDEADLK above by trying to lock on a different thread.
+ VERIFY_IN_NEW_THREAD(!stm.try_lock_until(tp));
+}
+
+template <typename Clock>
+void
+test_shared_absolute(chrono::nanoseconds offset)
+{
+ std::shared_timed_mutex stm;
+ chrono::time_point<Clock> tp(offset);
+ VERIFY(stm.try_lock_shared_until(tp));
+ stm.unlock_shared();
+
+ VERIFY(stm.try_lock_for(chrono::seconds{10}));
+ DEADLOCK_VERIFY(!stm.try_lock_shared_until(tp));
+ VERIFY_IN_NEW_THREAD(!stm.try_lock_shared_until(tp));
+}
+
+// The type of clock used for the actual wait depends on whether
+// _GLIBCXX_USE_PTHREAD_RWLOCK_CLOCKLOCK is defined. We might as well just test
+// both steady_clock and system_clock.
+template <typename Clock>
+void
+test_exclusive_relative(chrono::nanoseconds offset)
+{
+ std::shared_timed_mutex stm;
+ const auto d = -Clock::now().time_since_epoch() + offset;
+ VERIFY(stm.try_lock_for(d));
+ DEADLOCK_VERIFY(!stm.try_lock_for(d));
+ VERIFY_IN_NEW_THREAD(!stm.try_lock_for(d));
+}
+
+template <typename Clock>
+void
+test_shared_relative(chrono::nanoseconds offset)
+{
+ std::shared_timed_mutex stm;
+ const auto d = -Clock::now().time_since_epoch() + offset;
+ VERIFY(stm.try_lock_shared_for(d));
+ stm.unlock_shared();
+ // Should complete immediately
+ VERIFY(stm.try_lock_for(chrono::seconds{10}));
+ DEADLOCK_VERIFY(!stm.try_lock_shared_for(d));
+ VERIFY_IN_NEW_THREAD(!stm.try_lock_shared_for(d));
+}
+
+int main()
+{
+ // Try once with an offset that ought to result in tv_sec == 0, tv_nsec < 0
+ // and one with an offset that ought to result in tv_sec < 0, tv_nsec == 0
+ // for the absolute calls at least. It's not really possible to arrange for
+ // the relative calls to have tv_nsec == 0 due to time advancing.
+ using namespace std::chrono_literals;
+ for (const chrono::nanoseconds offset : {
+ // tv_sec == 0, tv_nsec == 0
+ chrono::nanoseconds{0},
+ // tv_sec == 0, tv_nsec < 0
+ chrono::nanoseconds{-10ms},
+ // tv_sec < 0
+ chrono::nanoseconds{-10s}
+ }) {
+ test_exclusive_absolute<chrono::system_clock>(offset);
+ test_shared_absolute<chrono::system_clock>(offset);
+ test_exclusive_relative<chrono::system_clock>(offset);
+ test_shared_relative<chrono::system_clock>(offset);
+
+ test_exclusive_absolute<chrono::steady_clock>(offset);
+ test_shared_absolute<chrono::steady_clock>(offset);
+ test_exclusive_relative<chrono::steady_clock>(offset);
+ test_shared_relative<chrono::steady_clock>(offset);
+ }
+}
diff --git a/libstdc++-v3/testsuite/30_threads/stop_token/stop_callback/destructible_neg.cc b/libstdc++-v3/testsuite/30_threads/stop_token/stop_callback/destructible_neg.cc
index 2c5125b..cdbb2f4 100644
--- a/libstdc++-v3/testsuite/30_threads/stop_token/stop_callback/destructible_neg.cc
+++ b/libstdc++-v3/testsuite/30_threads/stop_token/stop_callback/destructible_neg.cc
@@ -54,3 +54,4 @@ test02(std::stop_token& tok, G& g)
}
// { dg-error "static assertion failed" "" { target *-*-* } 0 }
+// { dg-error "private within this context" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/30_threads/stop_token/stop_callback/invocable_neg.cc b/libstdc++-v3/testsuite/30_threads/stop_token/stop_callback/invocable_neg.cc
index 93b3186..2b2fce4 100644
--- a/libstdc++-v3/testsuite/30_threads/stop_token/stop_callback/invocable_neg.cc
+++ b/libstdc++-v3/testsuite/30_threads/stop_token/stop_callback/invocable_neg.cc
@@ -32,3 +32,4 @@ test01(std::stop_token& tok, F& f)
}
// { dg-error "static assertion failed" "" { target *-*-* } 0 }
+// { dg-error "no match for call" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/30_threads/this_thread/113327.cc b/libstdc++-v3/testsuite/30_threads/this_thread/113327.cc
new file mode 100644
index 0000000..2daa2b0
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/this_thread/113327.cc
@@ -0,0 +1,29 @@
+// { dg-do run { target c++11 } }
+// { dg-additional-options "-pthread" { target pthread } }
+// { dg-require-gthreads "" }
+
+// PR libstdc++/113327
+// std::sleep_for(std::chrono::hours::max()) returns immediately
+
+#include <thread>
+#include <chrono>
+#include <cstdlib>
+#include <csignal>
+
+int main()
+{
+ std::thread sleepy([] {
+ // Rather than overflowing to a negative value, the timeout should be
+ // truncated to seconds::max() and so sleep for 292 billion years.
+ std::this_thread::sleep_for(std::chrono::minutes::max());
+ // This should not happen:
+ throw 1;
+ });
+ // Give the new thread a chance to start sleeping:
+ std::this_thread::yield();
+ std::this_thread::sleep_for(std::chrono::seconds(2));
+ // If we get here without the other thread throwing an exception
+ // then it should be sleeping peacefully, so the test passed.
+ // pthread_kill(sleepy.native_handle(), SIGINT);
+ std::_Exit(0);
+}
diff --git a/libstdc++-v3/testsuite/30_threads/this_thread/sleep_for.cc b/libstdc++-v3/testsuite/30_threads/this_thread/sleep_for.cc
index 3f55ccc..5b0518d 100644
--- a/libstdc++-v3/testsuite/30_threads/this_thread/sleep_for.cc
+++ b/libstdc++-v3/testsuite/30_threads/this_thread/sleep_for.cc
@@ -37,7 +37,20 @@ test01()
VERIFY( (chr::system_clock::now() - begin) >= ms );
}
+void
+test_negative()
+{
+ chr::system_clock::time_point begin = chr::system_clock::now();
+
+ std::this_thread::sleep_for(-chr::hours(8));
+
+ // That should have completed immediately, but be generous because we don't
+ // want spurious failures on busy machines.
+ VERIFY( (chr::system_clock::now() - begin) < chr::seconds(10) );
+}
+
int main()
{
test01();
+ test_negative();
}
diff --git a/libstdc++-v3/testsuite/30_threads/this_thread/sleep_until.cc b/libstdc++-v3/testsuite/30_threads/this_thread/sleep_until.cc
index 1fb82b6..8c70c2e 100644
--- a/libstdc++-v3/testsuite/30_threads/this_thread/sleep_until.cc
+++ b/libstdc++-v3/testsuite/30_threads/this_thread/sleep_until.cc
@@ -26,18 +26,36 @@
namespace chr = std::chrono;
+template <typename Clock>
void
test01()
{
- chr::system_clock::time_point begin = chr::system_clock::now();
+ typename Clock::time_point begin = Clock::now();
chr::microseconds ms(500);
- std::this_thread::sleep_until(chr::system_clock::now() + ms);
+ std::this_thread::sleep_until(Clock::now() + ms);
- VERIFY( (chr::system_clock::now() - begin) >= ms );
+ VERIFY( (Clock::now() - begin) >= ms );
+}
+
+template <typename Clock>
+void
+test_negative()
+{
+ typename Clock::time_point begin = Clock::now();
+
+ typename Clock::time_point tp(-chr::hours(8));
+ std::this_thread::sleep_until(tp);
+
+ // That should have completed immediately, but be generous because we don't
+ // want spurious failures on busy machines.
+ VERIFY( (Clock::now() - begin) < chr::seconds(10) );
}
int main()
{
- test01();
+ test01<chr::steady_clock>();
+ test01<chr::system_clock>();
+ test_negative<chr::steady_clock>();
+ test_negative<chr::system_clock>();
}
diff --git a/libstdc++-v3/testsuite/30_threads/thread/id/output.cc b/libstdc++-v3/testsuite/30_threads/thread/id/output.cc
index 94a6ff0..c3e0d42 100644
--- a/libstdc++-v3/testsuite/30_threads/thread/id/output.cc
+++ b/libstdc++-v3/testsuite/30_threads/thread/id/output.cc
@@ -81,7 +81,6 @@ void
test02()
{
#if __cpp_lib_formatters >= 202302
-
static_assert( std::is_default_constructible_v<std::formatter<std::thread::id, char>> );
std::thread t1([]{});
@@ -118,13 +117,47 @@ 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
}
+#if __cplusplus >= 202302L
+static_assert(std::enable_nonlocking_formatter_optimization<std::thread::id>);
+#endif
+
int main()
{
test01();
diff --git a/libstdc++-v3/testsuite/30_threads/thread/swap/1.cc b/libstdc++-v3/testsuite/30_threads/thread/swap/1.cc
index 9616b15..b1fde09 100644
--- a/libstdc++-v3/testsuite/30_threads/thread/swap/1.cc
+++ b/libstdc++-v3/testsuite/30_threads/thread/swap/1.cc
@@ -23,7 +23,7 @@
#include <thread>
#include <system_error>
-#include <bits/move.h> // std::move
+#include <utility> // std::move
#include <testsuite_hooks.h>
void f() { }
diff --git a/libstdc++-v3/testsuite/30_threads/timed_mutex/121496.cc b/libstdc++-v3/testsuite/30_threads/timed_mutex/121496.cc
new file mode 100644
index 0000000..d919704
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/timed_mutex/121496.cc
@@ -0,0 +1,14 @@
+// { dg-do compile { target { { i?86-*-linux* x86_64-*-linux* } && lp64 } } }
+// { dg-require-effective-target c++11 }
+// { dg-options "-fsanitize=thread" }
+
+// PR libstdc++/121496 no member named '_M_clocklock' with -fsanitize=thread
+
+#include <mutex>
+#include <chrono>
+
+void
+test_pr121496(std::timed_mutex& m)
+{
+ (void) m.try_lock_until(std::chrono::steady_clock::time_point{});
+}
diff --git a/libstdc++-v3/testsuite/30_threads/timed_mutex/try_lock_until/116586.cc b/libstdc++-v3/testsuite/30_threads/timed_mutex/try_lock_until/116586.cc
new file mode 100644
index 0000000..1566228
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/timed_mutex/try_lock_until/116586.cc
@@ -0,0 +1,60 @@
+// { dg-do run { target c++11 } }
+// { dg-additional-options "-pthread" { target pthread } }
+// { dg-require-gthreads "" }
+// { dg-require-effective-target hosted }
+
+#include <chrono>
+#include <mutex>
+#include <initializer_list>
+#include <testsuite_hooks.h>
+
+namespace chrono = std::chrono;
+
+// thread.timedmutex.requirements.general:
+// If abs_time has already passed, the function attempts to obtain
+// ownership without blocking (as if by calling try_lock()).
+
+template <typename Clock>
+void
+test_absolute(chrono::nanoseconds offset)
+{
+ std::timed_mutex mtx;
+ chrono::time_point<Clock> tp(offset);
+ VERIFY(mtx.try_lock_until(tp));
+ VERIFY(!mtx.try_lock_until(tp));
+}
+
+// The type of clock used for the actual wait depends on whether
+// _GLIBCXX_USE_PTHREAD_MUTEX_CLOCKLOCK is defined. We might as well just test
+// both steady_clock and system_clock.
+template <typename Clock>
+void
+test_relative(chrono::nanoseconds offset)
+{
+ std::timed_mutex mtx;
+ const auto d = -Clock::now().time_since_epoch() + offset;
+ VERIFY(mtx.try_lock_for(d));
+ VERIFY(!mtx.try_lock_for(d));
+}
+
+int main()
+{
+ // Try once with an offset that ought to result in tv_sec == 0, tv_nsec < 0
+ // and one with an offset that ought to result in tv_sec < 0, tv_nsec == 0
+ // for the absolute calls at least. It's not really possible to arrange for
+ // the relative calls to have tv_nsec == 0 due to time advancing.
+ for (const chrono::nanoseconds offset : {
+ // tv_sec == 0, tv_nsec == 0
+ chrono::nanoseconds{0},
+ // tv_sec == 0, tv_nsec < 0
+ chrono::duration_cast<chrono::nanoseconds>(chrono::milliseconds{-10}),
+ // tv_sec < 0
+ chrono::duration_cast<chrono::nanoseconds>(chrono::seconds{-10})
+ }) {
+ test_absolute<chrono::system_clock>(offset);
+ test_relative<chrono::system_clock>(offset);
+
+ test_absolute<chrono::steady_clock>(offset);
+ test_relative<chrono::steady_clock>(offset);
+ }
+}
diff --git a/libstdc++-v3/testsuite/Makefile.am b/libstdc++-v3/testsuite/Makefile.am
index bbdb72e..7754ab6 100644
--- a/libstdc++-v3/testsuite/Makefile.am
+++ b/libstdc++-v3/testsuite/Makefile.am
@@ -178,7 +178,7 @@ check-compile: testsuite_files ${compile_script}
# Runs the testsuite/performance tests.
# Some of these tests create large (~75MB) files, allocate huge
-# ammounts of memory, or otherwise tie up machine resources. Thus,
+# amounts of memory, or otherwise tie up machine resources. Thus,
# running this is off by default.
# XXX Need to add dependency on libtestc++.a
check_performance_script=${glibcxx_srcdir}/scripts/check_performance
diff --git a/libstdc++-v3/testsuite/Makefile.in b/libstdc++-v3/testsuite/Makefile.in
index 2e42d47..c3693b6 100644
--- a/libstdc++-v3/testsuite/Makefile.in
+++ b/libstdc++-v3/testsuite/Makefile.in
@@ -91,8 +91,10 @@ target_triplet = @target@
subdir = testsuite
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/../config/acx.m4 \
+ $(top_srcdir)/../config/clang-plugin.m4 \
$(top_srcdir)/../config/enable.m4 \
$(top_srcdir)/../config/futex.m4 \
+ $(top_srcdir)/../config/gcc-plugin.m4 \
$(top_srcdir)/../config/hwcaps.m4 \
$(top_srcdir)/../config/iconv.m4 \
$(top_srcdir)/../config/lead-dot.m4 \
@@ -222,6 +224,7 @@ LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
+LLVM_CONFIG = @LLVM_CONFIG@
LN_S = @LN_S@
LONG_DOUBLE_128_FLAGS = @LONG_DOUBLE_128_FLAGS@
LONG_DOUBLE_ALT128_COMPAT_FLAGS = @LONG_DOUBLE_ALT128_COMPAT_FLAGS@
@@ -412,7 +415,7 @@ compile_script = ${glibcxx_srcdir}/scripts/check_compile
# Runs the testsuite/performance tests.
# Some of these tests create large (~75MB) files, allocate huge
-# ammounts of memory, or otherwise tie up machine resources. Thus,
+# amounts of memory, or otherwise tie up machine resources. Thus,
# running this is off by default.
# XXX Need to add dependency on libtestc++.a
check_performance_script = ${glibcxx_srcdir}/scripts/check_performance
diff --git a/libstdc++-v3/testsuite/backward/hash_set/check_construct_destroy.cc b/libstdc++-v3/testsuite/backward/hash_set/check_construct_destroy.cc
index 042de4e..aca296d 100644
--- a/libstdc++-v3/testsuite/backward/hash_set/check_construct_destroy.cc
+++ b/libstdc++-v3/testsuite/backward/hash_set/check_construct_destroy.cc
@@ -39,50 +39,45 @@ int main()
int buckets;
- // For C++11 and later add 1 to all counts, because the std::vector used
- // internally by the hashtable creates and destroys a temporary object
- // using its allocator.
- const int extra = __cplusplus >= 201102L ? 1 : 0;
-
tracker_allocator_counter::reset();
{
Container c;
buckets = c.bucket_count();
- ok = check_construct_destroy("empty container", buckets+extra, extra) && ok;
+ ok = check_construct_destroy("empty container", buckets, 0) && ok;
}
- ok = check_construct_destroy("empty container", buckets+extra, buckets+extra) && ok;
+ ok = check_construct_destroy("empty container", buckets, buckets) && ok;
tracker_allocator_counter::reset();
{
Container c(arr10, arr10 + 10);
- ok = check_construct_destroy("Construct from range", buckets+10+extra, extra) && ok;
+ ok = check_construct_destroy("Construct from range", buckets+10, 0) && ok;
}
- ok = check_construct_destroy("Construct from range", buckets+10+extra, buckets+10+extra) && ok;
+ ok = check_construct_destroy("Construct from range", buckets+10, buckets+10) && ok;
tracker_allocator_counter::reset();
{
Container c(arr10, arr10 + 10);
c.insert(arr10a[0]);
- ok = check_construct_destroy("Insert element", buckets+11+extra, extra) && ok;
+ ok = check_construct_destroy("Insert element", buckets+11, 0) && ok;
}
- ok = check_construct_destroy("Insert element", buckets+11+extra, buckets+11+extra) && ok;
+ ok = check_construct_destroy("Insert element", buckets+11, buckets+11) && ok;
tracker_allocator_counter::reset();
{
Container c(arr10, arr10 + 10);
c.insert(arr10a, arr10a+3);
- ok = check_construct_destroy("Insert short range", buckets+13+extra, extra) && ok;
+ ok = check_construct_destroy("Insert short range", buckets+13, 0) && ok;
}
- ok = check_construct_destroy("Insert short range", buckets+13+extra, buckets+13+extra) && ok;
+ ok = check_construct_destroy("Insert short range", buckets+13, buckets+13) && ok;
tracker_allocator_counter::reset();
{
Container c(arr10, arr10 + 10);
c.insert(arr10a, arr10a+10);
- ok = check_construct_destroy("Insert long range", buckets+20+extra, extra) && ok;
+ ok = check_construct_destroy("Insert long range", buckets+20, 0) && ok;
}
- ok = check_construct_destroy("Insert long range", buckets+20+extra, buckets+20+extra) && ok;
+ ok = check_construct_destroy("Insert long range", buckets+20, buckets+20) && ok;
return ok ? 0 : 1;
}
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/memory/observer_ptr/make_observer.cc b/libstdc++-v3/testsuite/experimental/memory/observer_ptr/make_observer.cc
index 048735f..1de9cf0 100644
--- a/libstdc++-v3/testsuite/experimental/memory/observer_ptr/make_observer.cc
+++ b/libstdc++-v3/testsuite/experimental/memory/observer_ptr/make_observer.cc
@@ -20,12 +20,19 @@
#include <experimental/memory>
#include <testsuite_hooks.h>
-int main()
+constexpr bool test()
{
const int i = 42;
auto o = std::experimental::make_observer(&i);
static_assert( std::is_same<decltype(o),
- std::experimental::observer_ptr<const int>>(), "" );
+ std::experimental::observer_ptr<const int>>(), "" );
VERIFY( o && *o == 42 );
VERIFY( o.get() == &i );
+ return true;
+}
+
+int main()
+{
+ test();
+ static_assert( test(), "LWG 4295 - make_observer should be constexpr" );
}
diff --git a/libstdc++-v3/testsuite/experimental/memory/observer_ptr/relops/relops.cc b/libstdc++-v3/testsuite/experimental/memory/observer_ptr/relops/relops.cc
index 3e23e0b..d03dd5d 100644
--- a/libstdc++-v3/testsuite/experimental/memory/observer_ptr/relops/relops.cc
+++ b/libstdc++-v3/testsuite/experimental/memory/observer_ptr/relops/relops.cc
@@ -22,13 +22,13 @@
using std::experimental::observer_ptr;
-void test01()
+constexpr void test01()
{
observer_ptr<int> a, b;
VERIFY(a == b);
}
-void test02()
+constexpr void test02()
{
int x[2]{};
observer_ptr<int> a{&x[0]};
@@ -40,7 +40,7 @@ void test02()
VERIFY(b > a);
}
-void test03()
+constexpr void test03()
{
int x{};
observer_ptr<int> a{&x};
@@ -48,9 +48,10 @@ void test03()
VERIFY(a == b);
}
-void test04()
+int x[2]{};
+
+constexpr void test04()
{
- static constexpr int x[2]{};
constexpr observer_ptr<const int> a{&x[0]};
constexpr observer_ptr<const int> b{&x[1]};
VERIFY(a != b);
@@ -60,20 +61,25 @@ void test04()
VERIFY(b > a);
}
-void test05()
+constexpr void test05()
{
- static constexpr int x{};
- constexpr observer_ptr<const int> a{&x};
- constexpr observer_ptr<const int> b{&x};
+ constexpr observer_ptr<const int> a{&x[0]};
+ constexpr observer_ptr<const int> b{&x[0]};
VERIFY(a == b);
}
-
-int main()
+constexpr bool all_tests()
{
test01();
test02();
test03();
test04();
test05();
+ return true;
+}
+
+int main()
+{
+ all_tests();
+ static_assert( all_tests(), "LWG 4295 - relops should be constexpr" );
}
diff --git a/libstdc++-v3/testsuite/experimental/memory/observer_ptr/swap/swap.cc b/libstdc++-v3/testsuite/experimental/memory/observer_ptr/swap/swap.cc
index 9e76788..84b8844 100644
--- a/libstdc++-v3/testsuite/experimental/memory/observer_ptr/swap/swap.cc
+++ b/libstdc++-v3/testsuite/experimental/memory/observer_ptr/swap/swap.cc
@@ -25,7 +25,7 @@ using std::experimental::observer_ptr;
struct B {};
struct D : B {};
-void test01()
+constexpr void test01()
{
observer_ptr<int> a, b;
VERIFY(a == b);
@@ -33,7 +33,7 @@ void test01()
VERIFY(a == b);
}
-void test02()
+constexpr void test02()
{
int x{};
observer_ptr<int> a;
@@ -45,7 +45,7 @@ void test02()
VERIFY(!b);
}
-void test03()
+constexpr void test03()
{
int x[2]{1,2};
observer_ptr<int> a{&x[0]};
@@ -57,10 +57,16 @@ void test03()
VERIFY(*b == 1);
}
-
int main()
{
- test01();
- test02();
- test03();
+ auto tests = [] {
+ test01();
+ test02();
+ test03();
+ return true;
+ };
+ tests();
+#if __cpp_lib_constexpr_algorithms >= 201806L // >= C++20
+ static_assert( tests(), "LWG 4295 - swap should be constexpr" );
+#endif
}
diff --git a/libstdc++-v3/testsuite/experimental/memory/shared_ptr/cons/move_ctor.cc b/libstdc++-v3/testsuite/experimental/memory/shared_ptr/cons/move_ctor.cc
index f8ce58e..e414b1f 100644
--- a/libstdc++-v3/testsuite/experimental/memory/shared_ptr/cons/move_ctor.cc
+++ b/libstdc++-v3/testsuite/experimental/memory/shared_ptr/cons/move_ctor.cc
@@ -106,6 +106,8 @@ test04()
{
reset_count_struct __attribute__((unused)) reset;
+ // The std::move here prevents copy elision, so we construct from a prvalue.
+ // { dg-prune-output "-Wpessimizing-move" }
std::experimental::shared_ptr<A[5]> a(std::move(std::experimental
::shared_ptr<A[5]>
(new A[5])));
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/experimental/type_traits/value.cc b/libstdc++-v3/testsuite/experimental/type_traits/value.cc
index 60207b5..7ad72c6 100644
--- a/libstdc++-v3/testsuite/experimental/type_traits/value.cc
+++ b/libstdc++-v3/testsuite/experimental/type_traits/value.cc
@@ -1,5 +1,5 @@
// { dg-do compile { target c++14 } }
-// { dg-additional-options "-Wno-deprecated" { target { c++2a } } }
+// { dg-additional-options "-Wno-deprecated-declarations" { target { c++2a } } }
// Copyright (C) 2014-2025 Free Software Foundation, Inc.
//
diff --git a/libstdc++-v3/testsuite/ext/iotaarray.cc b/libstdc++-v3/testsuite/ext/iotaarray.cc
new file mode 100644
index 0000000..b259602
--- /dev/null
+++ b/libstdc++-v3/testsuite/ext/iotaarray.cc
@@ -0,0 +1,20 @@
+// { dg-do compile { target c++26 } }
+
+#include <utility>
+#include <type_traits>
+
+template<auto N>
+void test()
+{
+ constexpr auto [id0, ...ids] = std::_IotaArray<N>;
+ static_assert( std::is_same_v<decltype(id0), const decltype(N)> );
+ static_assert( sizeof...(ids) == N - 1 );
+ static_assert( (id0 + ... + ids) == N*(N-1)/2 );
+}
+
+int main()
+{
+ test<1>();
+ test<4u>();
+ test<8ull>();
+}
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/ext/unicode/properties.cc b/libstdc++-v3/testsuite/ext/unicode/properties.cc
index 50b215e..120192d 100644
--- a/libstdc++-v3/testsuite/ext/unicode/properties.cc
+++ b/libstdc++-v3/testsuite/ext/unicode/properties.cc
@@ -122,7 +122,7 @@ static_assert( uc::__is_extended_pictographic(U'\N{SOUTH WEST ARROW}') );
static_assert( ! uc::__is_extended_pictographic(U'\N{SOUTH WEST ARROW}' + 1) );
static_assert( uc::__is_extended_pictographic(U'\N{POSTBOX}') );
static_assert( ! uc::__is_extended_pictographic(U'\U0001EFFF') );
-static_assert( uc::__is_extended_pictographic(U'\U0001F000') );
+static_assert( uc::__is_extended_pictographic(U'\U0001F004') );
static_assert( uc::__is_extended_pictographic(U'\U0001FFFD') );
static_assert( ! uc::__is_extended_pictographic(U'\U0001FFFE') );
static_assert( ! uc::__is_extended_pictographic(U'\U0001FFFF') );
diff --git a/libstdc++-v3/testsuite/ext/unicode/view.cc b/libstdc++-v3/testsuite/ext/unicode/view.cc
index 6f3c099..677a21d 100644
--- a/libstdc++-v3/testsuite/ext/unicode/view.cc
+++ b/libstdc++-v3/testsuite/ext/unicode/view.cc
@@ -7,13 +7,28 @@
namespace uc = std::__unicode;
using namespace std::string_view_literals;
+static_assert( std::ranges::view<uc::_Utf8_view<std::string_view>> );
+static_assert( std::ranges::view<uc::_Utf16_view<std::string_view>> );
+static_assert( std::ranges::view<uc::_Utf32_view<std::string_view>> );
+
+template<std::ranges::range View>
+constexpr void
+compare(View v, std::basic_string_view<std::ranges::range_value_t<View>> s)
+{
+ long size = s.size();
+ VERIFY( std::ranges::distance(v) == size );
+ VERIFY( std::ranges::equal(v, s) );
+ auto rev = std::views::reverse(v);
+ VERIFY( std::ranges::distance(rev) == size );
+ VERIFY( std::ranges::equal(rev, s | std::views::reverse) );
+}
+
constexpr void
test_utf8_to_utf8()
{
const auto s8 = u8"£🇬🇧 €🇪🇺 æбçδé ♠♥♦♣ 🤡"sv;
uc::_Utf8_view v(s8);
- VERIFY( std::ranges::distance(v) == s8.size() );
- VERIFY( std::ranges::equal(v, s8) );
+ compare(v, s8);
}
constexpr void
@@ -22,8 +37,7 @@ test_utf8_to_utf16()
const auto s8 = u8"£🇬🇧 €🇪🇺 æбçδé ♠♥♦♣ 🤡"sv;
const std::u16string_view s16 = u"£🇬🇧 €🇪🇺 æбçδé ♠♥♦♣ 🤡";
uc::_Utf16_view v(s8);
- VERIFY( std::ranges::distance(v) == s16.size() );
- VERIFY( std::ranges::equal(v, s16) );
+ compare(v, s16);
}
constexpr void
@@ -32,36 +46,41 @@ test_utf8_to_utf32()
const auto s8 = u8"£🇬🇧 €🇪🇺 æбçδé ♠♥♦♣ 🤡"sv;
const auto s32 = U"£🇬🇧 €🇪🇺 æбçδé ♠♥♦♣ 🤡"sv;
uc::_Utf32_view v(s8);
- VERIFY( std::ranges::distance(v) == s32.size() );
- VERIFY( std::ranges::equal(v, s32) );
+ compare(v, s32);
}
constexpr void
test_illformed_utf8()
{
uc::_Utf32_view v("\xa3 10.99 \xee \xdd"sv);
- VERIFY( std::ranges::equal(v, U"\uFFFD 10.99 \uFFFD \uFFFD"sv) );
+ compare(v, U"\uFFFD 10.99 \uFFFD \uFFFD"sv);
uc::_Utf16_view v2(" \xf8\x80\x80\x80 "sv);
- VERIFY( std::ranges::distance(v2) == 6 );
- VERIFY( std::ranges::equal(v2, U" \uFFFD\uFFFD\uFFFD\uFFFD "sv) );
+ compare(v2, u" \uFFFD\uFFFD\uFFFD\uFFFD "sv);
// Examples of U+FFFD substitution from Unicode standard.
uc::_Utf8_view v3("\xc0\xaf\xe0\x80\xbf\xf0\x81\x82\x41"sv); // Table 3-8
- VERIFY( std::ranges::equal(v3, u8"\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\x41"sv) );
+ compare(v3, u8"\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\x41"sv);
uc::_Utf8_view v4("\xed\xa0\x80\xed\xbf\xbf\xed\xaf\x41"sv); // Table 3-9
- VERIFY( std::ranges::equal(v4, u8"\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\x41"sv) );
+ compare(v4, u8"\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\x41"sv);
uc::_Utf8_view v5("\xf4\x91\x92\x93\xff\x41\x80\xbf\x42"sv); // Table 3-10
- VERIFY( std::ranges::equal(v5, u8"\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\x41\uFFFD\uFFFD\x42"sv) );
+ compare(v5, u8"\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\x41\uFFFD\uFFFD\x42"sv);
uc::_Utf8_view v6("\xe1\x80\xe2\xf0\x91\x92\xf1\xbf\x41"sv); // Table 3-11
- VERIFY( std::ranges::equal(v6, u8"\uFFFD\uFFFD\uFFFD\uFFFD\x41"sv) );
+ compare(v6, u8"\uFFFD\uFFFD\uFFFD\uFFFD\x41"sv);
uc::_Utf32_view v7("\xe1\x80"sv);
- VERIFY( std::ranges::equal(v7, U"\uFFFD"sv) );
+ compare(v7, U"\uFFFD"sv);
uc::_Utf32_view v8("\xf1\x80"sv);
- VERIFY( std::ranges::equal(v8, U"\uFFFD"sv) );
+ compare(v8, U"\uFFFD"sv);
uc::_Utf32_view v9("\xf1\x80\x80"sv);
- VERIFY( std::ranges::equal(v9, U"\uFFFD"sv) );
+ compare(v9, U"\uFFFD"sv);
+
+ uc::_Utf32_view v10("\xcf\x80\x80\x81\x82\x83 \x84\x85\x86\x87\x88 "sv);
+ compare(v10, U"\u03C0\uFFFD\uFFFD\uFFFD\uFFFD \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD "sv);
+ uc::_Utf16_view v11("\xcf\x80\x80\x81\x82\x83 \x84\x85\x86\x87\x88 "sv);
+ compare(v11, u"\u03C0\uFFFD\uFFFD\uFFFD\uFFFD \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD "sv);
+ uc::_Utf8_view v12("\xcf\x80\x80\x81\x82\x83 \x84\x85\x86\x87\x88 "sv);
+ compare(v12, u8"\u03C0\uFFFD\uFFFD\uFFFD\uFFFD \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD "sv);
}
constexpr void
@@ -69,27 +88,32 @@ test_illformed_utf16()
{
std::u16string_view s = u"\N{CLOWN FACE}";
std::u16string_view r = u"\uFFFD";
- VERIFY( std::ranges::equal(uc::_Utf16_view(s.substr(0, 1)), r) );
- VERIFY( std::ranges::equal(uc::_Utf16_view(s.substr(1, 1)), r) );
+ compare(uc::_Utf16_view(s.substr(0, 1)), r);
+ compare(uc::_Utf16_view(s.substr(1, 1)), r);
std::array s2{ s[0], s[0] };
- VERIFY( std::ranges::equal(uc::_Utf16_view(s2), u"\uFFFD\uFFFD"sv) );
+ compare(uc::_Utf16_view(std::span(s2)), u"\uFFFD\uFFFD"sv);
std::array s3{ s[0], s[0], s[1] };
- VERIFY( std::ranges::equal(uc::_Utf16_view(s3), u"\uFFFD\N{CLOWN FACE}"sv) );
+ compare(uc::_Utf16_view(std::span(s3)), u"\uFFFD\N{CLOWN FACE}"sv);
std::array s4{ s[1], s[0] };
- VERIFY( std::ranges::equal(uc::_Utf16_view(s4), u"\uFFFD\uFFFD"sv) );
+ compare(uc::_Utf16_view(std::span(s4)), u"\uFFFD\uFFFD"sv);
std::array s5{ s[1], s[0], s[1] };
- VERIFY( std::ranges::equal(uc::_Utf16_view(s5), u"\uFFFD\N{CLOWN FACE}"sv) );
+ compare(uc::_Utf16_view(std::span(s5)), u"\uFFFD\N{CLOWN FACE}"sv);
+
+ std::array<char16_t, 2> s6{ 0xDC00, 0xDC01 };
+ compare(uc::_Utf16_view(std::span(s6)), u"\uFFFD\uFFFD"sv);
+ std::array<char16_t, 2> s7{ 0xD7FF, 0xDC00 };
+ compare(uc::_Utf16_view(std::span(s7)), u"\uD7FF\uFFFD"sv);
}
constexpr void
test_illformed_utf32()
{
std::u32string_view s = U"\x110000";
- VERIFY( std::ranges::equal(uc::_Utf32_view(s), U"\uFFFD"sv) );
+ compare(uc::_Utf32_view(s), U"\uFFFD"sv);
s = U"\xFFFFFF";
- VERIFY( std::ranges::equal(uc::_Utf32_view(s), U"\uFFFD"sv) );
+ compare(uc::_Utf32_view(s), U"\uFFFD"sv);
s = U"\xFFFFFFF0";
- VERIFY( std::ranges::equal(uc::_Utf32_view(s), U"\uFFFD"sv) );
+ compare(uc::_Utf32_view(s), U"\uFFFD"sv);
}
constexpr void
@@ -110,6 +134,13 @@ test_past_the_end()
iter++;
VERIFY( iter == v.end() );
VERIFY( *iter == U'4' );
+ std::ranges::advance(iter, -4);
+ VERIFY( *iter == U'1' );
+ // Incrementing before begin has well-defined behaviour.
+ iter--;
+ VERIFY( *iter == U'1' );
+ iter--;
+ VERIFY( *iter == U'1' );
std::string_view empty;
uc::_Utf32_view v2(empty);
@@ -119,6 +150,9 @@ test_past_the_end()
iter++;
VERIFY( iter2 == v2.end() );
VERIFY( *iter2 == U'\0' );
+ iter--;
+ VERIFY( iter2 == v2.end() );
+ VERIFY( *iter2 == U'\0' );
}
int main()
diff --git a/libstdc++-v3/testsuite/ext/verify_neg.cc b/libstdc++-v3/testsuite/ext/verify_neg.cc
new file mode 100644
index 0000000..ce03374
--- /dev/null
+++ b/libstdc++-v3/testsuite/ext/verify_neg.cc
@@ -0,0 +1,28 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_hooks.h>
+
+struct X { explicit operator void*() const { return nullptr; } };
+
+void
+test_VERIFY(int i)
+{
+ // This should not be parsed as a function type bool(bool(i)):
+ VERIFY( bool(i) );
+
+ // This should not produce warnings about lambda in unevaluated context:
+ VERIFY( []{ return 1; }() );
+
+ // Only one expression allowed:
+ VERIFY(1, 2); // { dg-error "in expansion of macro" }
+ // { dg-error "compound expression in functional cast" "" { target *-*-* } 0 }
+
+ // A scoped enum is not contextually convertible to bool:
+ enum class E { E0 };
+ VERIFY( E::E0 ); // { dg-error "could not convert" }
+
+ // explicit conversion to void* is not contextually convertible to bool:
+ X x;
+ VERIFY( x ); // { dg-error "in expansion of macro" }
+ // { dg-error "invalid cast .* to type 'bool'" "" { target *-*-* } 0 }
+}
diff --git a/libstdc++-v3/testsuite/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 a9a2993..93d3d52 100644
--- a/libstdc++-v3/testsuite/lib/prune.exp
+++ b/libstdc++-v3/testsuite/lib/prune.exp
@@ -53,12 +53,13 @@ proc libstdc++-dg-prune { system text } {
regsub -all "(^|\n)\[^\n\]*: (recursively )?required \[^\n\]*" $text "" text
regsub -all "(^|\n)\[^\n\]*: . skipping \[0-9\]* instantiation contexts \[^\n\]*" $text "" text
regsub -all "(^|\n)\[^\n\]*: in .constexpr. expansion \[^\n\]*" $text "" text
- regsub -all "(^|\n)\[^\n\]*: in requirements .with\[^\n\]*" $text "" text
- regsub -all "(^|\n)\[^\n\]*: in requirements with\[^\n\]*" $text "" text
+ regsub -all "(^|\n)\[^\n\]*: in requirements \[^\n\]*" $text "" text
regsub -all "(^|\n) inlined from \[^\n\]*" $text "" text
- # Why doesn't GCC need these to strip header context?
- regsub -all "(^|\n)In file included from \[^\n\]*" $text "" text
- regsub -all "(^|\n)\[ \t\]*from \[^\n\]*" $text "" text
+
+ # Diagnostic inclusion stack
+ regsub -all "(^|\n)(In file)?\[ \]+included from \[^\n\]*" $text "" text
+ regsub -all "(^|\n)\[ \]+from \[^\n\]*" $text "" text
+ regsub -all "(^|\n)(In|of) module( \[^\n \]*,)? imported at \[^\n\]*" $text "" text
# Ignore informational notes.
#TODO As this isn't even using 'gcc-dg.exp', cannot consider its
diff --git a/libstdc++-v3/testsuite/performance/23_containers/sort_search/list.cc b/libstdc++-v3/testsuite/performance/23_containers/sort_search/list.cc
index 525d37aa..efb6e6a 100644
--- a/libstdc++-v3/testsuite/performance/23_containers/sort_search/list.cc
+++ b/libstdc++-v3/testsuite/performance/23_containers/sort_search/list.cc
@@ -34,7 +34,7 @@ template<typename Container, int Iter>
//Search for random values that may or may not belong to the list.
for (int i = 0; i < 50; ++i)
- std::find(obj.begin(), obj.end(), rand() % 100001);
+ (void) std::find(obj.begin(), obj.end(), rand() % 100001);
obj.sort();
diff --git a/libstdc++-v3/testsuite/performance/25_algorithms/equal_deque_iterators.cc b/libstdc++-v3/testsuite/performance/25_algorithms/equal_deque_iterators.cc
index 1f97adb..5816667 100644
--- a/libstdc++-v3/testsuite/performance/25_algorithms/equal_deque_iterators.cc
+++ b/libstdc++-v3/testsuite/performance/25_algorithms/equal_deque_iterators.cc
@@ -34,7 +34,7 @@ int main()
start_counters(time, resource);
for (int i = 0; i < 1000; ++i)
for (int j = 0; j < 3000; ++j)
- std::equal(data.begin(), data.begin() + j, d.begin());
+ (void) std::equal(data.begin(), data.begin() + j, d.begin());
stop_counters(time, resource);
report_performance(__FILE__, "deque vs deque", time, resource);
clear_counters(time, resource);
@@ -44,7 +44,7 @@ int main()
start_counters(time, resource);
for (int i = 0; i < 1000; ++i)
for (int j = 0; j < 3000; ++j)
- std::equal(data.begin(), data.begin() + j, v.begin());
+ (void) std::equal(data.begin(), data.begin() + j, v.begin());
stop_counters(time, resource);
report_performance(__FILE__, "deque vs vector", time, resource);
clear_counters(time, resource);
@@ -54,7 +54,7 @@ int main()
start_counters(time, resource);
for (int i = 0; i < 1000; ++i)
for (int j = 0; j < 3000; ++j)
- std::equal(v.begin(), v.begin() + j, d.begin());
+ (void) std::equal(v.begin(), v.begin() + j, d.begin());
stop_counters(time, resource);
report_performance(__FILE__, "vector vs deque", time, resource);
clear_counters(time, resource);
@@ -64,7 +64,7 @@ int main()
start_counters(time, resource);
for (int i = 0; i < 1000; ++i)
for (int j = 0; j < 3000; ++j)
- std::equal(data.begin(), data.begin() + j, cv.begin());
+ (void) std::equal(data.begin(), data.begin() + j, cv.begin());
stop_counters(time, resource);
report_performance(__FILE__, "int deque vs char vector", time, resource);
clear_counters(time, resource);
@@ -74,7 +74,7 @@ int main()
start_counters(time, resource);
for (int i = 0; i < 1000; ++i)
for (int j = 0; j < 3000; ++j)
- std::equal(cv.begin(), cv.begin() + j, d.begin());
+ (void) std::equal(cv.begin(), cv.begin() + j, d.begin());
stop_counters(time, resource);
report_performance(__FILE__, "char vector vs int deque", time, resource);
diff --git a/libstdc++-v3/testsuite/performance/25_algorithms/search_n.cc b/libstdc++-v3/testsuite/performance/25_algorithms/search_n.cc
index 3f3585a..6218c1e 100644
--- a/libstdc++-v3/testsuite/performance/25_algorithms/search_n.cc
+++ b/libstdc++-v3/testsuite/performance/25_algorithms/search_n.cc
@@ -47,7 +47,7 @@ main(void)
__gnu_test::test_container<int, forward_iterator_wrapper> fcon(ary, ary + length);
start_counters(time, resource);
for(int i = 0; i < 100; i++)
- search_n(fcon.begin(), fcon.end(), 10, 1);
+ (void) search_n(fcon.begin(), fcon.end(), 10, 1);
stop_counters(time, resource);
report_performance(__FILE__, "forward iterator", time, resource);
clear_counters(time, resource);
@@ -55,7 +55,7 @@ main(void)
__gnu_test::test_container<int, random_access_iterator_wrapper> rcon(ary, ary + length);
start_counters(time, resource);
for(int i = 0; i < 100; i++)
- search_n(rcon.begin(), rcon.end(), 10, 1);
+ (void) search_n(rcon.begin(), rcon.end(), 10, 1);
stop_counters(time, resource);
report_performance(__FILE__, "random access iterator", time, resource);
clear_counters(time, resource);
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/concepts/concepts.compare/move_only.cc b/libstdc++-v3/testsuite/std/concepts/concepts.compare/move_only.cc
new file mode 100644
index 0000000..01870d8
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/concepts/concepts.compare/move_only.cc
@@ -0,0 +1,28 @@
+// { dg-do compile { target c++20 } }
+
+#include <concepts>
+#include <compare>
+
+// P2404R3 Move-only types for equality_comparable_with,
+// totally_ordered_with, and three_way_comparable_with
+
+// This was approved for C++23 but we treat it as a DR for C++20.
+
+#ifndef __cpp_lib_concepts
+# error "Feature-test macro __cpp_lib_concepts is missing in <compare>"
+#elif __cpp_lib_concepts < 202207L
+# error "Feature-test macro __cpp_lib_concepts has wrong value in <compare>"
+#endif
+
+struct MoveOnly
+{
+ MoveOnly(int);
+ MoveOnly(MoveOnly&&) = default;
+ auto operator<=>(const MoveOnly&) const = default;
+ std::strong_ordering operator<=>(int) const;
+ bool operator==(const MoveOnly&) const;
+};
+
+static_assert(std::equality_comparable_with<MoveOnly, int>);
+static_assert(std::totally_ordered_with<MoveOnly, int>);
+static_assert(std::three_way_comparable_with<MoveOnly, int>);
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/arguments/args_neg.cc b/libstdc++-v3/testsuite/std/format/arguments/args_neg.cc
index ded56fe..83c7b22 100644
--- a/libstdc++-v3/testsuite/std/format/arguments/args_neg.cc
+++ b/libstdc++-v3/testsuite/std/format/arguments/args_neg.cc
@@ -42,3 +42,4 @@ void test_const_arg()
}
// { dg-prune-output "no matching function for call to .*::basic_format_arg<" }
+// { dg-prune-output "use of deleted function" }
diff --git a/libstdc++-v3/testsuite/std/format/debug.cc b/libstdc++-v3/testsuite/std/format/debug.cc
index 71bb7f4..43e930c 100644
--- a/libstdc++-v3/testsuite/std/format/debug.cc
+++ b/libstdc++-v3/testsuite/std/format/debug.cc
@@ -1,7 +1,9 @@
// { 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>
@@ -24,13 +26,13 @@ fdebug(std::wstring_view t)
#define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S)
-#define WIDEN(S) WIDEN_(_CharT, S)
+#define WIDEN(S) WIDEN_(CharT, S)
-template<typename _CharT>
+template<typename CharT>
void
test_basic_escapes()
{
- std::basic_string<_CharT> res;
+ std::basic_string<CharT> res;
const auto tab = WIDEN("\t");
res = fdebug(tab);
@@ -69,11 +71,11 @@ test_basic_escapes()
VERIFY( res == WIDEN(R"('\'')") );
}
-template<typename _CharT>
+template<typename CharT>
void
test_ascii_escapes()
{
- std::basic_string<_CharT> res;
+ std::basic_string<CharT> res;
const auto in = WIDEN("\x10 abcde\x7f\t0123");
res = fdebug(in);
@@ -86,19 +88,19 @@ test_ascii_escapes()
VERIFY( res == WIDEN(R"('a')") );
}
-template<typename _CharT>
+template<typename CharT>
void
test_extended_ascii()
{
- std::basic_string<_CharT> res;
+ std::basic_string<CharT> res;
const auto in = WIDEN("Åëÿ");
res = fdebug(in);
VERIFY( res == WIDEN(R"("Åëÿ")") );
- static constexpr bool __test_characters
+ static constexpr bool __test_characters
#if UNICODE_ENC
- = sizeof(_CharT) >= 2;
+ = sizeof(CharT) >= 2;
#else // ISO8859-1
= true;
#endif // UNICODE_ENC
@@ -114,12 +116,12 @@ test_extended_ascii()
}
}
-#if UNICODE_ENC
-template<typename _CharT>
+template<typename CharT>
void
test_unicode_escapes()
{
- std::basic_string<_CharT> res;
+#if UNICODE_ENC
+ std::basic_string<CharT> res;
const auto in = WIDEN(
"\u008a" // Cc, Control, Line Tabulation Set,
@@ -141,7 +143,7 @@ test_unicode_escapes()
res = fdebug(in);
VERIFY( res == out );
- if constexpr (sizeof(_CharT) >= 2)
+ if constexpr (sizeof(CharT) >= 2)
{
res = fdebug(in[0]);
VERIFY( res == WIDEN(R"('\u{8a}')") );
@@ -155,53 +157,59 @@ test_unicode_escapes()
VERIFY( res == WIDEN(R"('\u{2029}')") );
}
- if constexpr (sizeof(_CharT) >= 4)
+ if constexpr (sizeof(CharT) >= 4)
{
res = fdebug(in[5]);
VERIFY( res == WIDEN("'\U0001f984'") );
}
+#endif // UNICODE_ENC
}
-template<typename _CharT>
+template<typename CharT>
void
test_grapheme_extend()
{
- std::basic_string<_CharT> res;
+#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");
+ 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)
+ if constexpr (sizeof(CharT) >= 2)
{
res = fdebug(in[1]);
VERIFY( res == WIDEN(R"('\u{302}')") );
}
+#endif // UNICODE_ENC
}
-template<typename _CharT>
+template<typename CharT>
void
test_replacement_char()
{
- std::basic_string<_CharT> repl = WIDEN("\uFFFD");
- std::basic_string<_CharT> res = fdebug(repl);
+#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;
@@ -233,11 +241,13 @@ test_ill_formed_utf8_seq()
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);
@@ -255,16 +265,16 @@ test_ill_formed_utf32()
std::wstring is2(1, ic2);
res = fdebug(is2);
VERIFY( res == LR"("\x{ffffffff}")" );
-}
#endif // UNICODE_ENC
+}
-template<typename _CharT>
+template<typename CharT>
void
test_fill()
{
- std::basic_string<_CharT> res;
+ std::basic_string<CharT> res;
- std::basic_string_view<_CharT> in = WIDEN("a\t\x10\u00ad");
+ 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" )") );
@@ -289,11 +299,11 @@ test_fill()
VERIFY( res == WIDEN(R"(="\u{ad}"=)") );
// width is 2
- std::basic_string_view<_CharT> in2 = WIDEN("\u1100");
+ std::basic_string_view<CharT> in2 = WIDEN("\u1100");
res = std::format(WIDEN("{:*^10?}"), in2);
VERIFY( res == WIDEN("***\"\u1100\"***") );
- if constexpr (sizeof(_CharT) >= 2)
+ if constexpr (sizeof(CharT) >= 2)
{
res = std::format(WIDEN("{:=^10?}"), in[3]);
VERIFY( res == WIDEN(R"(='\u{ad}'=)") );
@@ -304,14 +314,14 @@ test_fill()
#endif // UNICODE_ENC
}
-template<typename _CharT>
+template<typename CharT>
void
test_prec()
{
- std::basic_string<_CharT> res;
+ 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");
+ 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)") );
@@ -325,12 +335,390 @@ test_prec()
res = std::format(WIDEN("{:.10?}"), in.substr(3));
VERIFY( res == WIDEN(R"("\u{ad}")") );
- std::basic_string_view<_CharT> in2 = WIDEN("\u1100");
+ 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;
@@ -371,38 +759,38 @@ private:
std::formatter<T, CharT> under;
};
-template<typename _CharT, typename StrT>
+template<typename CharT, typename StrT>
void
test_formatter_str()
{
- _CharT buf[]{ 'a', 'b', 'c', 0 };
+ CharT buf[]{ 'a', 'b', 'c', 0 };
DebugWrapper<StrT> in{ buf };
- std::basic_string<_CharT> res = std::format(WIDEN("{:?}"), in );
+ std::basic_string<CharT> res = std::format(WIDEN("{:?}"), in );
VERIFY( res == WIDEN(R"("abc")") );
}
-template<typename _CharT>
+template<typename CharT>
void
test_formatter_arr()
{
- std::basic_string<_CharT> res;
+ std::basic_string<CharT> res;
- DebugWrapper<_CharT[3]> in3{ 'a', 'b', 'c' };
+ 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 };
+ 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>
+template<typename CharT, typename SrcT>
void
test_formatter_char()
{
DebugWrapper<SrcT> in{ 'a' };
- std::basic_string<_CharT> res = std::format(WIDEN("{:?}"), in);
+ std::basic_string<CharT> res = std::format(WIDEN("{:?}"), in);
VERIFY( res == WIDEN(R"('a')") );
}
@@ -435,7 +823,6 @@ int main()
test_extended_ascii<char>();
test_extended_ascii<wchar_t>();
-#if UNICODE_ENC
test_unicode_escapes<char>();
test_unicode_escapes<wchar_t>();
test_grapheme_extend<char>();
@@ -444,12 +831,13 @@ int main()
test_replacement_char<wchar_t>();
test_ill_formed_utf8_seq();
test_ill_formed_utf32();
-#endif // UNICODE_ENC
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/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 1f3edc9..07e63af 100644
--- a/libstdc++-v3/testsuite/std/format/formatter/lwg3944.cc
+++ b/libstdc++-v3/testsuite/std/format/formatter/lwg3944.cc
@@ -18,7 +18,7 @@ void test_lwg3944()
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" }
-#ifdef __glibcxx_format_ranges
+#ifdef __cpp_lib_format_ranges
// LWG 3944 does not change this, it's still valid.
std::format(L"{}", std::vector{'h', 'e', 'l', 'l', 'o'});
#endif
diff --git a/libstdc++-v3/testsuite/std/format/formatter/nonlocking.cc b/libstdc++-v3/testsuite/std/format/formatter/nonlocking.cc
new file mode 100644
index 0000000..a726e9d
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/format/formatter/nonlocking.cc
@@ -0,0 +1,59 @@
+// { dg-do compile { target c++23 } }
+
+#include <format>
+#include <string>
+
+template<typename CharT>
+struct MyTraits : std::char_traits<CharT>
+{};
+
+template<typename CharT>
+struct MyAlloc : std::allocator<CharT>
+{
+ using std::allocator<CharT>::allocator;
+};
+
+template<typename CharT>
+void testCharacters()
+{
+ static_assert(std::enable_nonlocking_formatter_optimization<
+ CharT>);
+ static_assert(std::enable_nonlocking_formatter_optimization<
+ CharT*>);
+ static_assert(std::enable_nonlocking_formatter_optimization<
+ const CharT*>);
+ static_assert(std::enable_nonlocking_formatter_optimization<
+ CharT[5]>);
+
+ static_assert(std::enable_nonlocking_formatter_optimization<
+ std::basic_string<CharT>>);
+ static_assert(std::enable_nonlocking_formatter_optimization<
+ std::basic_string<CharT, MyTraits<CharT>>>);
+ static_assert(std::enable_nonlocking_formatter_optimization<
+ std::basic_string<CharT, MyTraits<CharT>, MyAlloc<CharT>>>);
+
+ static_assert(std::enable_nonlocking_formatter_optimization<
+ std::basic_string_view<CharT>>);
+ static_assert(std::enable_nonlocking_formatter_optimization<
+ std::basic_string_view<CharT, MyTraits<CharT>>>);
+}
+
+void testAll()
+{
+ static_assert(std::enable_nonlocking_formatter_optimization<
+ int>);
+ static_assert(std::enable_nonlocking_formatter_optimization<
+ float>);
+ static_assert(std::enable_nonlocking_formatter_optimization<
+ void*>);
+ static_assert(std::enable_nonlocking_formatter_optimization<
+ const void*>);
+ static_assert(std::enable_nonlocking_formatter_optimization<
+ std::nullptr_t>);
+
+ testCharacters<char>();
+#ifdef _GLIBCXX_USE_WCHAR_T
+ testCharacters<wchar_t>();
+#endif // USE_WCHAR_T
+}
+
diff --git a/libstdc++-v3/testsuite/std/format/functions/format.cc b/libstdc++-v3/testsuite/std/format/functions/format.cc
index 93c33b4..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);
}
@@ -511,6 +522,7 @@ 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,
@@ -564,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 b338ac7..6294dcf 100644
--- a/libstdc++-v3/testsuite/std/format/parse_ctx.cc
+++ b/libstdc++-v3/testsuite/std/format/parse_ctx.cc
@@ -108,7 +108,7 @@ is_std_format_spec_for(std::string_view spec)
}
}
-#if __glibcxx_format_ranges
+#if __cpp_lib_format_ranges
constexpr bool escaped_strings_supported = true;
#else
constexpr bool escaped_strings_supported = false;
@@ -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/pr121765.cc b/libstdc++-v3/testsuite/std/format/pr121765.cc
new file mode 100644
index 0000000..1358fc1
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/format/pr121765.cc
@@ -0,0 +1,53 @@
+// { dg-do compile { target c++23 } }
+
+#include <format>
+#include <utility>
+
+struct MyPair
+{
+ int x;
+ int y;
+};
+
+template<typename CharT>
+struct std::formatter<MyPair, CharT>
+{
+ template<typename ParseContext>
+ auto parse(ParseContext& pc)
+ { return _formatter.parse(pc); }
+
+ template<typename FormatContext>
+ auto format(const MyPair& mp, FormatContext& fc) const
+ { return _formatter.format(std::make_pair(mp.x, mp.y), fc); }
+
+private:
+ std::formatter<std::pair<int, int>, CharT> _formatter;
+};
+
+static_assert(std::formattable<MyPair, char>);
+static_assert(std::formattable<MyPair, wchar_t>);
+
+struct MyRange
+{
+ int* begin;
+ int* end;
+};
+
+template<typename CharT>
+struct std::formatter<MyRange, CharT>
+{
+ template<typename ParseContext>
+ auto parse(ParseContext& pc)
+ { return _formatter.parse(pc); }
+
+ template<typename FormatContext>
+ auto format(const MyRange& mp, FormatContext& fc) const
+ { return _formatter.format(std::span<int>(mp.begin, mp.end), fc); }
+
+private:
+ std::formatter<std::span<int>, CharT> _formatter;
+};
+
+static_assert(std::formattable<MyRange, char>);
+static_assert(std::formattable<MyRange, wchar_t>);
+
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..649eea4
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/format/ranges/adaptors.cc
@@ -0,0 +1,165 @@
+// { 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>);
+
+ static_assert(!std::enable_nonlocking_formatter_optimization<
+ Adaptor<int>>);
+ static_assert(!std::enable_nonlocking_formatter_optimization<
+ Adaptor<MutFormat>>);
+ static_assert(!std::enable_nonlocking_formatter_optimization<
+ Adaptor<int, std::deque<int>>>);
+ static_assert(!std::enable_nonlocking_formatter_optimization<
+ Adaptor<int, NotFormattableCont<int>>>);
+}
+
+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
index 14b9ff2..1450fba 100644
--- a/libstdc++-v3/testsuite/std/format/ranges/format_kind.cc
+++ b/libstdc++-v3/testsuite/std/format/ranges/format_kind.cc
@@ -75,7 +75,9 @@ void test_override()
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<std::pair<int, int>, std::range_format::map> mapf
+ {{1, 11}, {2, 22}, {3, 33}};
+ VERIFY( std::format("{}", mapf) == "{1: 11, 2: 22, 3: 33}" );
CustFormat<char, std::range_format::string> stringf{'a', 'b', 'c', 'd'};
VERIFY( std::format("{}", stringf) == "abcd" );
diff --git a/libstdc++-v3/testsuite/std/format/ranges/format_kind_neg.cc b/libstdc++-v3/testsuite/std/format/ranges/format_kind_neg.cc
index bf8619d..0d761ae 100644
--- a/libstdc++-v3/testsuite/std/format/ranges/format_kind_neg.cc
+++ b/libstdc++-v3/testsuite/std/format/ranges/format_kind_neg.cc
@@ -5,9 +5,14 @@
#include <format>
-template<auto> struct Tester { };
+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" }
+}
-Tester<std::format_kind<const int(&)[1]>> t; // { dg-error "here" }
-
-// { dg-error "use of 'std::format_kind" "" { target *-*-* } 0 }
-// { dg-error "primary_template_not_defined" "" { target *-*-* } 0 }
+// { 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
index 00ce9f6..a50c5b1 100644
--- a/libstdc++-v3/testsuite/std/format/ranges/formatter.cc
+++ b/libstdc++-v3/testsuite/std/format/ranges/formatter.cc
@@ -4,9 +4,10 @@
#include <format>
#include <testsuite_hooks.h>
#include <vector>
+#include <span>
#define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S)
-#define WIDEN(S) WIDEN_(_CharT, S)
+#define WIDEN(S) WIDEN_(CharT, S)
template<typename T,
template<typename, typename> class Formatter = std::range_formatter>
@@ -22,7 +23,6 @@ struct std::formatter<MyVector<T, Formatter>, CharT>
{
constexpr formatter() noexcept
{
- using _CharT = CharT;
_formatter.set_brackets(WIDEN("<"), WIDEN(">"));
_formatter.set_separator(WIDEN("; "));
}
@@ -41,12 +41,12 @@ private:
Formatter<T, CharT> _formatter;
};
-template<typename _CharT, template<typename, typename> class Formatter>
+template<typename CharT, template<typename, typename> class Formatter>
void
test_default()
{
MyVector<int, Formatter> vec{1, 2, 3};
- std::basic_string<_CharT> res;
+ std::basic_string<CharT> res;
res = std::format(WIDEN("{}"), vec);
VERIFY( res == WIDEN("<1; 2; 3>") );
@@ -93,13 +93,13 @@ test_default()
VERIFY( res == WIDEN("< +1 ; +2 ; +3 >") );
}
-template<typename _CharT, template<typename, typename> class Formatter>
+template<typename CharT, template<typename, typename> class Formatter>
void
test_override()
{
- MyVector<_CharT, Formatter> vc{'a', 'b', 'c', 'd'};
+ MyVector<CharT, Formatter> vc{'a', 'b', 'c', 'd'};
MyVector<std::pair<int, int>, Formatter> vp{{1, 11}, {2, 21}};
- std::basic_string<_CharT> res;
+ std::basic_string<CharT> res;
res = std::format(WIDEN("{:s}"), vc);
VERIFY( res == WIDEN("abcd") );
@@ -146,7 +146,7 @@ struct MyFlatMap : std::flat_map<int, int>
template<typename CharT>
struct std::formatter<MyFlatMap, CharT>
- // This cannot apply format BitVector const&, because formatted type would
+ // We cannot format MyFlatMap 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>
@@ -162,10 +162,21 @@ void test_const_ref_type_mismatch()
template<typename T, typename CharT>
using VectorFormatter = std::formatter<std::vector<T>, CharT>;
+template<template<typename> typename Range>
+void test_nonblocking()
+{
+ static_assert(!std::enable_nonlocking_formatter_optimization<
+ Range<int>>);
+}
+
int main()
{
test_outputs<std::range_formatter>();
test_outputs<VectorFormatter>();
test_nested();
test_const_ref_type_mismatch();
+
+ test_nonblocking<std::span>();
+ test_nonblocking<std::vector>();
+ test_nonblocking<MyVector>();
}
diff --git a/libstdc++-v3/testsuite/std/format/ranges/map.cc b/libstdc++-v3/testsuite/std/format/ranges/map.cc
index 34c5ed5..5e1b98f 100644
--- a/libstdc++-v3/testsuite/std/format/ranges/map.cc
+++ b/libstdc++-v3/testsuite/std/format/ranges/map.cc
@@ -1,4 +1,5 @@
// { dg-do run { target c++23 } }
+// { dg-timeout-factor 2 }
#include <flat_map>
#include <format>
@@ -56,7 +57,7 @@ bool is_range_formatter_spec_for(CharT const* spec, Rg&& rg)
}
#define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S)
-#define WIDEN(S) WIDEN_(_CharT, S)
+#define WIDEN(S) WIDEN_(CharT, S)
void
test_format_string()
@@ -82,10 +83,10 @@ test_format_string()
VERIFY( !is_format_string_for("{:{}m}", std::vector<std::pair<int, int>>(), 1.0f) );
}
-template<typename _CharT, typename Range>
+template<typename CharT, typename Range>
void test_output(bool mapIsDefault)
{
- using Sv = std::basic_string_view<_CharT>;
+ 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>>;
@@ -93,7 +94,7 @@ void test_output(bool mapIsDefault)
return Range(s.data(), s.data() + s.size());
};
- std::basic_string<_CharT> res;
+ std::basic_string<CharT> res;
size_t size = 0;
Ft f1[]{1, 2, 3};
diff --git a/libstdc++-v3/testsuite/std/format/ranges/pr119861_neg.cc b/libstdc++-v3/testsuite/std/format/ranges/pr119861_neg.cc
new file mode 100644
index 0000000..9a6ed16
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/format/ranges/pr119861_neg.cc
@@ -0,0 +1,52 @@
+// { dg-do compile { target c++23 } }
+
+#include <format>
+#include <vector>
+
+// only format_kind::sequence provides set_brackets and set_separator methods
+
+template<std::range_format fk, typename T>
+struct MyCont : std::vector<T>
+{
+ using std::vector<T>::vector;
+};
+
+template<std::range_format fk, typename T>
+constexpr std::range_format std::format_kind<MyCont<fk, T>> = fk;
+
+void test_sequence()
+{
+ std::formatter<MyCont<std::range_format::sequence, int>, char> fmtter;
+ fmtter.set_brackets("{", "}");
+ fmtter.set_separator(",");
+}
+
+void test_map()
+{
+ std::formatter<MyCont<std::range_format::map, std::pair<int, int>>, char> fmtter;
+ fmtter.set_brackets("{", "}"); // { dg-error "here" }
+ fmtter.set_separator(","); // { dg-error "here" }
+}
+
+void test_set()
+{
+ std::formatter<MyCont<std::range_format::set, int>, char> fmtter;
+ fmtter.set_brackets("{", "}"); // { dg-error "here" }
+ fmtter.set_separator(","); // { dg-error "here" }
+}
+
+void test_string()
+{
+ std::formatter<MyCont<std::range_format::string, char>, char> fmtter;
+ fmtter.set_brackets("{", "}"); // { dg-error "here" }
+ fmtter.set_separator(","); // { dg-error "here" }
+}
+
+void test_debug_string()
+{
+ std::formatter<MyCont<std::range_format::debug_string, char>, char> fmtter;
+ fmtter.set_brackets("{", "}"); // { dg-error "here" }
+ fmtter.set_separator(","); // { dg-error "here" }
+}
+
+// { dg-error "no matching function for call to 'std::formatter<" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/std/format/ranges/sequence.cc b/libstdc++-v3/testsuite/std/format/ranges/sequence.cc
index 61fc68e..7fb65f9 100644
--- a/libstdc++-v3/testsuite/std/format/ranges/sequence.cc
+++ b/libstdc++-v3/testsuite/std/format/ranges/sequence.cc
@@ -1,10 +1,13 @@
// { 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>
@@ -73,12 +76,12 @@ test_format_string()
}
#define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S)
-#define WIDEN(S) WIDEN_(_CharT, S)
+#define WIDEN(S) WIDEN_(CharT, S)
-template<typename _CharT, typename Range, typename Storage>
+template<typename CharT, typename Range, typename Storage>
void test_output()
{
- using Sv = std::basic_string_view<_CharT>;
+ 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>)
@@ -88,7 +91,7 @@ void test_output()
std::ranges::data(s) + std::ranges::size(s));
};
- std::basic_string<_CharT> res;
+ std::basic_string<CharT> res;
size_t size = 0;
Storage v1{1, 2, 3};
@@ -198,9 +201,132 @@ test_nested()
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
index 7f59f59..bef2cc7 100644
--- a/libstdc++-v3/testsuite/std/format/ranges/string.cc
+++ b/libstdc++-v3/testsuite/std/format/ranges/string.cc
@@ -1,6 +1,9 @@
// { 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>
@@ -45,7 +48,7 @@ bool is_range_formatter_spec_for(CharT const* spec, Rg&& rg)
}
#define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S)
-#define WIDEN(S) WIDEN_(_CharT, S)
+#define WIDEN(S) WIDEN_(CharT, S)
void
test_format_string()
@@ -78,14 +81,14 @@ test_format_string()
template<typename Range>
void test_output()
{
- using _CharT = std::ranges::range_value_t<Range>;
- auto makeRange = [](std::basic_string<_CharT>& s) {
+ 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;
+ std::basic_string<CharT> res;
size_t size = 0;
- std::basic_string<_CharT> s1 = WIDEN("abcd");
+ std::basic_string<CharT> s1 = WIDEN("abcd");
res = std::format(WIDEN("{}"), makeRange(s1));
VERIFY( res == WIDEN("['a', 'b', 'c', 'd']") );
@@ -119,7 +122,7 @@ void test_output()
res = std::format(WIDEN("{:=^8s}"), makeRange(s1));
VERIFY( res == WIDEN("==abcd==") );
- std::basic_string<_CharT> s2(512, static_cast<_CharT>('a'));
+ std::basic_string<CharT> s2(512, static_cast<CharT>('a'));
res = std::format(WIDEN("{:=^8s}"), makeRange(s2));
VERIFY( res == s2 );
@@ -217,10 +220,160 @@ test_nested()
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 );
+
+ // width is 5, size is 15
+ in = "\u2160\u2161\u2162\u2163\u2164";
+ in += in; // width is 10, size is 30
+ in += in; // width is 20, size is 60
+ in += in; // width is 40, size is 120
+ in += in; // width is 80, size is 240
+ in += in; // width is 160, size is 480
+
+ lc.assign_range(in);
+
+ resv = res = std::format("{:s}", lc);
+ VERIFY( resv == in );
+
+ resv = res = std::format("{:*>10s}", lc);
+ VERIFY( resv == in );
+
+ resv = res = std::format("{:*>200s}", lc);
+ VERIFY( strip_prefix(resv, 40, '*') );
+ 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("{:*>200?s}", lc);
+ VERIFY( strip_prefix(resv, 38, '*') );
+ VERIFY( strip_quotes(resv) );
+ VERIFY( resv == in );
+}
+
+void test_escaping()
+{
+ std::string res;
+ std::string_view resv;
+
+ const std::string_view input =
+ "\t\n\r\\\""
+ "\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 std::string_view output =
+ R"(\t\n\r\\\")"
+ R"(\u{8a})"
+ R"(\u{ad})"
+ "\u1d3d"
+ R"(\u{a0})"
+ R"(\u{2029})"
+ "\U0001f984";
+
+ std::forward_list<char> lc(std::from_range, input);
+ resv = res = std::format("{:s}", lc);
+ VERIFY( resv == input );
+ resv = res = std::format("{:?s}", lc);
+ VERIFY( strip_quotes(resv) );
+ VERIFY( resv == output );
+
+ // width is 5, size is 15
+ std::string in = "\u2160\u2161\u2162\u2163\u2164";
+ in += in; // width is 10, size is 30
+ in += in; // width is 20, size is 60
+ in += in; // width is 40, size is 120
+ in += in; // width is 80, size is 240
+ in += in; // width is 160, size is 480
+ std::string_view inv = in;
+
+ // last charcter is incomplete
+ lc.assign_range(inv.substr(0, 479));
+
+ // non-debug format, chars copied as is
+ resv = res = std::format("{:s}", lc);
+ VERIFY( resv == inv.substr(0, 479) );
+
+ // debug-format, incomplete code-point sequence is esaped
+ resv = res = std::format("{:?s}", lc);
+ VERIFY( strip_quotes(resv) );
+ VERIFY( resv.substr(0, 477) == inv.substr(0, 477) );
+ resv.remove_prefix(477);
+ VERIFY( resv == R"(\x{e2}\x{85})" );
+}
+
int main()
{
test_format_string();
test_outputs<char>();
test_outputs<wchar_t>();
test_nested();
+ test_padding();
+ test_escaping();
}
diff --git a/libstdc++-v3/testsuite/std/format/string.cc b/libstdc++-v3/testsuite/std/format/string.cc
index 76614d4..ee987a1 100644
--- a/libstdc++-v3/testsuite/std/format/string.cc
+++ b/libstdc++-v3/testsuite/std/format/string.cc
@@ -62,7 +62,7 @@ test_indexing()
VERIFY( ! is_format_string_for("{} {0}", 1) );
}
-#if __glibcxx_format_ranges
+#if __cpp_lib_format_ranges
constexpr bool escaped_strings_supported = true;
#else
constexpr bool escaped_strings_supported = false;
diff --git a/libstdc++-v3/testsuite/std/format/string_neg.cc b/libstdc++-v3/testsuite/std/format/string_neg.cc
index 09cc9a2..acae88e 100644
--- a/libstdc++-v3/testsuite/std/format/string_neg.cc
+++ b/libstdc++-v3/testsuite/std/format/string_neg.cc
@@ -8,3 +8,5 @@ auto s = std::format(" {9} "); // { dg-error "call to consteval function" }
struct X { };
std::format_string<X> str(""); // { dg-error "here" }
// { dg-error "std::formatter must be specialized" "" { target *-*-* } 0 }
+
+// { dg-prune-output "use of deleted function" }
diff --git a/libstdc++-v3/testsuite/std/format/tuple.cc b/libstdc++-v3/testsuite/std/format/tuple.cc
index 62f9d29..eace827 100644
--- a/libstdc++-v3/testsuite/std/format/tuple.cc
+++ b/libstdc++-v3/testsuite/std/format/tuple.cc
@@ -1,4 +1,6 @@
// { dg-do run { target c++23 } }
+// { dg-options "-fexec-charset=UTF-8" }
+// { dg-timeout-factor 2 }
#include <format>
#include <string>
@@ -37,7 +39,7 @@ is_format_string_for(const wchar_t* str, Args&&... args)
}
#define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S)
-#define WIDEN(S) WIDEN_(_CharT, S)
+#define WIDEN(S) WIDEN_(CharT, S)
void
test_format_string()
@@ -60,13 +62,13 @@ test_format_string()
VERIFY( !is_format_string_for("{:{}}", std::tuple<>(), 1.0f) );
}
-template<typename _CharT>
+template<typename CharT>
void test_multi()
{
- using Sv = std::basic_string_view<_CharT>;
- using Str = std::basic_string<_CharT>;
+ using Sv = std::basic_string_view<CharT>;
+ using Str = std::basic_string<CharT>;
- std::basic_string<_CharT> res;
+ std::basic_string<CharT> res;
std::size_t size = 0;
std::tuple<int, Str, float> t1(1, WIDEN("test"), 2.1);
@@ -120,10 +122,10 @@ void test_multi()
}
-template<typename _CharT, typename Tuple>
+template<typename CharT, typename Tuple>
void test_empty()
{
- std::basic_string<_CharT> res;
+ std::basic_string<CharT> res;
Tuple e1;
res = std::format(WIDEN("{}"), e1);
@@ -139,13 +141,13 @@ void test_empty()
VERIFY( res == WIDEN(R"(^^^^())") );
}
-template<typename _CharT, typename Pair>
+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;
+ std::basic_string<CharT> res;
Ft f1 = 1;
St s1 = WIDEN("abc");
@@ -185,7 +187,6 @@ struct std::formatter<MyPair<Pair>, CharT>
{
constexpr formatter() noexcept
{
- using _CharT = CharT;
_formatter.set_brackets(WIDEN("<"), WIDEN(">"));
_formatter.set_separator(WIDEN("; "));
}
@@ -204,11 +205,11 @@ private:
std::formatter<Pair, CharT> _formatter;
};
-template<typename _CharT, template<typename, typename> class PairT>
+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"));
+ 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">)") );
@@ -250,10 +251,137 @@ void test_nested()
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) );
+}
+
+struct Custom {};
+
+template<typename CharT>
+struct std::formatter<Custom, CharT>
+{
+ constexpr std::basic_format_parse_context<CharT>::iterator
+ parse(const std::basic_format_parse_context<CharT>& pc)
+ { return pc.begin(); }
+
+ template<typename Out>
+ typename std::basic_format_context<Out, CharT>::iterator
+ format(Custom, const std::basic_format_context<Out, CharT>& fc) const
+ { return fc.out(); }
+};
+
+template<template<typename...> typename Tuple>
+void test_nonblocking()
+{
+ static_assert(std::enable_nonlocking_formatter_optimization<
+ Tuple<int, float>>);
+ static_assert(std::enable_nonlocking_formatter_optimization<
+ Tuple<const int, const float>>);
+ static_assert(std::enable_nonlocking_formatter_optimization<
+ Tuple<int&, float&>>);
+
+ static_assert(!std::enable_nonlocking_formatter_optimization<
+ Tuple<Custom, float>>);
+ static_assert(!std::enable_nonlocking_formatter_optimization<
+ Tuple<const Custom, const float>>);
+ static_assert(!std::enable_nonlocking_formatter_optimization<
+ Tuple<Custom&, float&>>);
+}
+
int main()
{
test_format_string();
test_outputs<char>();
test_outputs<wchar_t>();
test_nested();
+ test_padding();
+
+ test_nonblocking<std::pair>();
+ test_nonblocking<std::tuple>();
}
diff --git a/libstdc++-v3/testsuite/std/memory/indirect/access.cc b/libstdc++-v3/testsuite/std/memory/indirect/access.cc
new file mode 100644
index 0000000..cf21275
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/memory/indirect/access.cc
@@ -0,0 +1,58 @@
+// { dg-do run { target c++26 } }
+
+#include <memory>
+#include <vector>
+
+#include <testsuite_hooks.h>
+
+template<template<typename> class Indirect>
+constexpr void
+test_access()
+{
+ const std::vector<int> src{1, 2, 3, 4, 5};
+ Indirect<std::vector<int>> i(src);
+ auto const& ci = i;
+ VERIFY( *i == src );
+ VERIFY( *ci == src );
+ VERIFY( *std::move(ci) == src );
+
+ std::vector<int>&& vr = *std::move(i);
+ VERIFY( vr == src );
+ VERIFY( *i == src );
+
+ std::vector<int> vc = *std::move(i);
+ VERIFY( vc == src );
+ VERIFY( vr.empty() );
+ VERIFY( i->empty() );
+ VERIFY( ci->empty() );
+}
+
+template<typename T>
+struct PublicBase : std::indirect<T>
+{
+ using std::indirect<T>::indirect;
+};
+
+template<typename T>
+class PrivateBase : std::indirect<T>
+{
+public:
+ using std::indirect<T>::indirect;
+ using std::indirect<T>::operator*;
+ using std::indirect<T>::operator->;
+};
+
+constexpr bool
+test_all()
+{
+ test_access<std::indirect>();
+ test_access<PublicBase>();
+ test_access<PrivateBase>();
+ return true;
+}
+
+int main()
+{
+ test_all();
+ static_assert(test_all());
+}
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..5ecfbbd
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/memory/indirect/copy.cc
@@ -0,0 +1,156 @@
+// { 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});
+
+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 );
+}
+
+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 );
+}
+
+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_constexpr()
+{
+ using Alloc = __gnu_test::uneq_allocator<Vector>;
+ using Indirect = std::indirect<Vector, Alloc>;
+ const Indirect src(std::in_place, {1, 2, 3});
+
+ Indirect i1(src);
+ VERIFY( *i1 == *src );
+ VERIFY( &*i1 != &*src );
+ VERIFY( i1.get_allocator() == Alloc{} );
+
+ Indirect i2(std::allocator_arg, Alloc{2}, src);
+ VERIFY( *i2 == *src );
+ VERIFY( &*i2 != &*src );
+ VERIFY( i2.get_allocator() == Alloc{2} );
+
+ Indirect i3(std::allocator_arg, Alloc{3});
+ i3 = src;
+ VERIFY( *i3 == *src );
+ VERIFY( &*i3 != &*src );
+ VERIFY( i3.get_allocator() == Alloc{3} );
+
+ Indirect e;
+ auto(std::move(e));
+ VERIFY( e.valueless_after_move() );
+
+ Indirect e1(e);
+ VERIFY( e1.valueless_after_move() );
+
+ Indirect e2(std::allocator_arg, {}, e);
+ VERIFY( e2.valueless_after_move() );
+
+ i3 = e;
+ VERIFY( i3.valueless_after_move() );
+
+ i3 = e;
+ VERIFY( i3.valueless_after_move() );
+}
+
+int main()
+{
+ test_ctor();
+ test_assign();
+ test_valueless();
+ test_constexpr();
+
+ static_assert([] {
+ test_constexpr();
+ 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..e48855a
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/memory/indirect/copy_alloc.cc
@@ -0,0 +1,222 @@
+// { 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>
+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>
+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>
+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>();
+}
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..dfd9341
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/memory/indirect/ctor.cc
@@ -0,0 +1,213 @@
+// { 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 );
+
+ if (std::is_constant_evaluated())
+ return;
+
+ // 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 );
+
+ if (std::is_constant_evaluated())
+ return;
+
+ 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 );
+
+ if (std::is_constant_evaluated())
+ return;
+
+ 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..9800f7f
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/memory/indirect/move.cc
@@ -0,0 +1,201 @@
+// { 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});
+
+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 );
+}
+
+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();
+}
+
+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();
+}
+
+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();
+}
+
+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_constexpr()
+{
+ using Alloc = __gnu_test::uneq_allocator<Vector>;
+ using Indirect = std::indirect<Vector, Alloc>;
+ const Indirect val(std::in_place, {1, 2, 3});
+
+ std::optional<Indirect> src;
+ auto make = [&src, &val] -> Indirect&& {
+ src.emplace(val);
+ return std::move(*src);
+ };
+
+ Indirect i1(make());
+ VERIFY( src->valueless_after_move() );
+ VERIFY( *i1 == *val );
+
+ Indirect i2(std::allocator_arg, {}, make());
+ VERIFY( src->valueless_after_move() );
+ VERIFY( *i2 == *val );
+
+ i2 = make();
+ VERIFY( src->valueless_after_move() );
+ VERIFY( *i2 == *val );
+
+ auto(std::move(i2));
+ i2 = make();
+ VERIFY( *i2 == *val );
+ VERIFY( src->valueless_after_move() );
+
+ const Indirect val1(std::in_place, {1, 2, 3});
+ const Indirect val2(std::in_place, {2, 4, 6});
+
+ Indirect s1(val1);
+ Indirect s2(val2);
+ s1.swap(s2);
+ VERIFY( *s2 == *val1 );
+ VERIFY( *s1 == *val2 );
+
+ auto(std::move(s1));
+
+ s1.swap(s2);
+ VERIFY( *s1 == *val1 );
+ VERIFY( s2.valueless_after_move() );
+
+ auto e = [] {
+ Indirect res;
+ auto(std::move(res));
+ return res;
+ };
+
+ Indirect e1(e());
+ VERIFY( e1.valueless_after_move() );
+
+ Indirect e2(std::allocator_arg, {}, e());
+ VERIFY( e2.valueless_after_move() );
+
+ Indirect e3(val);
+ e3 = e();
+ e3 = e();
+}
+
+int main()
+{
+ test_ctor();
+ test_assign();
+ test_swap();
+ test_valueless();
+ test_constexpr();
+
+ static_assert([] {
+ test_constexpr();
+ 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..cf35e83
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/memory/indirect/move_alloc.cc
@@ -0,0 +1,290 @@
+// { 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;
+
+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>
+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>
+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>
+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>
+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>
+void
+test_all()
+{
+ test_ctor<Propagate>();
+ test_assign<Propagate>();
+ test_swap<Propagate>();
+ test_valueless<Propagate>();
+}
+
+int main()
+{
+ test_all<true>();
+ test_all<false>();
+}
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..77d599c
--- /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/access.cc b/libstdc++-v3/testsuite/std/memory/polymorphic/access.cc
new file mode 100644
index 0000000..7b95bb1
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/memory/polymorphic/access.cc
@@ -0,0 +1,53 @@
+// { dg-do run { target c++26 } }
+
+#include <memory>
+#include <vector>
+
+#include <testsuite_hooks.h>
+
+template<template<typename> class Polymorhpic>
+constexpr void
+test_access()
+{
+ const std::vector<int> src{1, 2, 3, 4, 5};
+ Polymorhpic<std::vector<int>> i(src);
+ auto const& ci = i;
+ VERIFY( *i == src );
+ VERIFY( *ci == src );
+ VERIFY( *std::move(ci) == src );
+
+ auto&& vr = *std::move(i);
+ static_assert( std::is_same_v<decltype(vr), std::vector<int>&> );
+ VERIFY( vr == src );
+ VERIFY( *i == src );
+}
+
+template<typename T>
+struct PublicBase : std::polymorphic<T>
+{
+ using std::polymorphic<T>::polymorphic;
+};
+
+template<typename T>
+class PrivateBase : std::polymorphic<T>
+{
+public:
+ using std::polymorphic<T>::polymorphic;
+ using std::polymorphic<T>::operator*;
+ using std::polymorphic<T>::operator->;
+};
+
+constexpr bool
+test_all()
+{
+ test_access<std::polymorphic>();
+ test_access<PublicBase>();
+ test_access<PrivateBase>();
+ return true;
+}
+
+int main()
+{
+ test_all();
+// static_assert(test_all());
+}
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..34c7822
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/memory/polymorphic/copy.cc
@@ -0,0 +1,192 @@
+// { 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 Polymorphic = std::polymorphic<Base, tracker_allocator<Base>>;
+const Polymorphic src(std::in_place_type<Derived>, 1, 2, 3);
+
+void
+test_ctor()
+{
+ Counter::reset();
+ Polymorphic 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();
+ Polymorphic 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 );
+}
+
+void
+test_assign()
+{
+ Counter::reset();
+ Polymorphic 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 );
+}
+
+void
+test_valueless()
+{
+ Polymorphic e(std::in_place_type<Derived>);
+ auto(std::move(e));
+ VERIFY( e.valueless_after_move() );
+
+ Counter::reset();
+ Polymorphic 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 );
+
+ Polymorphic 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 );
+
+ Polymorphic 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_constexpr()
+{
+ using Polymorphic = std::polymorphic<Base, __gnu_test::uneq_allocator<Base>>;
+ const Polymorphic src(std::in_place_type<Derived>, 1, 2, 3);
+
+ Polymorphic i1(src);
+ VERIFY( *i1 == *src );
+ VERIFY( &*i1 != &*src );
+
+ Polymorphic i2(std::allocator_arg, {}, src);
+ VERIFY( *i2 == *src );
+ VERIFY( &*i2 != &*src );
+
+ i1 = Polymorphic(std::in_place_type<Derived>);
+ VERIFY( *i1 != *src );
+ i1 = src;
+ VERIFY( *i1 == *src );
+ VERIFY( &*i1 != &*src );
+
+ auto(std::move(i1));
+ i1 = src;
+ VERIFY( *i1 == *src );
+ VERIFY( &*i1 != &*src );
+
+ Polymorphic e(std::in_place_type<Derived>);
+ auto(std::move(e));
+ VERIFY( e.valueless_after_move() );
+
+ Polymorphic e1(e);
+ VERIFY( e1.valueless_after_move() );
+
+ Polymorphic e2(std::allocator_arg, {}, e);
+ VERIFY( e2.valueless_after_move() );
+
+ Polymorphic e3(src);
+ e3 = e;
+ VERIFY( e3.valueless_after_move() );
+}
+
+int main()
+{
+ test_ctor();
+ test_assign();
+ test_valueless();
+ test_constexpr();
+
+ static_assert([] {
+ test_constexpr();
+ 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..f149fc8
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/memory/polymorphic/copy_alloc.cc
@@ -0,0 +1,264 @@
+// { 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
+ bool operator==(const Base& lhs, const Base& rhs)
+ { return lhs.eq(rhs); }
+
+ virtual int
+ get_alloc_personality() const
+ { return -1; }
+
+private:
+ 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;
+
+ int
+ get_alloc_personality() const override
+ { return this->get_allocator().get_personality(); }
+
+private:
+
+ 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>
+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>
+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>
+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>
+void
+test_all()
+{
+ test_ctor<Propagate>();
+ test_assign<Propagate>();
+ test_valueless<Propagate>();
+}
+
+int main()
+{
+ test_all<true>();
+ test_all<false>();
+}
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..4d043db
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/memory/polymorphic/ctor.cc
@@ -0,0 +1,199 @@
+// { 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 );
+
+ if (std::is_constant_evaluated())
+ return;
+
+ // 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);
+
+ if (std::is_constant_evaluated())
+ return;
+
+ 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 );
+
+ if (std::is_constant_evaluated())
+ return;
+
+ 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..cb18031
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/memory/polymorphic/ctor_poly.cc
@@ -0,0 +1,226 @@
+// { 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 );
+
+ if (std::is_constant_evaluated())
+ return;
+
+ 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 );
+
+ if (std::is_constant_evaluated())
+ return;
+
+ 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..97e598e
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/memory/polymorphic/move.cc
@@ -0,0 +1,232 @@
+// { 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);
+
+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 );
+}
+
+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();
+}
+
+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();
+}
+
+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();
+}
+
+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_constexpr()
+{
+ using Polymorphic = std::polymorphic<Base, __gnu_test::uneq_allocator<Base>>;
+ const Polymorphic val(std::in_place_type<Derived>, 1, 2, 3);
+
+ std::optional<Polymorphic> src;
+ auto make = [&src, &val] -> Polymorphic&& {
+ src.emplace(val);
+ return std::move(*src);
+ };
+
+ Polymorphic i1(make());
+ VERIFY( src->valueless_after_move() );
+ VERIFY( *i1 == *val );
+
+ Polymorphic i2(std::allocator_arg, {}, make());
+ VERIFY( src->valueless_after_move() );
+ VERIFY( *i2 == *val );
+
+ i1 = make();
+ VERIFY( src->valueless_after_move() );
+ VERIFY( *i1 == *val );
+
+ auto(std::move(i1));
+ i1 = make();
+ VERIFY( *i1 == *val );
+ VERIFY( src->valueless_after_move() );
+
+ const Polymorphic val1(std::in_place_type<Derived>, 1, 2, 3);
+ const Polymorphic val2(std::in_place_type<Derived>, 2, 4, 6);
+
+ Polymorphic s1(val1);
+ Polymorphic s2(val2);
+ s1.swap(s2);
+ VERIFY( *s2 == *val1 );
+ VERIFY( *s1 == *val2 );
+
+ auto(std::move(s1));
+ s1.swap(s2);
+ VERIFY( *s1 == *val1 );
+ VERIFY( s2.valueless_after_move() );
+
+ auto e = [] {
+ Polymorphic res(std::in_place_type<Derived>);
+ auto(std::move(res));
+ return res;
+ };
+
+ Polymorphic e1(e());
+ VERIFY( e1.valueless_after_move() );
+
+ Polymorphic e2(std::allocator_arg, {}, e());
+ VERIFY( e2.valueless_after_move() );
+
+ Polymorphic e3(val);
+ e3 = e();
+ e3 = e();
+}
+
+int main()
+{
+ test_ctor();
+ test_assign();
+ test_swap();
+ test_valueless();
+ test_constexpr();
+
+ static_assert([] {
+ test_constexpr();
+ 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..490bffb
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/memory/polymorphic/move_alloc.cc
@@ -0,0 +1,333 @@
+// { 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;
+
+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>
+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>
+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>
+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>
+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>
+void
+test_all()
+{
+ test_ctor<Propagate>();
+ test_assign<Propagate>();
+ test_swap<Propagate>();
+ test_valueless<Propagate>();
+}
+
+int main()
+{
+ test_all<true>();
+ test_all<false>();
+}
diff --git a/libstdc++-v3/testsuite/std/memory/start_lifetime_as/start_lifetime_as.cc b/libstdc++-v3/testsuite/std/memory/start_lifetime_as/start_lifetime_as.cc
new file mode 100644
index 0000000..c32e4de
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/memory/start_lifetime_as/start_lifetime_as.cc
@@ -0,0 +1,94 @@
+// { dg-do run { target c++23 } }
+
+#include <bit>
+#include <memory>
+
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct S { int a; int b; };
+struct T { long long c; };
+
+template<typename S, typename T>
+void
+test01()
+{
+}
+
+template<typename S, typename T>
+requires (sizeof(S) == sizeof(T))
+void
+test01()
+{
+ union U { unsigned char a[sizeof(S)]; S b; T c; } u;
+ u.a[0] = 1;
+ T v = std::bit_cast<T> (S{1, 2});
+ union V { unsigned char a[3 * sizeof(S)]; S b[3]; T c[3]; } w;
+ T x = std::bit_cast<T> (S{3, 4});
+ T y = std::bit_cast<T> (S{5, 6});
+ S* d = std::start_lifetime_as<S>(reinterpret_cast<void*>(&u.a));
+ d->a = 1;
+ d->b = 2;
+ T* e = std::start_lifetime_as<T>(reinterpret_cast<void*>(d));
+ VERIFY( e->c == v.c );
+ const T* f = std::start_lifetime_as<T>(reinterpret_cast<const void*>(d));
+ VERIFY( f->c == v.c );
+ volatile T* g
+ = std::start_lifetime_as<T>(reinterpret_cast<volatile void*>(d));
+ VERIFY( g->c == v.c );
+ const volatile T* h
+ = std::start_lifetime_as<T>(reinterpret_cast<const volatile void*>(d));
+ VERIFY( h->c == v.c );
+ S* i = std::start_lifetime_as_array<S>(reinterpret_cast<void*>(&w.a), 3);
+ i[0].a = 1;
+ i[0].b = 2;
+ i[1].a = 3;
+ i[1].b = 4;
+ i[2].a = 5;
+ i[2].b = 6;
+ T* j = std::start_lifetime_as_array<T>(reinterpret_cast<void*>(i), 3);
+ VERIFY( j[0].c == v.c && j[1].c == x.c && j[2].c == y.c );
+ const T* k
+ = std::start_lifetime_as_array<T>(reinterpret_cast<const void*>(i), 3);
+ VERIFY( k[0].c == v.c && k[1].c == x.c && k[2].c == y.c );
+ volatile T* l
+ = std::start_lifetime_as_array<T>(reinterpret_cast<volatile void*>(i), 3);
+ VERIFY( l[0].c == v.c && l[1].c == x.c && l[2].c == y.c );
+ const volatile T* m
+ = std::start_lifetime_as_array<T>(reinterpret_cast<const volatile void*>(i),
+ 3);
+ VERIFY( m[0].c == v.c && m[1].c == x.c && m[2].c == y.c );
+ T* n = std::start_lifetime_as_array<T>(static_cast<void*>(nullptr), 0);
+ VERIFY( n == nullptr );
+ const T* o
+ = std::start_lifetime_as_array<T>(static_cast<const void*>(nullptr), 0);
+ VERIFY( o == nullptr );
+ volatile T* p
+ = std::start_lifetime_as_array<T>(static_cast<volatile void*>(nullptr), 0);
+ VERIFY( p == nullptr );
+ const volatile T* q
+ = std::start_lifetime_as_array<T>(static_cast<const volatile void*>(nullptr),
+ 0);
+ VERIFY( q == nullptr );
+ VERIFY( std::start_lifetime_as_array<T>(reinterpret_cast<void*>(&w.a), 0)
+ == &w.c[0] );
+ VERIFY( std::start_lifetime_as_array<T>(reinterpret_cast<const void*>(&w.a), 0)
+ == static_cast<const T*>(&w.c[0]) );
+ VERIFY( std::start_lifetime_as_array<T>(reinterpret_cast<volatile void*>(&w.a),
+ 0)
+ == static_cast<volatile T*>(&w.c[0]) );
+ VERIFY( std::start_lifetime_as_array<T>(reinterpret_cast<const volatile void*>(&w.a),
+ 0)
+ == static_cast<const volatile T*>(&w.c[0]) );
+ static const S r[] = { { 5, 6 }, { 3, 4 } };
+ const T* s = std::start_lifetime_as<T>(&r[1]);
+ VERIFY( s->c == x.c );
+ const T* t = std::start_lifetime_as_array<T>(&r[0], 2);
+ VERIFY( t[0].c == y.c && t[1].c == x.c );
+}
+
+int
+main()
+{
+ test01<S, T>();
+}
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent/1.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent/1.cc
index 085cd4a..0a5c67f 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent/1.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent/1.cc
@@ -114,6 +114,18 @@ test04()
return true;
}
+constexpr bool
+test05()
+{
+ // PR libstdc++/121956
+ int a[2]{};
+ __gnu_test::test_random_access_range r(a);
+ auto v = r | views::pairwise;
+ static_assert( std::is_same_v<ranges::range_value_t<decltype(v)>,
+ std::tuple<int, int>> );
+ return true;
+}
+
int
main()
{
@@ -121,4 +133,5 @@ main()
static_assert(test02());
static_assert(test03());
static_assert(test04());
+ static_assert(test05());
}
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent_transform/1.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent_transform/1.cc
index 772e4b3..6890618 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent_transform/1.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent_transform/1.cc
@@ -113,6 +113,47 @@ test04()
static_assert( requires { x | views::pairwise_transform(move_only{}); } );
}
+template<size_t FuncSize, typename Fn>
+void
+test05(Fn f)
+{
+ int x[] = {1,2,3,4,5,6};
+ auto v = x | views::pairwise_transform(f);
+ static_assert(sizeof(v.begin()) == 2*sizeof(int*) + FuncSize);
+}
+
+void
+test05all()
+{
+ test05<0>(std::equal_to<>());
+ test05<0>(std::equal_to<>());
+ test05<0>(std::not_equal_to<>());
+ test05<0>(std::greater<>());
+ test05<0>(std::less<>());
+ test05<0>(std::greater_equal<>());
+ test05<0>(std::less_equal<>());
+
+ test05<0>(std::ranges::equal_to());
+ test05<0>(std::ranges::not_equal_to());
+ test05<0>(std::ranges::greater());
+ test05<0>(std::ranges::less());
+ test05<0>(std::ranges::greater_equal());
+ test05<0>(std::ranges::less_equal());
+
+ test05<0>(std::plus<>());
+ test05<0>(std::minus<>());
+ test05<0>(std::multiplies<>());
+ test05<0>(std::divides<>());
+ test05<0>(std::modulus<>());
+
+ test05<0>(std::logical_and<>());
+ test05<0>(std::logical_or<>());
+
+ test05<0>(std::bit_and<>());
+ test05<0>(std::bit_or<>());
+ test05<0>(std::bit_xor<>());
+}
+
int
main()
{
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/drop.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/drop.cc
index 4583fb0..57db806 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/drop.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/drop.cc
@@ -243,7 +243,7 @@ test08()
long b[10]{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
test_range<long, ra_test_wrapper> rb(b);
- ranges::subrange sized = {rb.begin(), rb.begin()+6};
+ ranges::subrange sized = {rb.begin(), ranges::next(rb.begin(), 6)};
using Sized = decltype(sized);
static_assert( ranges::random_access_range<Sized> );
static_assert( ranges::sized_range<Sized> );
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/join.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/join.cc
index 2861115..db77490 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/join.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/join.cc
@@ -233,6 +233,24 @@ test14()
VERIFY( ranges::equal(v | views::join, (int[]){1, 2, 3}) );
}
+void
+test15()
+{
+ // PR libstdc++/119962 - __maybe_present_t misses initialization
+ constexpr decltype(views::join(views::single(views::single(0))).begin()) it;
+}
+
+void
+test16()
+{
+ // PR libstdc++/121804 - join_view::iterator::_M_get_inner should be noexcept
+ std::vector<std::vector<int>> vv;
+ ranges::join_view j{vv};
+ auto jit = j.begin();
+ static_assert(noexcept(ranges::iter_move(jit)));
+ static_assert(noexcept(ranges::iter_swap(jit, jit)));
+}
+
int
main()
{
@@ -250,4 +268,6 @@ main()
test12();
test13();
test14();
+ test15();
+ test16();
}
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/join_with/1.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/join_with/1.cc
index 8ab30a5..4d55c9d 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/join_with/1.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/join_with/1.cc
@@ -94,6 +94,13 @@ test04()
return true;
}
+void
+test05()
+{
+ // PR libstdc++/119962 - __maybe_present_t misses initialization
+ constexpr decltype(views::join_with(views::single(views::single(0)), 0).begin()) it;
+}
+
int
main()
{
@@ -105,4 +112,5 @@ main()
#else
VERIFY(test04());
#endif
+ test05();
}
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/lazy_split.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/lazy_split.cc
index 81fc60b..321ae27 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/lazy_split.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/lazy_split.cc
@@ -232,6 +232,13 @@ test12()
return true;
}
+void
+test13()
+{
+ // PR libstdc++/119962 - __maybe_present_t misses initialization
+ constexpr decltype(views::lazy_split(views::single(0), 0).begin()) it;
+}
+
int
main()
{
@@ -247,4 +254,5 @@ main()
test10();
test11();
static_assert(test12());
+ test13();
}
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/take.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/take.cc
index 1673772..9584c57 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/take.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/take.cc
@@ -118,6 +118,20 @@ test06()
static_assert(!requires { views::all | take; });
}
+void
+test07()
+{
+ // PR libstdc++/111550
+ struct Five {
+ operator int() & { return 5; }
+ operator int() && = delete;
+ };
+ auto take_five = views::take(Five{});
+ auto r = take_five(views::iota(0));
+ auto take_five_piped = views::take(Five{}) | views::transform(std::identity{});
+ auto s = take_five_piped(views::iota(0));
+}
+
int
main()
{
@@ -127,4 +141,5 @@ main()
test04();
test05();
test06();
+ test07();
}
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc
index 1788db1..3a21a1f 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc
@@ -18,6 +18,7 @@
// { dg-do run { target c++20 } }
#include <algorithm>
+#include <cstdint>
#include <ranges>
#include <testsuite_hooks.h>
#include <testsuite_iterators.h>
@@ -28,12 +29,12 @@ using __gnu_test::random_access_iterator_wrapper;
namespace ranges = std::ranges;
namespace views = std::ranges::views;
+template<typename Fn>
void
-test01()
+test01(Fn f)
{
int x[] = {1,2,3,4,5};
- auto is_odd = [] (int i) { return i%2==1; };
- auto v = x | views::transform(is_odd);
+ auto v = x | views::transform(f);
VERIFY( ranges::equal(v, (int[]){1,0,1,0,1}) );
using R = decltype(v);
static_assert(std::same_as<bool, decltype(*ranges::begin(v))>);
@@ -42,24 +43,51 @@ test01()
static_assert(ranges::random_access_range<R>);
}
+void
+test01a()
+{
+ auto is_odd = [] (int i) { return i%2==1; };
+ test01(is_odd);
+}
+
+void
+test01b()
+{
+#if __cpp_static_call_operator >= 202207L
+ auto is_odd = [] (int i) static { return i%2==1; };
+ test01(is_odd);
+#endif
+}
+
+void
+test01c()
+{
+ bool(*is_odd)(int) = [] (int i) { return i%2==1; };
+ test01(is_odd);
+}
+
struct X
{
int i,j;
+ int& first() { return i; }
};
+template<size_t FuncSize, typename Fn>
void
-test02()
+test02(Fn f)
{
X x[] = {{1,2},{3,4},{5,6},{7,8},{9,10}};
test_range<X, random_access_iterator_wrapper> rx(x);
- auto v = rx | views::transform(&X::i);
+ auto v = rx | views::transform(f);
VERIFY( ranges::size(v) == 5 );
VERIFY( ranges::distance(v.begin(), v.end()) == 5 );
VERIFY( ranges::equal(v, (int[]){1,3,5,7,9}) );
VERIFY( ranges::equal(v | views::reverse, (int[]){9,7,5,3,1}) );
using R = decltype(v);
+ using It = ranges::iterator_t<R>;
static_assert(std::same_as<int&, decltype(*ranges::begin(v))>);
- static_assert(std::same_as<int, std::iter_value_t<ranges::iterator_t<R>>>);
+ static_assert(std::same_as<int, std::iter_value_t<It>>);
+ static_assert(sizeof(It) == sizeof(rx.begin()) + FuncSize);
static_assert(ranges::view<R>);
static_assert(ranges::sized_range<R>);
static_assert(!ranges::common_range<R>);
@@ -67,6 +95,73 @@ test02()
}
void
+test02a()
+{ test02<sizeof(int X::*)>(&X::i); }
+
+void
+test02b()
+{ test02<sizeof(int(X::*)())>(&X::first); }
+
+void
+test02c()
+{
+ auto first = [](X& x) -> int& { return x.i; };
+ test02<sizeof(void*)>(first);
+}
+
+void
+test02d()
+{
+#if __cpp_static_call_operator >= 202207L
+ auto first = [](X& x) static -> int& { return x.i; };
+ test02<0>(first);
+#endif
+}
+
+void
+test02e()
+{
+ int&(*fptr)(X&) = [](X& x) -> int& { return x.i; };
+ test02<sizeof(void(*)())>(fptr);
+}
+
+void
+test02f()
+{
+#if __cpp_static_call_operator >= 202207L
+ struct PickStatic
+ {
+ static constexpr int&
+ operator()(X& x)
+ { return x.i; }
+
+ constexpr int
+ operator()(char*) const
+ { return 0; };
+ };
+ test02<0>(PickStatic{});
+#endif
+}
+
+void
+test02g()
+{
+#if __cpp_static_call_operator >= 202207L
+ struct PickObject
+ {
+ constexpr int&
+ operator()(X& x) const
+ { return x.i; }
+
+ static constexpr int
+ operator()(char*)
+ { return 0; };
+ };
+ test02<sizeof(void*)>(PickObject{});
+#endif
+}
+
+void
test03()
{
auto id = [] (int i) { return i; };
@@ -227,11 +322,75 @@ test11()
static_assert(std::same_as<cat, std::random_access_iterator_tag>);
}
+void
+test12()
+{
+ struct Obfuscate
+ {
+ int operator()(int x) const
+ { return x + reinterpret_cast<std::uintptr_t>(this); }
+ };
+
+ int x[]{1, 2, 3, 4, 5};
+ auto v = x | views::transform(Obfuscate{});
+ VERIFY( ranges::equal(v, v) );
+};
+
+void
+test13()
+{
+#if __cpp_static_call_operator >= 202207L
+ struct StaticWins {
+ static int operator()(int i) { return 0; }
+ int operator()(float f) const { return 1; }
+ };
+
+ int x[]{1, 2, 3, 4, 5};
+ auto vs = x | views::transform(StaticWins{});
+ VERIFY( vs.front() == 0 );
+ static_assert( sizeof(vs.begin()) == sizeof(int*) );
+
+ struct MemberWins {
+ static int operator()(float f) { return 0; }
+ int operator()(int i) const { return 1; }
+ };
+
+ auto vm = x | views::transform(MemberWins{});
+ VERIFY( vm.front() == 1 );
+ static_assert( sizeof(vm.begin()) > sizeof(int*) );
+#endif
+}
+
+template<size_t FuncSize, typename Fn>
+void
+test14(Fn f)
+{
+ int x[] = {1,2,3,4,5,6};
+ auto v = x | views::transform(std::negate<>());
+ static_assert(sizeof(v.begin()) == sizeof(int*) + FuncSize);
+}
+
+void
+test14all()
+{
+ test14<0>(std::identity());
+ test14<0>(std::negate<>());
+ test14<0>(std::bit_not<>());
+}
+
int
main()
{
- test01();
- test02();
+ test01a();
+ test01b();
+ test01c();
+ test02a();
+ test02b();
+ test02c();
+ test02d();
+ test02e();
+ test02f();
+ test02g();
test03();
test04();
test05();
@@ -241,4 +400,7 @@ main()
test09();
test10();
test11();
+ test12();
+ test13();
+ test14all();
}
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/indices/1.cc b/libstdc++-v3/testsuite/std/ranges/indices/1.cc
new file mode 100644
index 0000000..038b38f
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/ranges/indices/1.cc
@@ -0,0 +1,45 @@
+// { dg-do run { target c++26 } }
+
+#include <testsuite_hooks.h>
+
+#include <ranges>
+#include <type_traits>
+#include <stddef.h>
+
+template <typename T>
+constexpr bool test(T n) {
+ auto indices_view = std::ranges::views::indices(n);
+ static_assert(
+ std::is_same_v<T, std::ranges::range_value_t<decltype(indices_view)>>);
+ static_assert(noexcept(std::ranges::views::indices(n)));
+
+ VERIFY(indices_view.size() == n);
+ for (T i = 0; i < n; ++i) VERIFY(indices_view[i] == i);
+
+ return true;
+}
+
+int main() {
+ VERIFY(test<int>(41));
+ static_assert(test<int>(41));
+ VERIFY(test<short>(42));
+ static_assert(test<short>(42));
+ VERIFY(test<long>(43));
+ static_assert(test<long>(43));
+ VERIFY(test<size_t>(44));
+ static_assert(test<size_t>(44));
+}
+
+template<typename T>
+constexpr size_t test_wider(T n)
+{
+ // If indices(n) works, try again with ranges::distance(indices(n)),
+ // which will be a wider type, until we get to an unsupported type.
+ // This verifies that indices(n) is SFINAE-friendly, because otherwise we
+ // would get a hard error outside the immediate context checked by requires.
+ if constexpr (requires { std::views::indices(n); })
+ return test_wider(std::ranges::distance(std::views::indices(n)));
+ return sizeof(T);
+}
+
+static_assert(test_wider(0) > sizeof(long long));
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..fbd783b 100644
--- a/libstdc++-v3/testsuite/std/ranges/iota/max_size_type.cc
+++ b/libstdc++-v3/testsuite/std/ranges/iota/max_size_type.cc
@@ -352,6 +352,9 @@ static_assert(numeric_limits<max_size_t>::is_specialized);
static_assert(!numeric_limits<max_size_t>::is_signed);
static_assert(numeric_limits<max_size_t>::is_integer);
static_assert(numeric_limits<max_size_t>::is_exact);
+static_assert(numeric_limits<max_size_t>::is_bounded);
+static_assert(numeric_limits<max_size_t>::is_modulo);
+static_assert(numeric_limits<max_size_t>::radix == 2);
// We can't unconditionally use numeric_limits here because __int128 is an
// integral type only in GNU mode.
#if __SIZEOF_INT128__
@@ -379,6 +382,9 @@ static_assert(numeric_limits<max_diff_t>::is_specialized);
static_assert(numeric_limits<max_diff_t>::is_signed);
static_assert(numeric_limits<max_diff_t>::is_integer);
static_assert(numeric_limits<max_diff_t>::is_exact);
+static_assert(numeric_limits<max_diff_t>::is_bounded);
+static_assert(!numeric_limits<max_diff_t>::is_modulo);
+static_assert(numeric_limits<max_diff_t>::radix == 2);
static_assert(numeric_limits<max_diff_t>::digits
== numeric_limits<max_size_t>::digits - 1);
static_assert(numeric_limits<max_diff_t>::digits10
@@ -400,6 +406,38 @@ static_assert(max_diff_t(max_size_t(1)
<< (numeric_limits<max_size_t>::digits-1))
== numeric_limits<max_diff_t>::min());
+template <typename integer_class>
+constexpr bool verify_numeric_limits_values_not_meaningful_for = true
+ && (numeric_limits<integer_class>::max_digits10 == 0)
+ && (numeric_limits<integer_class>::min_exponent == 0)
+ && (numeric_limits<integer_class>::min_exponent10 == 0)
+ && (numeric_limits<integer_class>::max_exponent == 0)
+ && (numeric_limits<integer_class>::max_exponent10 == 0)
+ && !numeric_limits<integer_class>::is_iec559
+ && !numeric_limits<integer_class>::has_infinity
+ && !numeric_limits<integer_class>::has_quiet_NaN
+ && !numeric_limits<integer_class>::has_signaling_NaN
+ && !numeric_limits<integer_class>::has_denorm_loss
+ && !numeric_limits<integer_class>::tinyness_before
+ && (numeric_limits<integer_class>::has_denorm == std::denorm_absent)
+ && (numeric_limits<integer_class>::round_style == std::round_toward_zero)
+ && (numeric_limits<integer_class>::denorm_min() == 0)
+ && (numeric_limits<integer_class>::epsilon() == 0)
+ && (numeric_limits<integer_class>::round_error() == 0)
+ && (numeric_limits<integer_class>::infinity() == 0)
+ && (numeric_limits<integer_class>::quiet_NaN() == 0)
+ && (numeric_limits<integer_class>::signaling_NaN() == 0);
+
+static_assert(verify_numeric_limits_values_not_meaningful_for<max_size_t>);
+static_assert(verify_numeric_limits_values_not_meaningful_for<max_diff_t>);
+
+// 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/ranges/zip_transform/1.cc b/libstdc++-v3/testsuite/std/ranges/zip_transform/1.cc
index 9a0ad38..8524a14 100644
--- a/libstdc++-v3/testsuite/std/ranges/zip_transform/1.cc
+++ b/libstdc++-v3/testsuite/std/ranges/zip_transform/1.cc
@@ -132,6 +132,97 @@ test04()
static_assert( requires { views::zip_transform(move_only{}, x, x); } );
}
+struct X
+{
+ int i;
+ constexpr int add(int b) const
+ { return i+b; }
+};
+
+template<size_t ExtraSize, typename Fn>
+constexpr bool
+test05(Fn f)
+{
+ using namespace __gnu_test;
+ X x[] = {{1},{2},{3},{4},{5}};
+ int y[] = {500,400,300,200,100};
+ test_range<X, random_access_iterator_wrapper> rx(x);
+ test_range<int, random_access_iterator_wrapper> ry(y);
+
+ auto v = views::zip_transform(f, rx, ry);
+ VERIFY( ranges::size(v) == 5 );
+ VERIFY( ranges::distance(v.begin(), v.end()) == 5 );
+ VERIFY( ranges::equal(v, (int[]){501,402,303,204,105}) );
+ VERIFY( ranges::equal(v | views::reverse, (int[]){105,204,303,402,501}) );
+ using R = decltype(v);
+ using It = ranges::iterator_t<R>;
+ static_assert(std::same_as<int, decltype(*ranges::begin(v))>);
+ static_assert(std::same_as<int, std::iter_value_t<It>>);
+ static_assert(sizeof(It) == sizeof(rx.begin()) + sizeof(ry.begin()) + ExtraSize);
+ static_assert(ranges::view<R>);
+ static_assert(ranges::sized_range<R>);
+ static_assert(ranges::common_range<R>);
+ static_assert(ranges::random_access_range<R>);
+ return true;
+}
+
+constexpr bool
+test05a()
+{
+ auto add = [](const X& x, int v) { return x.i + v; };
+ return test05<sizeof(void*)>(add);
+}
+
+constexpr bool
+test05b()
+{
+ auto add = [](const X& x, int v) static { return x.i + v; };
+ return test05<0>(add);
+}
+
+constexpr bool
+test05c()
+{
+ int(*ptr)(const X&, int) = [](const X& x, int v) { return x.i + v; };
+ return test05<sizeof(void(*)())>(ptr);
+}
+
+constexpr bool
+test05d()
+{ return test05<sizeof(int(X::*)())>(&X::add); }
+
+constexpr bool
+test05e()
+{
+ struct PickStatic
+ {
+ static constexpr int
+ operator()(const X& x1, int v)
+ { return x1.i + v; }
+
+ constexpr int
+ operator()(int x, int y) const
+ { return x + y; };
+ };
+ return test05<0>(PickStatic{});
+}
+
+constexpr bool
+test05f()
+{
+ struct PickObject
+ {
+ constexpr int
+ operator()(const X& x1, int v) const
+ { return x1.i + v; }
+
+ static constexpr int
+ operator()(int x, int y)
+ { return x + y; };
+ };
+ return test05<sizeof(void*)>(PickObject{});
+}
+
int
main()
{
@@ -139,4 +230,10 @@ main()
static_assert(test02());
static_assert(test03());
test04();
+ static_assert(test05a());
+ static_assert(test05b());
+ static_assert(test05c());
+ static_assert(test05d());
+ static_assert(test05e());
+ static_assert(test05f());
}
diff --git a/libstdc++-v3/testsuite/std/time/clock/local/io.cc b/libstdc++-v3/testsuite/std/time/clock/local/io.cc
index b4d562f..6efd81a 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
@@ -122,6 +125,14 @@ test_parse()
VERIFY( tp.time_since_epoch() == 0s );
}
+// LWG 4257. Stream insertion for chrono::local_time should be constrained
+template<typename T>
+concept ostream_insertable = requires (std::ostream& o, const T& t) { o << t; };
+using D = std::chrono::duration<double>;
+static_assert( ostream_insertable<std::chrono::local_days> );
+static_assert( ostream_insertable<std::chrono::local_seconds> );
+static_assert( ! ostream_insertable<std::chrono::local_time<D>> );
+
int main()
{
test_ostream();
diff --git a/libstdc++-v3/testsuite/std/time/format/custom_rep.h b/libstdc++-v3/testsuite/std/time/format/custom_rep.h
new file mode 100644
index 0000000..8363eaa
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/time/format/custom_rep.h
@@ -0,0 +1,92 @@
+#include <chrono>
+#include <ostream>
+
+#define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S)
+#define WIDEN(S) WIDEN_(CharT, S)
+
+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;
+ }
+};
+
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..cb8f916
--- /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
+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
+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..b84f84a
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/time/format/empty_spec.cc
@@ -0,0 +1,841 @@
+// { 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>
+#include "custom_rep.h"
+
+using namespace std::chrono;
+
+
+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==") );
+}
+
+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, bool CustomizedOstream>
+void
+test_time_point()
+{
+ std::basic_string<CharT> res;
+
+ const auto lt = local_days(2024y/March/22) + 13h + 24min + 54s + 111222333ns;
+ auto strip_time = [](std::basic_string_view<CharT> sv)
+ { return CustomizedOstream ? sv.substr(0, 10) : sv; };
+
+ 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")) );
+
+ if constexpr (!CustomizedOstream)
+ {
+ verify( wall_cast<Clock, duration<double>>(lt),
+ WIDEN("2024-03-22 13:24:54") );
+ verify( wall_cast<Clock, years>(lt),
+ WIDEN("2024-01-01 02:16:48") );
+ }
+ else
+ {
+ test_no_empty_spec<CharT, time_point<Clock, duration<double>>>();
+ test_no_empty_spec<CharT, time_point<Clock, years>>();
+ }
+}
+
+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, true>();
+ test_time_point<CharT, system_clock, true>();
+ test_time_point<CharT, utc_clock, false>();
+ test_time_point<CharT, tai_clock, false>();
+ test_time_point<CharT, gps_clock, false>();
+ test_time_point<CharT, file_clock, false>();
+ test_leap_second<CharT>();
+#if _GLIBCXX_USE_CXX11_ABI || !_GLIBCXX_USE_DUAL_ABI
+ test_zoned_time<CharT>();
+#endif
+ test_local_time_format<CharT>();
+
+}
+
+#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/format.cc b/libstdc++-v3/testsuite/std/time/format/format.cc
index d6e3583..d1aee05 100644
--- a/libstdc++-v3/testsuite/std/time/format/format.cc
+++ b/libstdc++-v3/testsuite/std/time/format/format.cc
@@ -2,6 +2,7 @@
// { dg-timeout-factor 2 }
#include <chrono>
+#include <vector>
#include <testsuite_hooks.h>
void
@@ -78,6 +79,13 @@ test_bad_format_strings()
VERIFY( not is_format_string_for("{:%OOy}", t) );
VERIFY( not is_format_string_for("{:%OEy}", t) );
VERIFY( not is_format_string_for("{:%EOy}", t) );
+
+ // weekday and month values for which ok() is false
+ VERIFY( not is_format_string_for("{:%a}", std::chrono::weekday(8)) );
+ VERIFY( not is_format_string_for("{:%A}", std::chrono::weekday(8)) );
+ VERIFY( not is_format_string_for("{:%b}", std::chrono::month(13)) );
+ VERIFY( not is_format_string_for("{:%h}", std::chrono::month(13)) );
+ VERIFY( not is_format_string_for("{:%B}", std::chrono::month(13)) );
}
template<typename I>
diff --git a/libstdc++-v3/testsuite/std/time/format/nonlocking.cc b/libstdc++-v3/testsuite/std/time/format/nonlocking.cc
new file mode 100644
index 0000000..f1b57b5
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/time/format/nonlocking.cc
@@ -0,0 +1,164 @@
+// { dg-do compile { target c++23 } }
+
+#include <format>
+#include <chrono>
+#include "custom_rep.h"
+
+static_assert(std::enable_nonlocking_formatter_optimization<
+ std::chrono::day>);
+static_assert(std::enable_nonlocking_formatter_optimization<
+ std::chrono::month>);
+static_assert(std::enable_nonlocking_formatter_optimization<
+ std::chrono::year>);
+static_assert(std::enable_nonlocking_formatter_optimization<
+ std::chrono::weekday>);
+static_assert(std::enable_nonlocking_formatter_optimization<
+ std::chrono::weekday_indexed>);
+static_assert(std::enable_nonlocking_formatter_optimization<
+ std::chrono::weekday_last>);
+static_assert(std::enable_nonlocking_formatter_optimization<
+ std::chrono::month_day>);
+static_assert(std::enable_nonlocking_formatter_optimization<
+ std::chrono::month_day_last>);
+static_assert(std::enable_nonlocking_formatter_optimization<
+ std::chrono::month_weekday>);
+static_assert(std::enable_nonlocking_formatter_optimization<
+ std::chrono::month_weekday_last>);
+static_assert(std::enable_nonlocking_formatter_optimization<
+ std::chrono::year_month>);
+static_assert(std::enable_nonlocking_formatter_optimization<
+ std::chrono::year_month_day>);
+static_assert(std::enable_nonlocking_formatter_optimization<
+ std::chrono::year_month_day_last>);
+static_assert(std::enable_nonlocking_formatter_optimization<
+ std::chrono::year_month_weekday>);
+static_assert(std::enable_nonlocking_formatter_optimization<
+ std::chrono::year_month_weekday_last>);
+
+#if _GLIBCXX_USE_CXX11_ABI || !_GLIBCXX_USE_DUAL_ABI
+static_assert(std::enable_nonlocking_formatter_optimization<
+ std::chrono::local_info>);
+static_assert(std::enable_nonlocking_formatter_optimization<
+ std::chrono::sys_info>);
+#endif
+
+template<typename Duration>
+using local_time_fmt
+ = decltype(std::chrono::local_time_format(std::chrono::local_time<Duration>{}));
+
+static_assert(std::enable_nonlocking_formatter_optimization<
+ std::chrono::seconds>);
+static_assert(std::enable_nonlocking_formatter_optimization<
+ std::chrono::duration<float>>);
+static_assert(std::enable_nonlocking_formatter_optimization<
+ std::chrono::duration<long long, std::mega>>);
+static_assert(std::enable_nonlocking_formatter_optimization<
+ std::chrono::local_time<std::chrono::seconds>>);
+static_assert(std::enable_nonlocking_formatter_optimization<
+ std::chrono::sys_time<std::chrono::seconds>>);
+static_assert(std::enable_nonlocking_formatter_optimization<
+ std::chrono::utc_time<std::chrono::seconds>>);
+static_assert(std::enable_nonlocking_formatter_optimization<
+ std::chrono::gps_time<std::chrono::seconds>>);
+static_assert(std::enable_nonlocking_formatter_optimization<
+ std::chrono::tai_time<std::chrono::seconds>>);
+static_assert(std::enable_nonlocking_formatter_optimization<
+ std::chrono::file_time<std::chrono::seconds>>);
+static_assert(std::enable_nonlocking_formatter_optimization<
+ local_time_fmt<std::chrono::seconds>>);
+
+using BufferedDuration = std::chrono::duration<Rep<void, int>>;
+
+static_assert(!std::enable_nonlocking_formatter_optimization<
+ BufferedDuration>);
+static_assert(!std::enable_nonlocking_formatter_optimization<
+ std::chrono::local_time<BufferedDuration>>);
+static_assert(!std::enable_nonlocking_formatter_optimization<
+ std::chrono::sys_time<BufferedDuration>>);
+static_assert(!std::enable_nonlocking_formatter_optimization<
+ std::chrono::utc_time<BufferedDuration>>);
+static_assert(!std::enable_nonlocking_formatter_optimization<
+ std::chrono::gps_time<BufferedDuration>>);
+static_assert(!std::enable_nonlocking_formatter_optimization<
+ std::chrono::tai_time<BufferedDuration>>);
+static_assert(!std::enable_nonlocking_formatter_optimization<
+ std::chrono::file_time<BufferedDuration>>);
+static_assert(!std::enable_nonlocking_formatter_optimization<
+ local_time_fmt<BufferedDuration>>);
+
+template<>
+inline constexpr bool
+ std::enable_nonlocking_formatter_optimization<Rep<void, long>> = true;
+
+using NonBufferedRep = std::chrono::duration<Rep<void, long>>;
+
+static_assert(!std::enable_nonlocking_formatter_optimization<
+ NonBufferedRep>);
+static_assert(!std::enable_nonlocking_formatter_optimization<
+ std::chrono::local_time<NonBufferedRep>>);
+static_assert(!std::enable_nonlocking_formatter_optimization<
+ std::chrono::sys_time<NonBufferedRep>>);
+static_assert(!std::enable_nonlocking_formatter_optimization<
+ std::chrono::utc_time<NonBufferedRep>>);
+static_assert(!std::enable_nonlocking_formatter_optimization<
+ std::chrono::gps_time<NonBufferedRep>>);
+static_assert(!std::enable_nonlocking_formatter_optimization<
+ std::chrono::tai_time<NonBufferedRep>>);
+static_assert(!std::enable_nonlocking_formatter_optimization<
+ std::chrono::file_time<NonBufferedRep>>);
+static_assert(!std::enable_nonlocking_formatter_optimization<
+ local_time_fmt<NonBufferedRep>>);
+
+using NonBufferedDuration = std::chrono::duration<Rep<void, short>>;
+
+template<>
+inline constexpr bool
+ std::enable_nonlocking_formatter_optimization<NonBufferedDuration> = true;
+
+static_assert(std::enable_nonlocking_formatter_optimization<
+ NonBufferedDuration>);
+static_assert(std::enable_nonlocking_formatter_optimization<
+ std::chrono::local_time<NonBufferedDuration>>);
+static_assert(std::enable_nonlocking_formatter_optimization<
+ std::chrono::sys_time<NonBufferedDuration>>);
+static_assert(std::enable_nonlocking_formatter_optimization<
+ std::chrono::utc_time<NonBufferedDuration>>);
+static_assert(std::enable_nonlocking_formatter_optimization<
+ std::chrono::gps_time<NonBufferedDuration>>);
+static_assert(std::enable_nonlocking_formatter_optimization<
+ std::chrono::tai_time<NonBufferedDuration>>);
+static_assert(std::enable_nonlocking_formatter_optimization<
+ std::chrono::file_time<NonBufferedDuration>>);
+static_assert(std::enable_nonlocking_formatter_optimization<
+ local_time_fmt<NonBufferedDuration>>);
+
+#if _GLIBCXX_USE_CXX11_ABI || !_GLIBCXX_USE_DUAL_ABI
+static_assert(std::enable_nonlocking_formatter_optimization<
+ std::chrono::zoned_time<std::chrono::seconds>>);
+static_assert(!std::enable_nonlocking_formatter_optimization<
+ std::chrono::zoned_time<BufferedDuration>>);
+static_assert(!std::enable_nonlocking_formatter_optimization<
+ std::chrono::zoned_time<NonBufferedRep>>);
+static_assert(std::enable_nonlocking_formatter_optimization<
+ std::chrono::zoned_time<NonBufferedDuration>>);
+
+struct MyTimeZone : std::chrono::time_zone
+{};
+
+template<>
+struct std::chrono::zoned_traits<MyTimeZone>
+{
+ static const MyTimeZone* default_zone();
+ static const MyTimeZone* locate_zone(std::string_view name);
+};
+
+static_assert(!std::enable_nonlocking_formatter_optimization<
+ std::chrono::zoned_time<std::chrono::seconds, MyTimeZone>>);
+static_assert(!std::enable_nonlocking_formatter_optimization<
+ std::chrono::zoned_time<BufferedDuration, MyTimeZone>>);
+static_assert(!std::enable_nonlocking_formatter_optimization<
+ std::chrono::zoned_time<NonBufferedRep, MyTimeZone>>);
+static_assert(!std::enable_nonlocking_formatter_optimization<
+ std::chrono::zoned_time<NonBufferedDuration, MyTimeZone>>);
+#endif
+
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/pr117214_custom_timeput.cc b/libstdc++-v3/testsuite/std/time/format/pr117214_custom_timeput.cc
new file mode 100644
index 0000000..03b9496
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/time/format/pr117214_custom_timeput.cc
@@ -0,0 +1,37 @@
+// { dg-do run { target c++20 } }
+
+#include <chrono>
+#include <format>
+#include <locale>
+#include <testsuite_hooks.h>
+
+struct custom_time_put : std::time_put<char>
+{
+ iter_type
+ do_put(iter_type out, std::ios_base& io, char_type fill, const tm* t,
+ char format, char modifier) const override
+ {
+ using Base = std::time_put<char>;
+
+ switch (format) {
+ case 'a': case 'A': case 'b': case 'h': case 'B': case 'p':
+ *out++ = '[';
+ *out++ = format;
+ *out++ = ']';
+ }
+ return Base::do_put(out, io, fill, t, format, modifier);
+ }
+};
+
+int main()
+{
+ using namespace std::chrono;
+ std::locale loc(std::locale::classic(), new custom_time_put);
+#define test(t, fmt, exp) VERIFY( std::format(loc, fmt, t) == exp )
+ test(Monday, "{:L%a}", "[a]Mon");
+ test(Monday, "{:L%A}", "[A]Monday");
+ test(January, "{:L%b}", "[b]Jan");
+ test(January, "{:L%h}", "[h]Jan");
+ test(January, "{:L%B}", "[B]January");
+ test(1h, "{:L%p}", "[p]AM");
+}
diff --git a/libstdc++-v3/testsuite/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/std/time/hash.cc b/libstdc++-v3/testsuite/std/time/hash.cc
new file mode 100644
index 0000000..ed9139b
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/time/hash.cc
@@ -0,0 +1,280 @@
+// { dg-do run { target c++26 } }
+
+#include <chrono>
+#include <unordered_set>
+#include <limits.h>
+#include <testsuite_hooks.h>
+
+#if _GLIBCXX_USE_CXX11_ABI
+# if !defined(__cpp_lib_chrono)
+# error "__cpp_lib_chrono not defined"
+# elif __cpp_lib_chrono < 202306L
+# error "Wrong value for __cpp_lib_chrono"
+# endif
+#endif
+
+template <typename T>
+struct arithmetic_wrapper
+{
+ arithmetic_wrapper() = default;
+ arithmetic_wrapper(T t) : t(t) {}
+ friend bool operator==(arithmetic_wrapper, arithmetic_wrapper) = default;
+ T t;
+};
+
+template <typename T>
+struct std::hash<arithmetic_wrapper<T>>
+{
+ size_t operator()(arithmetic_wrapper<T> val) const noexcept
+ { return std::hash<T>{}(val.t); }
+};
+
+template <typename T>
+struct non_hashable_arithmetic_wrapper
+{
+ non_hashable_arithmetic_wrapper() = default;
+ non_hashable_arithmetic_wrapper(T t) : t(t) {}
+ friend bool operator==(non_hashable_arithmetic_wrapper, non_hashable_arithmetic_wrapper) = default;
+ T t;
+};
+
+template <typename T>
+constexpr bool is_hash_poisoned = !std::is_default_constructible_v<std::hash<T>>;
+
+template <typename T>
+void test_unordered_set(const T& t)
+{
+ std::unordered_set<T> set;
+
+ set.insert(t);
+ VERIFY(set.size() == 1);
+ VERIFY(set.contains(t));
+
+ set.erase(t);
+ VERIFY(set.size() == 0);
+ VERIFY(!set.contains(t));
+}
+
+template <typename T>
+void test_hash(const T& t)
+{
+ static_assert(noexcept(std::hash<T>{}(t)));
+ static_assert(std::__is_fast_hash<T>::value);
+ test_unordered_set(t);
+}
+
+void test01()
+{
+ using namespace std::chrono;
+ using namespace std::literals::chrono_literals;
+
+ // duration
+ test_hash(-999s);
+ test_hash(1234ms);
+#if defined __SIZEOF_INT128__
+ test_hash(duration<__int128>(123456));
+#endif
+ test_hash(duration<double>(123.45));
+ using AWint = arithmetic_wrapper<int>;
+ test_hash(duration<AWint>(AWint(1234)));
+ using AWdouble = arithmetic_wrapper<double>;
+ test_hash(duration<AWdouble>(AWdouble(123.45)));
+
+ // time_point
+ test_hash(sys_seconds(1234s));
+#if defined __SIZEOF_INT128__
+ test_hash(sys_time<duration<__int128>>(duration<__int128>(123456)));
+#endif
+ test_hash(sys_time<duration<double>>(duration<double>(123.45)));
+ test_hash(utc_seconds(1234s));
+ test_hash(local_days(days(1234)));
+ test_hash(system_clock::now());
+ test_hash(steady_clock::now());
+ test_hash(utc_clock::now());
+ test_hash(gps_clock::now());
+
+ // day
+ test_hash(1d);
+ test_hash(0d);
+ test_hash(255d);
+ test_hash(1234d);
+ test_hash(day(UINT_MAX));
+
+ // month
+ test_hash(January);
+ test_hash(September);
+ test_hash(month(0u));
+ test_hash(month(255u));
+ test_hash(month(1234u));
+ test_hash(month(UINT_MAX));
+
+ // year
+ test_hash(2024y);
+ test_hash(0y);
+ test_hash(year::min());
+ test_hash(year::max());
+ test_hash(year(INT_MAX));
+ test_hash(year(INT_MIN));
+
+ // weekday
+ test_hash(Monday);
+ test_hash(Thursday);
+ test_hash(weekday(255u));
+ test_hash(weekday(UINT_MAX));
+
+ // weekday_indexed
+ test_hash(Monday[0u]);
+ test_hash(Monday[7u]);
+ test_hash(Monday[1234u]);
+ test_hash(weekday(1234u)[0u]);
+
+ // weekday_last
+ test_hash(Monday[last]);
+ test_hash(Friday[last]);
+ test_hash(weekday(1234u)[last]);
+
+ // month_day
+ test_hash(March / 3);
+ test_hash(March / 31);
+ test_hash(February / 31);
+ test_hash(February / 1234);
+ test_hash(month(1234u) / 1);
+
+ // month_day_last
+ test_hash(March / last);
+ test_hash(month(1234u) / last);
+
+ // month_weekday
+ test_hash(March / Tuesday[2u]);
+ test_hash(month(1234u) / Tuesday[2u]);
+ test_hash(March / weekday(1234u)[2u]);
+ test_hash(March / Tuesday[1234u]);
+
+ // month_weekday_last
+ test_hash(April / Sunday[last]);
+ test_hash(month(1234u) / Tuesday[last]);
+ test_hash(April / weekday(1234u)[last]);
+
+ // year_month
+ test_hash(2024y / August);
+ test_hash(1'000'000y / August);
+ test_hash(2024y / month(1234u));
+
+ // year_month_day
+ test_hash(2024y / August / 31);
+ test_hash(-10y / March / 5);
+ test_hash(2024y / February / 31);
+ test_hash(1'000'000y / March / 5);
+ test_hash(2024y / month(1234u) / 5);
+ test_hash(2024y / March / 1234);
+
+ // year_month_day_last
+ test_hash(2024y / August / last);
+ test_hash(1'000'000y / August / last);
+ test_hash(2024y / month(1234u) / last);
+
+ // year_month_weekday
+ test_hash(2024y / August / Tuesday[2u]);
+ test_hash(-10y / August / Tuesday[2u]);
+ test_hash(1'000'000y / August / Tuesday[2u]);
+ test_hash(2024y / month(1234u) / Tuesday[2u]);
+ test_hash(2024y / August / weekday(1234u)[2u]);
+ test_hash(2024y / August / Tuesday[1234u]);
+
+ // year_month_weekday_last
+ test_hash(2024y / August / Tuesday[last]);
+ test_hash(-10y / August / Tuesday[last]);
+ test_hash(1'000'000y / August / Tuesday[last]);
+ test_hash(2024y / month(1234u) / Tuesday[last]);
+ test_hash(2024y / August / weekday(1234u)[last]);
+
+#if _GLIBCXX_USE_CXX11_ABI
+ // zoned_time
+ test_hash(zoned_seconds("Europe/Rome", sys_seconds(1234s)));
+ test_hash(zoned_time("Europe/Rome", system_clock::now()));
+
+ // leap_second
+ for (leap_second l : get_tzdb().leap_seconds)
+ test_hash(l);
+#endif
+}
+
+void test02()
+{
+ using namespace std::chrono;
+ using namespace std::literals::chrono_literals;
+
+ {
+ std::unordered_set<milliseconds> set;
+ set.insert(2000ms);
+ VERIFY(set.contains(2000ms));
+ VERIFY(set.contains(2s));
+ VERIFY(!set.contains(1234ms));
+ VERIFY(!set.contains(1234s));
+ }
+ {
+ using TP = sys_time<milliseconds>;
+ std::unordered_set<TP> set;
+ set.insert(TP(2000ms));
+ VERIFY(set.contains(TP(2000ms)));
+ VERIFY(set.contains(sys_seconds(2s)));
+ VERIFY(!set.contains(TP(1234ms)));
+ VERIFY(!set.contains(sys_seconds(1234s)));
+ }
+}
+
+void test03()
+{
+ using namespace std::chrono;
+
+ static constexpr
+ auto test_hash = []<typename T>(const T& t)
+ {
+ static_assert(noexcept(std::hash<T>{}(t)));
+ };
+
+ static constexpr
+ auto test = []<typename D>(const D& d)
+ {
+ test_hash(d);
+ test_hash(sys_time<D>(d));
+#if _GLIBCXX_USE_CXX11_ABI
+ test_hash(zoned_time<D>(sys_time<D>(d)));
+#endif
+ };
+
+ test(duration<int>(123));
+ test(duration<int, std::ratio<1, 1000>>(123));
+ test(duration<int, std::ratio<1000, 1>>(123));
+ test(duration<double>(123.456));
+ test(duration<arithmetic_wrapper<int>>(arithmetic_wrapper<int>(123)));
+}
+
+void test04()
+{
+ using namespace std::chrono;
+
+ static_assert(!is_hash_poisoned<duration<int>>);
+ static_assert(!is_hash_poisoned<duration<double>>);
+ static_assert(!is_hash_poisoned<duration<arithmetic_wrapper<int>>>);
+ static_assert(!is_hash_poisoned<duration<arithmetic_wrapper<double>>>);
+ static_assert(is_hash_poisoned<duration<non_hashable_arithmetic_wrapper<int>>>);
+ static_assert(is_hash_poisoned<duration<non_hashable_arithmetic_wrapper<double>>>);
+
+#if _GLIBCXX_USE_CXX11_ABI
+ static_assert(!is_hash_poisoned<zoned_time<duration<int>>>);
+ static_assert(!is_hash_poisoned<zoned_time<duration<double>>>);
+ static_assert(!is_hash_poisoned<zoned_time<duration<arithmetic_wrapper<int>>>>);
+ static_assert(!is_hash_poisoned<zoned_time<duration<arithmetic_wrapper<double>>>>);
+ static_assert(is_hash_poisoned<zoned_time<duration<non_hashable_arithmetic_wrapper<int>>>>);
+ static_assert(is_hash_poisoned<zoned_time<duration<non_hashable_arithmetic_wrapper<double>>>>);
+#endif
+}
+
+int main()
+{
+ test01();
+ test02();
+ test03();
+ test04();
+}
diff --git a/libstdc++-v3/testsuite/std/time/month/io.cc b/libstdc++-v3/testsuite/std/time/month/io.cc
index 99ec073..edfa196 100644
--- a/libstdc++-v3/testsuite/std/time/month/io.cc
+++ b/libstdc++-v3/testsuite/std/time/month/io.cc
@@ -24,6 +24,9 @@ test_ostream()
ss.imbue(std::locale(ISO_8859(15,fr_FR)));
ss << month(1);
VERIFY( ss.str() == "janv." );
+ ss.str("");
+ ss << month(0) << '|' << month(13);
+ VERIFY( ss.str() == "0 is not a valid month|13 is not a valid month" );
}
void
@@ -66,6 +69,10 @@ test_format()
VERIFY( s == "Jan" );
s = std::format(loc_fr, "{:L%b}", month(1));
VERIFY( s == "janv." );
+ s = std::format(loc_fr, "{:L}", month(0));
+ VERIFY( s == "0 is not a valid month" );
+ s = std::format(loc_fr, "{:L}", month(13));
+ VERIFY( s == "13 is not a valid month" );
std::string_view specs = "aAbBcCdDeFgGhHIjmMpqQrRSTuUVwWxXyYzZ";
std::string_view my_specs = "bBhm";
diff --git a/libstdc++-v3/testsuite/std/time/month_day/io.cc b/libstdc++-v3/testsuite/std/time/month_day/io.cc
index 30aa588..c3ae180 100644
--- a/libstdc++-v3/testsuite/std/time/month_day/io.cc
+++ b/libstdc++-v3/testsuite/std/time/month_day/io.cc
@@ -23,6 +23,45 @@ test_ostream()
}
void
+test_format()
+{
+ using namespace std::chrono;
+ std::locale loc_fr(ISO_8859(15,fr_FR));
+
+ auto s = std::format("{:%b%%%B%t%m%n %d%%%e}", month(1)/day(3));
+ VERIFY( s == "Jan%January\t01\n 03% 3" );
+ s = std::format(loc_fr, "{:L%b%%%B%t%m%n %d%%%e}", month(1)/day(3));
+ VERIFY( s == "janv.%janvier\t01\n 03% 3");
+
+ s = std::format("{0:%m/%d} {0}", month(10)/day(13));
+ VERIFY( s == "10/13 Oct/13" );
+ s = std::format("{0:%m/%d} {0}", month(13)/day(34));
+ VERIFY( s == "13/34 13 is not a valid month/34 is not a valid day" );
+
+ std::string_view specs = "aAbBcCdDeFgGhHIjmMpqQrRSTuUVwWxXyYzZ";
+ std::string_view my_specs = "bBdehm";
+ for (char c : specs)
+ {
+ char fmt[] = { '{', ':', '%', c, '}' };
+ try
+ {
+ auto md = month(1)/day(10);
+ (void) std::vformat(std::string_view(fmt, 5), std::make_format_args(md));
+ // The call above should throw for any conversion-spec not in my_specs:
+ VERIFY(my_specs.find(c) != my_specs.npos);
+ }
+ catch (const std::format_error& e)
+ {
+ VERIFY(my_specs.find(c) == my_specs.npos);
+ std::string_view s = e.what();
+ // Libstdc++-specific message:
+ VERIFY(s.find("format argument does not contain the information "
+ "required by the chrono-specs") != s.npos);
+ }
+ }
+}
+
+void
test_parse()
{
using namespace std::chrono;
@@ -102,6 +141,6 @@ test_parse()
int main()
{
test_ostream();
- // TODO: test_format();
+ test_format();
test_parse();
}
diff --git a/libstdc++-v3/testsuite/std/time/month_day_last/io.cc b/libstdc++-v3/testsuite/std/time/month_day_last/io.cc
index c12cee8..484a8d8 100644
--- a/libstdc++-v3/testsuite/std/time/month_day_last/io.cc
+++ b/libstdc++-v3/testsuite/std/time/month_day_last/io.cc
@@ -22,9 +22,47 @@ test_ostream()
VERIFY( ss.str() == "juil./last" );
}
+void
+test_format()
+{
+ using namespace std::chrono;
+ std::locale loc_fr(ISO_8859(15,fr_FR));
+
+ auto s = std::format("{:%b%%%B%t%m%n}", month(3)/last);
+ VERIFY( s == "Mar%March\t03\n" );
+ s = std::format(loc_fr, "{:L%b%%%B%t%m%n}", month(3)/last);
+ VERIFY( s == "mars%mars\t03\n");
+
+ s = std::format("{0:%m/last} {0}", month(4)/last);
+ VERIFY( s == "04/last Apr/last" );
+ s = std::format("{0:%m/last} {0}", month(0)/last);
+ VERIFY( s == "00/last 0 is not a valid month/last" );
+
+ std::string_view specs = "aAbBcCdDeFgGhHIjmMpqQrRSTuUVwWxXyYzZ";
+ std::string_view my_specs = "bBhm";
+ for (char c : specs)
+ {
+ char fmt[] = { '{', ':', '%', c, '}' };
+ try
+ {
+ auto mdl = month(1)/last;
+ (void) std::vformat(std::string_view(fmt, 5), std::make_format_args(mdl));
+ // The call above should throw for any conversion-spec not in my_specs:
+ VERIFY(my_specs.find(c) != my_specs.npos);
+ }
+ catch (const std::format_error& e)
+ {
+ VERIFY(my_specs.find(c) == my_specs.npos);
+ std::string_view s = e.what();
+ // Libstdc++-specific message:
+ VERIFY(s.find("format argument does not contain the information "
+ "required by the chrono-specs") != s.npos);
+ }
+ }
+}
+
int main()
{
test_ostream();
- // TODO: test_format();
- // TODO: test_parse();
+ test_format();
}
diff --git a/libstdc++-v3/testsuite/std/time/month_weekday/io.cc b/libstdc++-v3/testsuite/std/time/month_weekday/io.cc
index 82cac64..0c2dcaf 100644
--- a/libstdc++-v3/testsuite/std/time/month_weekday/io.cc
+++ b/libstdc++-v3/testsuite/std/time/month_weekday/io.cc
@@ -23,9 +23,47 @@ test_ostream()
VERIFY( ss.str() == "juil./jeu.[4]" );
}
+void
+test_format()
+{
+ using namespace std::chrono;
+ std::locale loc_fr(ISO_8859(15,fr_FR));
+
+ auto s = std::format("{:%b%%%B%t%m%n %a%%%A%t%u%n%w}", month(5)/weekday(1)[2]);
+ VERIFY( s == "May%May\t05\n Mon%Monday\t1\n1" );
+ s = std::format(loc_fr, "{:L%b%%%B%t%m%n %a%%%A%t%u%n%w}", month(5)/weekday(1)[2]);
+ VERIFY( s == "mai%mai\t05\n lun.%lundi\t1\n1");
+
+ s = std::format("{0:%m/%u[]} {0}", month(9)/weekday(0)[2]);
+ VERIFY( s == "09/7[] Sep/Sun[2]" );
+ s = std::format("{0:%m/%u[]} {0}", month(111)/weekday(8)[0]);
+ VERIFY( s == "111/8[] 111 is not a valid month/8 is not a valid weekday[0 is not a valid index]" );
+
+ std::string_view specs = "aAbBcCdDeFgGhHIjmMpqQrRSTuUVwWxXyYzZ";
+ std::string_view my_specs = "aAbBhmuw";
+ for (char c : specs)
+ {
+ char fmt[] = { '{', ':', '%', c, '}' };
+ try
+ {
+ auto mwi = month(1)/weekday(1)[1];
+ (void) std::vformat(std::string_view(fmt, 5), std::make_format_args(mwi));
+ // The call above should throw for any conversion-spec not in my_specs:
+ VERIFY(my_specs.find(c) != my_specs.npos);
+ }
+ catch (const std::format_error& e)
+ {
+ VERIFY(my_specs.find(c) == my_specs.npos);
+ std::string_view s = e.what();
+ // Libstdc++-specific message:
+ VERIFY(s.find("format argument does not contain the information "
+ "required by the chrono-specs") != s.npos);
+ }
+ }
+}
+
int main()
{
test_ostream();
- // TODO: test_format();
- // TODO: test_parse();
+ test_format();
}
diff --git a/libstdc++-v3/testsuite/std/time/month_weekday_last/io.cc b/libstdc++-v3/testsuite/std/time/month_weekday_last/io.cc
index 47968d0..2c29258 100644
--- a/libstdc++-v3/testsuite/std/time/month_weekday_last/io.cc
+++ b/libstdc++-v3/testsuite/std/time/month_weekday_last/io.cc
@@ -23,9 +23,47 @@ test_ostream()
VERIFY( ss.str() == "juil./jeu.[last]" );
}
+void
+test_format()
+{
+ using namespace std::chrono;
+ std::locale loc_fr(ISO_8859(15,fr_FR));
+
+ auto s = std::format("{:%b%%%B%t%m%n %a%%%A%t%u%n%w}", month(6)/weekday(2)[last]);
+ VERIFY( s == "Jun%June\t06\n Tue%Tuesday\t2\n2" );
+ s = std::format(loc_fr, "{:L%b%%%B%t%m%n %a%%%A%t%u%n%w}", month(6)/weekday(2)[last]);
+ VERIFY( s == "juin%juin\t06\n mar.%mardi\t2\n2");
+
+ s = std::format("{0:%m/%w[last]} {0}", month(8)/weekday(7)[last]);
+ VERIFY( s == "08/0[last] Aug/Sun[last]" );
+ s = std::format("{0:%m/%w[last]} {0}", month(70)/weekday(9)[last]);
+ VERIFY( s == "70/9[last] 70 is not a valid month/9 is not a valid weekday[last]" );
+
+ std::string_view specs = "aAbBcCdDeFgGhHIjmMpqQrRSTuUVwWxXyYzZ";
+ std::string_view my_specs = "aAbBhmuw";
+ for (char c : specs)
+ {
+ char fmt[] = { '{', ':', '%', c, '}' };
+ try
+ {
+ auto mwl = month(1)/weekday(1)[last];
+ (void) std::vformat(std::string_view(fmt, 5), std::make_format_args(mwl));
+ // The call above should throw for any conversion-spec not in my_specs:
+ VERIFY(my_specs.find(c) != my_specs.npos);
+ }
+ catch (const std::format_error& e)
+ {
+ VERIFY(my_specs.find(c) == my_specs.npos);
+ std::string_view s = e.what();
+ // Libstdc++-specific message:
+ VERIFY(s.find("format argument does not contain the information "
+ "required by the chrono-specs") != s.npos);
+ }
+ }
+}
+
int main()
{
test_ostream();
- // TODO: test_format();
- // TODO: test_parse();
+ test_format();
}
diff --git a/libstdc++-v3/testsuite/std/time/parse/parse.cc b/libstdc++-v3/testsuite/std/time/parse/parse.cc
index 8bb0fd0..78c761c 100644
--- a/libstdc++-v3/testsuite/std/time/parse/parse.cc
+++ b/libstdc++-v3/testsuite/std/time/parse/parse.cc
@@ -309,7 +309,7 @@ test_modifiers()
is >> parse("%5M", min);
VERIFY( is.eof() && is.fail() );
- std::chrono::seconds s;
+ std::chrono::seconds s{};
is.clear();
is.str("000000000012345");
is >> parse("%12S", s); // Read more than 10 digits to check overflow logic.
diff --git a/libstdc++-v3/testsuite/std/time/weekday/io.cc b/libstdc++-v3/testsuite/std/time/weekday/io.cc
index a56cdae..90a9bcb 100644
--- a/libstdc++-v3/testsuite/std/time/weekday/io.cc
+++ b/libstdc++-v3/testsuite/std/time/weekday/io.cc
@@ -69,6 +69,8 @@ test_format()
VERIFY( s == "Mon" );
s = std::format(loc_fr, "{:L%a}", weekday(1));
VERIFY( s == "lun." );
+ s = std::format(loc_fr, "{:L}", weekday(25));
+ VERIFY( s == "25 is not a valid weekday" );
std::string_view specs = "aAbBcCdDeFgGhHIjmMpqQrRSTuUVwWxXyYzZ";
std::string_view my_specs = "aAuw";
diff --git a/libstdc++-v3/testsuite/std/time/weekday_indexed/io.cc b/libstdc++-v3/testsuite/std/time/weekday_indexed/io.cc
index 29255ad..ae86419 100644
--- a/libstdc++-v3/testsuite/std/time/weekday_indexed/io.cc
+++ b/libstdc++-v3/testsuite/std/time/weekday_indexed/io.cc
@@ -22,9 +22,47 @@ test_ostream()
VERIFY( ss.str() == "sam.[1]" );
}
+void
+test_format()
+{
+ using namespace std::chrono;
+ std::locale loc_fr(ISO_8859(15,fr_FR));
+
+ auto s = std::format("{:%a%%%A%t%u%n%w}", weekday(7)[3]);
+ VERIFY( s == "Sun%Sunday\t7\n0" );
+ s = std::format(loc_fr, "{:L%a%%%A%t%u%n%w}", weekday(7)[3]);
+ VERIFY( s == "dim.%dimanche\t7\n0");
+
+ s = std::format("{0:%w[]} {0}", weekday(4)[4]);
+ VERIFY( s == "4[] Thu[4]" );
+ s = std::format("{0:%w[]} {0}", weekday(10)[7]);
+ VERIFY( s == "10[] 10 is not a valid weekday[7 is not a valid index]" );
+
+ std::string_view specs = "aAbBcCdDeFgGhHIjmMpqQrRSTuUVwWxXyYzZ";
+ std::string_view my_specs = "aAuw";
+ for (char c : specs)
+ {
+ char fmt[] = { '{', ':', '%', c, '}' };
+ try
+ {
+ auto wi = weekday(1)[1];
+ (void) std::vformat(std::string_view(fmt, 5), std::make_format_args(wi));
+ // The call above should throw for any conversion-spec not in my_specs:
+ VERIFY(my_specs.find(c) != my_specs.npos);
+ }
+ catch (const std::format_error& e)
+ {
+ VERIFY(my_specs.find(c) == my_specs.npos);
+ std::string_view s = e.what();
+ // Libstdc++-specific message:
+ VERIFY(s.find("format argument does not contain the information "
+ "required by the chrono-specs") != s.npos);
+ }
+ }
+}
+
int main()
{
test_ostream();
- // TODO: test_format();
- // TODO: test_parse();
+ test_format();
}
diff --git a/libstdc++-v3/testsuite/std/time/weekday_last/io.cc b/libstdc++-v3/testsuite/std/time/weekday_last/io.cc
index 6f76922..49cf0d5 100644
--- a/libstdc++-v3/testsuite/std/time/weekday_last/io.cc
+++ b/libstdc++-v3/testsuite/std/time/weekday_last/io.cc
@@ -22,9 +22,47 @@ test_ostream()
VERIFY( ss.str() == "sam.[last]" );
}
+void
+test_format()
+{
+ using namespace std::chrono;
+ std::locale loc_fr(ISO_8859(15,fr_FR));
+
+ auto s = std::format("{:%a%%%A%t%u%n%w}", weekday(5)[last]);
+ VERIFY( s == "Fri%Friday\t5\n5" );
+ s = std::format(loc_fr, "{:L%a%%%A%t%u%n%w}", weekday(5)[last]);
+ VERIFY( s == "ven.%vendredi\t5\n5");
+
+ s = std::format("{0:%w[last]} {0}", weekday(6)[last]);
+ VERIFY( s == "6[last] Sat[last]" );
+ s = std::format("{0:%w[last]} {0}", weekday(9)[last]);
+ VERIFY( s == "9[last] 9 is not a valid weekday[last]" );
+
+ std::string_view specs = "aAbBcCdDeFgGhHIjmMpqQrRSTuUVwWxXyYzZ";
+ std::string_view my_specs = "aAuw";
+ for (char c : specs)
+ {
+ char fmt[] = { '{', ':', '%', c, '}' };
+ try
+ {
+ auto wl = weekday(1)[last];
+ (void) std::vformat(std::string_view(fmt, 5), std::make_format_args(wl));
+ // The call above should throw for any conversion-spec not in my_specs:
+ VERIFY(my_specs.find(c) != my_specs.npos);
+ }
+ catch (const std::format_error& e)
+ {
+ VERIFY(my_specs.find(c) == my_specs.npos);
+ std::string_view s = e.what();
+ // Libstdc++-specific message:
+ VERIFY(s.find("format argument does not contain the information "
+ "required by the chrono-specs") != s.npos);
+ }
+ }
+}
+
int main()
{
test_ostream();
- // TODO: test_format();
- // TODO: test_parse();
+ test_format();
}
diff --git a/libstdc++-v3/testsuite/std/time/year_month/io.cc b/libstdc++-v3/testsuite/std/time/year_month/io.cc
index 7bb3442..3392eb3 100644
--- a/libstdc++-v3/testsuite/std/time/year_month/io.cc
+++ b/libstdc++-v3/testsuite/std/time/year_month/io.cc
@@ -23,6 +23,45 @@ test_ostream()
}
void
+test_format()
+{
+ using namespace std::chrono;
+ std::locale loc_fr(ISO_8859(15,fr_FR));
+
+ auto s = std::format("{:%C%%%y\t%Y %b%%%B%t%m%n}", year(2019)/month(4));
+ VERIFY( s == "20%19\t2019 Apr%April\t04\n" );
+ s = std::format(loc_fr, "{:L%C%%%y\t%Y %b%%%B%t%m%n}", year(2019)/month(4));
+ VERIFY( s == "20%19\t2019 avril%avril\t04\n");
+
+ s = std::format("{0:%Y/%m} {0}", year(2018)/month(2));
+ VERIFY( s == "2018/02 2018/Feb" );
+ s = std::format("{0:%Y/%m} {0}", year(-32768)/month(15));
+ VERIFY( s == "-32768/15 -32768 is not a valid year/15 is not a valid month" );
+
+ std::string_view specs = "aAbBcCdDeFgGhHIjmMpqQrRSTuUVwWxXyYzZ";
+ std::string_view my_specs = "CbBhmyY";
+ for (char c : specs)
+ {
+ char fmt[] = { '{', ':', '%', c, '}' };
+ try
+ {
+ auto ym = year(2013)/month(1);
+ (void) std::vformat(std::string_view(fmt, 5), std::make_format_args(ym));
+ // The call above should throw for any conversion-spec not in my_specs:
+ VERIFY(my_specs.find(c) != my_specs.npos);
+ }
+ catch (const std::format_error& e)
+ {
+ VERIFY(my_specs.find(c) == my_specs.npos);
+ std::string_view s = e.what();
+ // Libstdc++-specific message:
+ VERIFY(s.find("format argument does not contain the information "
+ "required by the chrono-specs") != s.npos);
+ }
+ }
+}
+
+void
test_parse()
{
using namespace std::chrono;
@@ -73,6 +112,6 @@ test_parse()
int main()
{
test_ostream();
- // TODO: test_format();
+ test_format();
test_parse();
}
diff --git a/libstdc++-v3/testsuite/std/time/year_month_day/io.cc b/libstdc++-v3/testsuite/std/time/year_month_day/io.cc
index 632b7a0..5ce2794 100644
--- a/libstdc++-v3/testsuite/std/time/year_month_day/io.cc
+++ b/libstdc++-v3/testsuite/std/time/year_month_day/io.cc
@@ -43,38 +43,87 @@ test_format()
s = std::format("{:%G-W%V-%u}", 2022y/January/3);
VERIFY( s == "2022-W01-1" );
+ std::chrono::month Quindecember(17);
// %U: Week number for weeks starting on Sunday
s = std::format("Day {:%w (%a) of Week %U of %Y}", 2022y/January/1);
VERIFY( s == "Day 6 (Sat) of Week 00 of 2022" );
s = std::format("Day {:%w (%a) of Week %U of %Y}", 2022y/January/2);
VERIFY( s == "Day 0 (Sun) of Week 01 of 2022" );
+ s = std::format("Day {:%w (%a) of Week %U of %Y}", 2024y/January/1);
+ VERIFY( s == "Day 1 (Mon) of Week 00 of 2024" );
+ s = std::format("Day {:%w (%a) of Week %U of %Y}", 2024y/January/7);
+ VERIFY( s == "Day 0 (Sun) of Week 01 of 2024" );
+ s = std::format("Day {:%w (%a) of Week %U of %Y}", 2024y/January/8);
+ VERIFY( s == "Day 1 (Mon) of Week 01 of 2024" );
+ s = std::format("Day {:%w (%a) of Week %U of %Y}", 2022y/Quindecember/20);
+ VERIFY( s == "Day 1 (Mon) of Week 73 of 2022" );
// %W: Week number for weeks starting on Monday
s = std::format("Day {:%u (%a) of Week %W of %Y}", 2022y/January/2);
VERIFY( s == "Day 7 (Sun) of Week 00 of 2022" );
s = std::format("Day {:%u (%a) of Week %W of %Y}", 2022y/January/3);
VERIFY( s == "Day 1 (Mon) of Week 01 of 2022" );
-
+ s = std::format("Day {:%w (%a) of Week %W of %Y}", 2019y/January/1);
+ VERIFY( s == "Day 2 (Tue) of Week 00 of 2019" );
+ s = std::format("Day {:%w (%a) of Week %W of %Y}", 2019y/January/7);
+ VERIFY( s == "Day 1 (Mon) of Week 01 of 2019" );
+ s = std::format("Day {:%w (%a) of Week %W of %Y}", 2019y/January/8);
+ VERIFY( s == "Day 2 (Tue) of Week 01 of 2019" );
+ s = std::format("Day {:%w (%a) of Week %W of %Y}", 2022y/Quindecember/20);
+ VERIFY( s == "Day 1 (Mon) of Week 73 of 2022" );
+
+ // %G: ISO week-calendar year (ISO 8601)
// %V: ISO week number (ISO 8601).
- s = std::format("W{:%V}", 1977y/1/1);
- VERIFY( s == "W53" );
- s = std::format("W{:%V}", 1977y/1/2);
- VERIFY( s == "W53" );
- s = std::format("W{:%V}", 1977y/12/31);
- VERIFY( s == "W52" );
- s = std::format("W{:%V}", 1978y/1/1);
- VERIFY( s == "W52" );
- s = std::format("W{:%V}", 1978y/1/2);
- VERIFY( s == "W01" );
- s = std::format("W{:%V}", 1978y/12/31);
- VERIFY( s == "W52" );
- s = std::format("W{:%V}", 1979y/1/1);
- VERIFY( s == "W01" );
- s = std::format("W{:%V}", 1979y/12/30);
- VERIFY( s == "W52" );
- s = std::format("W{:%V}", 1979y/12/31);
- VERIFY( s == "W01" );
- s = std::format("W{:%V}", 1980y/1/1);
- VERIFY( s == "W01" );
+ s = std::format("{:%G-W%V}", 1977y/1/1);
+ VERIFY( s == "1976-W53" );
+ s = std::format("{:%G-W%V}", 1977y/1/2);
+ VERIFY( s == "1976-W53" );
+ s = std::format("{:%G-W%V}", 1977y/1/3);
+ VERIFY( s == "1977-W01" );
+ s = std::format("{:%G-W%V}", 1977y/12/31);
+ VERIFY( s == "1977-W52" );
+ s = std::format("{:%G-W%V}", 1978y/1/1);
+ VERIFY( s == "1977-W52" );
+ s = std::format("{:%G-W%V}", 1978y/1/2);
+ VERIFY( s == "1978-W01" );
+ s = std::format("{:%G-W%V}", 1978y/12/31);
+ VERIFY( s == "1978-W52" );
+ s = std::format("{:%G-W%V}", 1979y/1/1);
+ VERIFY( s == "1979-W01" );
+ s = std::format("{:%G-W%V}", 1979y/12/30);
+ VERIFY( s == "1979-W52" );
+ s = std::format("{:%G-W%V}", 1979y/12/31);
+ VERIFY( s == "1980-W01" );
+ s = std::format("{:%G-W%V}", 1980y/1/1);
+ VERIFY( s == "1980-W01" );
+ s = std::format("{:%G-W%V}", 1980y/18/20);
+ VERIFY( s == "1981-W26" );
+
+ // "Leap weak" on year starting on Thursday
+ s = std::format("{:%G-W%V}", 2009y/12/31);
+ VERIFY( s == "2009-W53" );
+ s = std::format("{:%G-W%V}", 2010y/1/1);
+ VERIFY( s == "2009-W53" );
+ s = std::format("{:%G-W%V}", 2010y/1/3);
+ VERIFY( s == "2009-W53" );
+ s = std::format("{:%G-W%V}", 2010y/1/4);
+ VERIFY( s == "2010-W01" );
+
+ // "Leap weak" on leap year stating on Wednesday
+ // 2020/Dec/31 is Thurday, thus 366 day of year
+ s = std::format("{:%G-W%V}", 2020y/12/30);
+ VERIFY( s == "2020-W53" );
+ s = std::format("{:%G-W%V}", 2020y/12/31);
+ VERIFY( s == "2020-W53" );
+ s = std::format("{:%G-W%V}", 2021y/1/1);
+ VERIFY( s == "2020-W53" );
+ s = std::format("{:%G-W%V}", 2021y/1/3);
+ VERIFY( s == "2020-W53" );
+ s = std::format("{:%G-W%V}", 2021y/1/4);
+ VERIFY( s == "2021-W01" );
+ s = std::format("{:%G-W%V}", 2021y/1/7);
+ VERIFY( s == "2021-W01" );
+ s = std::format("{:%G-W%V}", 2021y/1/8);
+ VERIFY( s == "2021-W01" );
s = std::format("{:%x}", 2022y/December/19);
VERIFY( s == "12/19/22" );
diff --git a/libstdc++-v3/testsuite/std/time/year_month_day_last/io.cc b/libstdc++-v3/testsuite/std/time/year_month_day_last/io.cc
index 3241536..cb937c1 100644
--- a/libstdc++-v3/testsuite/std/time/year_month_day_last/io.cc
+++ b/libstdc++-v3/testsuite/std/time/year_month_day_last/io.cc
@@ -22,9 +22,87 @@ test_ostream()
VERIFY( ss.str() == "2023/juil./last" );
}
+void
+test_format()
+{
+ using namespace std::chrono;
+
+ std::string s = std::format("{:%Y%t%C%%%y%n%j %b %a}", 2024y/January/last);
+ VERIFY( s == "2024\t20%24\n031 Jan Wed" );
+ std::wstring ws = std::format(L"{:%Y%t%C%%%y%n%j %b %a}", 2024y/December/last);
+ VERIFY( ws == L"2024\t20%24\n366 Dec Tue" );
+
+ s = std::format("{0:%Y-%m-%d} {0}", 2023y/May/last);
+ VERIFY( s == "2023-05-31 2023/May/last" );
+ s = std::format("{0:%Y-%m-%d} {0}", 2023y/month(13)/last);
+ VERIFY( s == "2023-13-30 2023/13 is not a valid month/last" );
+
+ s = std::format("{:%Y-%m-%d %j}", 2024y/February/last);
+ VERIFY( s == "2024-02-29 060" );
+ s = std::format("{:%Y-%m-%d %j}", 2023y/February/last);
+ VERIFY( s == "2023-02-28 059" );
+ s = std::format("{:%Y-%m-%d %j}", 2024y/September/last);
+ VERIFY( s == "2024-09-30 274" );
+
+ // %U: Week number for weeks starting on Sunday
+ s = std::format("{:%Y-U%U}", 2023y/January/last);
+ VERIFY( s == "2023-U05" );
+ s = std::format("{:%Y-U%U}", 2023y/December/last);
+ VERIFY( s == "2023-U53" );
+ // %W: Week number for weeks starting on Monday
+ s = std::format("{:%Y-W%W}", 2023y/January/last);
+ VERIFY( s == "2023-W05" );
+ s = std::format("{:%Y-W%W}", 2023y/December/last);
+ VERIFY( s == "2023-W52" );
+
+ // %G: ISO week-calendar year (ISO 8601)
+ // %V: ISO week number (ISO 8601).
+ s = std::format("{:%G-V%V}", 2019y/December/last);
+ VERIFY( s == "2020-V01" );
+ s = std::format("{:%G-V%V}", 2023y/January/last);
+ VERIFY( s == "2023-V05" );
+ s = std::format("{:%G-V%V}", 2023y/December/last);
+ VERIFY( s == "2023-V52" );
+
+ s = std::format("{:%F}", 2023y/July/last);
+ VERIFY( s == "2023-07-31" );
+ s = std::format("{:%x}", 2023y/July/last);
+ VERIFY( s == "07/31/23" );
+ s = std::format("{:L%x}", 2023y/July/last);
+ VERIFY( s == "07/31/23" );
+ std::locale loc_fr(ISO_8859(15,fr_FR));
+ s = std::format(loc_fr, "{:%x}", 2023y/July/last);
+ VERIFY( s == "07/31/23" );
+ s = std::format(loc_fr, "{:L%x}", 2023y/July/last);
+ VERIFY( s == "31/07/2023" || s == "31.07.2023" ); // depends on locale defs
+ s = std::format(loc_fr, "{:L}", 2023y/July/last);
+ VERIFY( s == "2023/juil./last" );
+
+ std::string_view specs = "aAbBcCdDeFgGhHIjmMpqQrRSTuUVwWxXyYzZ";
+ std::string_view my_specs = "aAbBCdDeFgGhjmuUVwWxyY";
+ for (char c : specs)
+ {
+ char fmt[] = { '{', ':', '%', c, '}' };
+ try
+ {
+ year_month_weekday ymw = 2023y/July/Thursday[2];
+ (void) std::vformat(std::string_view(fmt, 5), std::make_format_args(ymw));
+ // The call above should throw for any conversion-spec not in my_specs:
+ VERIFY(my_specs.find(c) != my_specs.npos);
+ }
+ catch (const std::format_error& e)
+ {
+ VERIFY(my_specs.find(c) == my_specs.npos);
+ std::string_view s = e.what();
+ // Libstdc++-specific message:
+ VERIFY(s.find("format argument does not contain the information "
+ "required by the chrono-specs") != s.npos);
+ }
+ }
+}
+
int main()
{
test_ostream();
- // TODO: test_format();
- // TODO: test_parse();
+ test_format();
}
diff --git a/libstdc++-v3/testsuite/std/time/year_month_weekday/io.cc b/libstdc++-v3/testsuite/std/time/year_month_weekday/io.cc
index 65baf1d..e01484c 100644
--- a/libstdc++-v3/testsuite/std/time/year_month_weekday/io.cc
+++ b/libstdc++-v3/testsuite/std/time/year_month_weekday/io.cc
@@ -34,9 +34,153 @@ test_ostream()
VERIFY( ss.str() == "2023/juil./jeu.[2]" );
}
+void
+test_format()
+{
+ using namespace std::chrono;
+
+ std::string s = std::format("{:%Y%t%C%%%y%n%j %b %a}", 2024y/January/Friday[2]);
+ VERIFY( s == "2024\t20%24\n012 Jan Fri" );
+ std::wstring ws = std::format(L"{:%Y%t%C%%%y%n%j %b %a}", 2024y/December/Monday[1]);
+ VERIFY( ws == L"2024\t20%24\n337 Dec Mon" );
+
+ s = std::format("{0:%Y-%m-%d} {0}", 2023y/May/Monday[1]);
+ VERIFY( s == "2023-05-01 2023/May/Mon[1]" );
+ s = std::format("{0:%Y-%m-%d} {0}", 2023y/month(13)/Monday[1]);
+ VERIFY( s == "2023-13-01 2023/13 is not a valid month/Mon[1]" );
+
+ s = std::format("{:%u %w}", Monday[1]);
+ VERIFY( s == "1 1" );
+ s = std::format("{:%u %w}", Sunday[2]);
+ VERIFY( s == "7 0" );
+ // 0 and 7 are both Sundays
+ s = std::format("{:%u %w}", weekday(0)[1]);
+ VERIFY( s == "7 0" );
+ s = std::format("{:%u %w}", weekday(7)[1]);
+ VERIFY( s == "7 0" );
+ s = std::format("{:%u %w}", weekday(9)[1]);
+ VERIFY( s == "9 9" );
+
+ s = std::format("{:%Y-%m-%d %j}", 2024y/February/Thursday[5]);
+ VERIFY( s == "2024-02-29 060" );
+ s = std::format("{:%Y-%m-%d %j}", 2023y/February/Tuesday[4]);
+ VERIFY( s == "2023-02-28 059" );
+ s = std::format("{:%Y-%m-%d %j}", 2024y/September/Sunday[1]);
+ VERIFY( s == "2024-09-01 245" );
+ s = std::format("{:%Y-%m-%d %j}", 2024y/September/Sunday[5]);
+ VERIFY( s == "2024-09-29 273" );
+ // first weeks of next month
+ s = std::format("{:%Y-%m-%d %j}", 2024y/September/Sunday[6]);
+ VERIFY( s == "2024-09-36 280" );
+ s = std::format("{:%Y-%m-%d %j}", 2024y/September/Sunday[7]);
+ VERIFY( s == "2024-09-43 287" );
+ // last week on previous month
+ s = std::format("{:%Y-%m-%d %j}", 2024y/September/Saturday[0]);
+ VERIFY( s == "2024-09-00 244" );
+ s = std::format("{:%Y-%m-%d %j}", 2024y/September/Sunday[0]);
+ VERIFY( s == "2024-09-00 238" ); // day is de-facto -6
+
+ // %U: Week number for weeks starting on Sunday
+ s = std::format("{:%Y-U%U}", 2023y/January/Sunday[0]);
+ VERIFY( s == "2023-U00" );
+ s = std::format("{:%Y-U%U}", 2023y/January/Sunday[1]);
+ VERIFY( s == "2023-U01" );
+ s = std::format("{:%Y-U%U}", 2023y/January/Sunday[4]);
+ VERIFY( s == "2023-U04" );
+ s = std::format("{:%Y-U%U}", 2023y/January/Sunday[7]);
+ VERIFY( s == "2023-U07" );
+ s = std::format("{:%Y-U%U}", 2023y/December/Sunday[0]);
+ VERIFY( s == "2023-U48" );
+ s = std::format("{:%Y-U%U}", 2023y/December/Sunday[1]);
+ VERIFY( s == "2023-U49" );
+ s = std::format("{:%Y-U%U}", 2023y/December/Sunday[4]);
+ VERIFY( s == "2023-U52" );
+ s = std::format("{:%Y-U%U}", 2023y/December/Sunday[7]);
+ VERIFY( s == "2023-U55" );
+ // %W: Week number for weeks starting on Monday
+ s = std::format("{:%Y-W%W}", 2023y/January/Monday[0]);
+ VERIFY( s == "2023-W00" );
+ s = std::format("{:%Y-W%W}", 2023y/January/Monday[1]);
+ VERIFY( s == "2023-W01" );
+ s = std::format("{:%Y-W%W}", 2023y/January/Monday[4]);
+ VERIFY( s == "2023-W04" );
+ s = std::format("{:%Y-W%W}", 2023y/January/Monday[7]);
+ VERIFY( s == "2023-W07" );
+ s = std::format("{:%Y-W%W}", 2023y/December/Monday[0]);
+ VERIFY( s == "2023-W48" );
+ s = std::format("{:%Y-W%W}", 2023y/December/Monday[1]);
+ VERIFY( s == "2023-W49" );
+ s = std::format("{:%Y-W%W}", 2023y/December/Monday[4]);
+ VERIFY( s == "2023-W52" );
+ s = std::format("{:%Y-W%W}", 2023y/December/Monday[7]);
+ VERIFY( s == "2023-W55" );
+ // First Sunday precedes first Monday, so happens on
+ // last week of previous month and thus year
+ s = std::format("{:%Y-W%W}", 2023y/January/Sunday[1]);
+ VERIFY( s == "2023-W00" );
+ // Last Sunday of pevious year happens on second to
+ // last week on previous year
+ s = std::format("{:%Y-W%W}", 2023y/January/Sunday[0]);
+ VERIFY( s == "2023-W99" );
+
+ // %G: ISO week-calendar year (ISO 8601)
+ // %V: ISO week number (ISO 8601).
+ s = std::format("{:%G-V%V}", 2023y/January/Monday[0]);
+ VERIFY( s == "2022-V52" );
+ s = std::format("{:%G-V%V}", 2023y/January/Monday[1]);
+ VERIFY( s == "2023-V01" );
+ s = std::format("{:%G-V%V}", 2023y/January/Monday[4]);
+ VERIFY( s == "2023-V04" );
+ s = std::format("{:%G-V%V}", 2023y/January/Monday[7]);
+ VERIFY( s == "2023-V07" );
+ s = std::format("{:%G-V%V}", 2023y/December/Friday[0]);
+ VERIFY( s == "2023-V47" );
+ s = std::format("{:%G-V%V}", 2023y/December/Friday[1]);
+ VERIFY( s == "2023-V48" );
+ s = std::format("{:%G-V%V}", 2023y/December/Friday[5]);
+ VERIFY( s == "2023-V52" );
+ s = std::format("{:%G-V%V}", 2023y/December/Friday[6]);
+ VERIFY( s == "2024-V01" );
+
+ s = std::format("{:%F}", 2023y/July/Thursday[2]);
+ VERIFY( s == "2023-07-13" );
+ s = std::format("{:%x}", 2023y/July/Thursday[2]);
+ VERIFY( s == "07/13/23" );
+ s = std::format("{:L%x}", 2023y/July/Thursday[2]);
+ VERIFY( s == "07/13/23" );
+ std::locale loc_fr(ISO_8859(15,fr_FR));
+ s = std::format(loc_fr, "{:%x}", 2023y/July/Thursday[2]);
+ VERIFY( s == "07/13/23" );
+ s = std::format(loc_fr, "{:L%x}", 2023y/July/Thursday[2]);
+ VERIFY( s == "13/07/2023" || s == "13.07.2023" ); // depends on locale defs
+ s = std::format(loc_fr, "{:L}", 2023y/July/Thursday[2]);
+ VERIFY( s == "2023/juil./jeu.[2]" );
+
+ std::string_view specs = "aAbBcCdDeFgGhHIjmMpqQrRSTuUVwWxXyYzZ";
+ std::string_view my_specs = "aAbBCdDeFgGhjmuUVwWxyY";
+ for (char c : specs)
+ {
+ char fmt[] = { '{', ':', '%', c, '}' };
+ try
+ {
+ year_month_weekday ymw = 2023y/July/Thursday[2];
+ (void) std::vformat(std::string_view(fmt, 5), std::make_format_args(ymw));
+ // The call above should throw for any conversion-spec not in my_specs:
+ VERIFY(my_specs.find(c) != my_specs.npos);
+ }
+ catch (const std::format_error& e)
+ {
+ VERIFY(my_specs.find(c) == my_specs.npos);
+ std::string_view s = e.what();
+ // Libstdc++-specific message:
+ VERIFY(s.find("format argument does not contain the information "
+ "required by the chrono-specs") != s.npos);
+ }
+ }
+}
+
int main()
{
test_ostream();
- // TODO: test_format();
- // TODO: test_parse();
+ test_format();
}
diff --git a/libstdc++-v3/testsuite/std/time/year_month_weekday_last/io.cc b/libstdc++-v3/testsuite/std/time/year_month_weekday_last/io.cc
index 17f2244..27bbe94 100644
--- a/libstdc++-v3/testsuite/std/time/year_month_weekday_last/io.cc
+++ b/libstdc++-v3/testsuite/std/time/year_month_weekday_last/io.cc
@@ -30,9 +30,103 @@ test_ostream()
VERIFY( ss.str() == "2023/juil./jeu.[last]" );
}
+void
+test_format()
+{
+ using namespace std::chrono;
+
+ std::string s = std::format("{:%Y%t%C%%%y%n%j %b %a}", 2024y/January/Friday[last]);
+ VERIFY( s == "2024\t20%24\n026 Jan Fri" );
+ std::wstring ws = std::format(L"{:%Y%t%C%%%y%n%j %b %a}", 2024y/December/Monday[last]);
+ VERIFY( ws == L"2024\t20%24\n365 Dec Mon" );
+
+ s = std::format("{0:%Y-%m-%d} {0}", 2023y/May/Monday[last]);
+ VERIFY( s == "2023-05-29 2023/May/Mon[last]" );
+ s = std::format("{0:%Y-%m-%d} {0}", 2023y/month(13)/Monday[last]);
+ VERIFY( s == "2023-13-29 2023/13 is not a valid month/Mon[last]" );
+
+ s = std::format("{:%u %w}", Monday[last]);
+ VERIFY( s == "1 1" );
+ s = std::format("{:%u %w}", Sunday[2]);
+ VERIFY( s == "7 0" );
+ // 0 and 7 are both Sundays
+ s = std::format("{:%u %w}", weekday(0)[last]);
+ VERIFY( s == "7 0" );
+ s = std::format("{:%u %w}", weekday(7)[last]);
+ VERIFY( s == "7 0" );
+ s = std::format("{:%u %w}", weekday(9)[last]);
+ VERIFY( s == "9 9" );
+
+ s = std::format("{:%Y-%m-%d %j}", 2024y/February/Thursday[last]);
+ VERIFY( s == "2024-02-29 060" );
+ s = std::format("{:%Y-%m-%d %j}", 2023y/February/Tuesday[last]);
+ VERIFY( s == "2023-02-28 059" );
+ s = std::format("{:%Y-%m-%d %j}", 2024y/September/Sunday[last]);
+ VERIFY( s == "2024-09-29 273" );
+
+ // %U: Week number for weeks starting on Sunday
+ s = std::format("{:%Y-U%U}", 2023y/January/Sunday[last]);
+ VERIFY( s == "2023-U05" );
+ s = std::format("{:%Y-U%U}", 2023y/December/Sunday[last]);
+ VERIFY( s == "2023-U53" );
+ // %W: Week number for weeks starting on Monday
+ s = std::format("{:%Y-W%W}", 2023y/January/Monday[last]);
+ VERIFY( s == "2023-W05" );
+ s = std::format("{:%Y-W%W}", 2023y/December/Monday[last]);
+ VERIFY( s == "2023-W52" );
+ s = std::format("{:%Y-W%W}", 2023y/January/Sunday[last]);
+ VERIFY( s == "2023-W04" );
+ s = std::format("{:%Y-W%W}", 2023y/December/Sunday[last]);
+ VERIFY( s == "2023-W52" );
+
+ // %G: ISO week-calendar year (ISO 8601)
+ // %V: ISO week number (ISO 8601).
+ s = std::format("{:%G-V%V}", 2019y/December/Tuesday[last]);
+ VERIFY( s == "2020-V01" );
+ s = std::format("{:%G-V%V}", 2023y/January/Monday[last]);
+ VERIFY( s == "2023-V05" );
+ s = std::format("{:%G-V%V}", 2023y/December/Friday[last]);
+ VERIFY( s == "2023-V52" );
+
+ s = std::format("{:%F}", 2023y/July/Thursday[last]);
+ VERIFY( s == "2023-07-27" );
+ s = std::format("{:%x}", 2023y/July/Thursday[last]);
+ VERIFY( s == "07/27/23" );
+ s = std::format("{:L%x}", 2023y/July/Thursday[last]);
+ VERIFY( s == "07/27/23" );
+ std::locale loc_fr(ISO_8859(15,fr_FR));
+ s = std::format(loc_fr, "{:%x}", 2023y/July/Thursday[last]);
+ VERIFY( s == "07/27/23" );
+ s = std::format(loc_fr, "{:L%x}", 2023y/July/Thursday[last]);
+ VERIFY( s == "27/07/2023" || s == "27.07.2023" ); // depends on locale defs
+ s = std::format(loc_fr, "{:L}", 2023y/July/Thursday[last]);
+ VERIFY( s == "2023/juil./jeu.[last]" );
+
+ std::string_view specs = "aAbBcCdDeFgGhHIjmMpqQrRSTuUVwWxXyYzZ";
+ std::string_view my_specs = "aAbBCdDeFgGhjmuUVwWxyY";
+ for (char c : specs)
+ {
+ char fmt[] = { '{', ':', '%', c, '}' };
+ try
+ {
+ year_month_weekday ymw = 2023y/July/Thursday[2];
+ (void) std::vformat(std::string_view(fmt, 5), std::make_format_args(ymw));
+ // The call above should throw for any conversion-spec not in my_specs:
+ VERIFY(my_specs.find(c) != my_specs.npos);
+ }
+ catch (const std::format_error& e)
+ {
+ VERIFY(my_specs.find(c) == my_specs.npos);
+ std::string_view s = e.what();
+ // Libstdc++-specific message:
+ VERIFY(s.find("format argument does not contain the information "
+ "required by the chrono-specs") != s.npos);
+ }
+ }
+}
+
int main()
{
test_ostream();
- // TODO: test_format();
- // TODO: test_parse();
+ test_format();
}
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/checks.h b/libstdc++-v3/testsuite/util/debug/checks.h
index 938cdda..528c021 100644
--- a/libstdc++-v3/testsuite/util/debug/checks.h
+++ b/libstdc++-v3/testsuite/util/debug/checks.h
@@ -19,10 +19,12 @@
#include <vector>
#include <deque>
#include <list>
+#include <inplace_vector>
#ifndef _GLIBCXX_DEBUG
# include <debug/vector>
# include <debug/deque>
# include <debug/list>
+# include <debug/inplace_vector>
#endif
#include <testsuite_hooks.h>
@@ -88,10 +90,11 @@ namespace __gnu_test
void
check_assign1()
{
+ using namespace std;
typedef _Tp cont_type;
typedef typename cont_type::value_type cont_val_type;
typedef typename CopyableValueType<cont_val_type>::value_type val_type;
- typedef std::vector<val_type> vector_type;
+ typedef _GLIBCXX_STD_C::vector<val_type> vector_type;
generate_unique<val_type> gu;
@@ -116,10 +119,11 @@ namespace __gnu_test
void
check_assign2()
{
+ using namespace std;
typedef _Tp cont_type;
typedef typename cont_type::value_type cont_val_type;
typedef typename CopyableValueType<cont_val_type>::value_type val_type;
- typedef std::vector<val_type> vector_type;
+ typedef _GLIBCXX_STD_C::vector<val_type> vector_type;
generate_unique<val_type> gu;
@@ -170,10 +174,11 @@ namespace __gnu_test
void
check_construct1()
{
+ using namespace std;
typedef _Tp cont_type;
typedef typename cont_type::value_type cont_val_type;
typedef typename CopyableValueType<cont_val_type>::value_type val_type;
- typedef std::vector<val_type> vector_type;
+ typedef _GLIBCXX_STD_C::vector<val_type> vector_type;
generate_unique<val_type> gu;
@@ -193,10 +198,11 @@ namespace __gnu_test
void
check_construct2()
{
+ using namespace std;
typedef _Tp cont_type;
typedef typename cont_type::value_type cont_val_type;
typedef typename CopyableValueType<cont_val_type>::value_type val_type;
- typedef std::vector<val_type> vector_type;
+ typedef _GLIBCXX_STD_C::vector<val_type> vector_type;
generate_unique<val_type> gu;
@@ -267,6 +273,13 @@ namespace __gnu_test
: InsertRangeHelperAux<std::list<_Tp1, _Tp2> >
{ };
+#ifdef __glibcxx_inplace_vector // C++ >= 26
+ template<typename _Tp, size_t _Nm>
+ struct InsertRangeHelper<std::inplace_vector<_Tp, _Nm> >
+ : InsertRangeHelperAux<std::inplace_vector<_Tp, _Nm> >
+ { };
+#endif
+
#ifndef _GLIBCXX_DEBUG
template <typename _Tp1, typename _Tp2>
struct InsertRangeHelper<__gnu_debug::vector<_Tp1, _Tp2> >
@@ -282,16 +295,24 @@ namespace __gnu_test
struct InsertRangeHelper<__gnu_debug::list<_Tp1, _Tp2> >
: InsertRangeHelperAux<__gnu_debug::list<_Tp1, _Tp2> >
{ };
+
+# ifdef __glibcxx_inplace_vector // C++ >= 26
+ template<typename _Tp, size_t _Nm>
+ struct InsertRangeHelper<__gnu_debug::inplace_vector<_Tp, _Nm> >
+ : InsertRangeHelperAux<__gnu_debug::inplace_vector<_Tp, _Nm> >
+ { };
+# endif
#endif
template<typename _Tp>
void
check_insert1()
{
+ using namespace std;
typedef _Tp cont_type;
typedef typename cont_type::value_type cont_val_type;
typedef typename CopyableValueType<cont_val_type>::value_type val_type;
- typedef std::vector<val_type> vector_type;
+ typedef _GLIBCXX_STD_C::vector<val_type> vector_type;
generate_unique<val_type> gu;
@@ -315,10 +336,11 @@ namespace __gnu_test
void
check_insert2()
{
+ using namespace std;
typedef _Tp cont_type;
typedef typename cont_type::value_type cont_val_type;
typedef typename CopyableValueType<cont_val_type>::value_type val_type;
- typedef std::vector<val_type> vector_type;
+ typedef _GLIBCXX_STD_C::vector<val_type> vector_type;
generate_unique<val_type> gu;
@@ -369,10 +391,11 @@ namespace __gnu_test
void
check_insert4()
{
+ using namespace std;
typedef _Tp cont_type;
typedef typename cont_type::value_type cont_val_type;
typedef typename CopyableValueType<cont_val_type>::value_type val_type;
- typedef std::list<val_type> list_type;
+ typedef _GLIBCXX_STD_C::list<val_type> list_type;
generate_unique<val_type> gu;
diff --git a/libstdc++-v3/testsuite/util/exception/safety.h b/libstdc++-v3/testsuite/util/exception/safety.h
index 8226c17..c62394c 100644
--- a/libstdc++-v3/testsuite/util/exception/safety.h
+++ b/libstdc++-v3/testsuite/util/exception/safety.h
@@ -24,6 +24,7 @@
#include <ext/throw_allocator.h>
#include <cstdlib> // getenv, atoi
#include <cstdio> // printf, fflush
+#include <cassert> // assert
// Container requirement testing.
namespace __gnu_test
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..3367b1b 100644
--- a/libstdc++-v3/testsuite/util/testsuite_allocator.h
+++ b/libstdc++-v3/testsuite/util/testsuite_allocator.h
@@ -26,14 +26,14 @@
#ifndef _GLIBCXX_TESTSUITE_ALLOCATOR_H
#define _GLIBCXX_TESTSUITE_ALLOCATOR_H
-#include <bits/move.h>
-#include <ext/pointer.h>
-#include <ext/alloc_traits.h>
-#include <testsuite_hooks.h>
#if __cplusplus >= 201703L
# include <memory_resource>
# include <new>
#endif
+#include <bits/move.h>
+#include <ext/pointer.h>
+#include <ext/alloc_traits.h>
+#include <testsuite_hooks.h>
#if __cplusplus >= 201103L
# include <unordered_map>
@@ -216,7 +216,7 @@ namespace __gnu_test
}
// Implement swap for underlying allocators that might need it.
- friend inline void
+ friend void
swap(tracker_allocator& a, tracker_allocator& b)
{
using std::swap;
@@ -310,10 +310,6 @@ namespace __gnu_test
{
typedef __gnu_cxx::__alloc_traits<Alloc> AllocTraits;
- Alloc& base() { return *this; }
- const Alloc& base() const { return *this; }
- void swap_base(Alloc& b) { using std::swap; swap(b, this->base()); }
-
public:
typedef typename check_consistent_alloc_value_type<Tp, Alloc>::value_type
value_type;
@@ -332,9 +328,11 @@ namespace __gnu_test
typename AllocTraits::template rebind<Tp1>::other> other;
};
+ _GLIBCXX_CONSTEXPR
uneq_allocator() _GLIBCXX_USE_NOEXCEPT
: personality(0) { }
+ _GLIBCXX_CONSTEXPR
uneq_allocator(int person) _GLIBCXX_USE_NOEXCEPT
: personality(person) { }
@@ -344,21 +342,23 @@ namespace __gnu_test
#endif
template<typename Tp1>
+ _GLIBCXX_CONSTEXPR
uneq_allocator(const uneq_allocator<Tp1,
typename AllocTraits::template rebind<Tp1>::other>& b)
_GLIBCXX_USE_NOEXCEPT
: personality(b.get_personality()) { }
- ~uneq_allocator() _GLIBCXX_USE_NOEXCEPT
- { }
-
- int get_personality() const { return personality; }
+ _GLIBCXX_CONSTEXPR int get_personality() const { return personality; }
+ _GLIBCXX20_CONSTEXPR
pointer
allocate(size_type n, const void* = 0)
{
pointer p = AllocTraits::allocate(*this, n);
+ if (std::__is_constant_evaluated())
+ return p;
+
try
{
get_map().insert(map_type::value_type(reinterpret_cast<void*>(p),
@@ -373,19 +373,24 @@ namespace __gnu_test
return p;
}
+ _GLIBCXX14_CONSTEXPR
void
deallocate(pointer p, size_type n)
{
VERIFY( p );
- map_type::iterator it = get_map().find(reinterpret_cast<void*>(p));
- VERIFY( it != get_map().end() );
+ if (!std::__is_constant_evaluated())
+ {
+ map_type::iterator it = get_map().find(reinterpret_cast<void*>(p));
+ VERIFY( it != get_map().end() );
+
+ // Enforce requirements in Table 32 about deallocation vs
+ // allocator equality.
+ VERIFY( it->second == personality );
- // Enforce requirements in Table 32 about deallocation vs
- // allocator equality.
- VERIFY( it->second == personality );
+ get_map().erase(it);
+ }
- get_map().erase(it);
AllocTraits::deallocate(*this, p, n);
}
@@ -406,22 +411,23 @@ namespace __gnu_test
private:
// ... yet swappable!
- friend inline void
+ friend _GLIBCXX_CONSTEXPR void
swap(uneq_allocator& a, uneq_allocator& b)
{
std::swap(a.personality, b.personality);
- a.swap_base(b);
+ using std::swap;
+ swap(static_cast<Alloc&>(a), static_cast<Alloc&>(b));
}
template<typename Tp1>
- friend inline bool
+ friend _GLIBCXX_CONSTEXPR bool
operator==(const uneq_allocator& a,
const uneq_allocator<Tp1,
typename AllocTraits::template rebind<Tp1>::other>& b)
{ return a.personality == b.get_personality(); }
template<typename Tp1>
- friend inline bool
+ friend _GLIBCXX_CONSTEXPR bool
operator!=(const uneq_allocator& a,
const uneq_allocator<Tp1,
typename AllocTraits::template rebind<Tp1>::other>& b)
@@ -438,9 +444,12 @@ namespace __gnu_test
typedef __gnu_cxx::__alloc_traits<Alloc> AllocTraits;
typedef uneq_allocator<Tp, Alloc> base_alloc;
- base_alloc& base() { return *this; }
- const base_alloc& base() const { return *this; }
- void swap_base(base_alloc& b) { swap(b, this->base()); }
+ _GLIBCXX14_CONSTEXPR void
+ swap_base(base_alloc& b)
+ {
+ using std::swap;
+ swap(b, static_cast<base_alloc&>(*this));
+ }
typedef std::integral_constant<bool, Propagate> trait_type;
@@ -454,11 +463,13 @@ namespace __gnu_test
typename AllocTraits::template rebind<Up>::other> other;
};
+ constexpr
propagating_allocator(int i) noexcept
: base_alloc(i)
{ }
template<typename Up>
+ constexpr
propagating_allocator(const propagating_allocator<Up, Propagate,
typename AllocTraits::template rebind<Up>::other>& a)
noexcept
@@ -469,6 +480,7 @@ namespace __gnu_test
propagating_allocator(const propagating_allocator&) noexcept = default;
+ _GLIBCXX14_CONSTEXPR
propagating_allocator&
operator=(const propagating_allocator& a) noexcept
{
@@ -478,6 +490,7 @@ namespace __gnu_test
}
template<bool P2>
+ _GLIBCXX14_CONSTEXPR
propagating_allocator&
operator=(const propagating_allocator<Tp, P2, Alloc>& a) noexcept
{
@@ -487,11 +500,13 @@ namespace __gnu_test
}
// postcondition: LWG2593 a.get_personality() un-changed.
+ constexpr
propagating_allocator(propagating_allocator&& a) noexcept
- : base_alloc(std::move(a.base()))
+ : base_alloc(static_cast<base_alloc&&>(a))
{ }
// postcondition: LWG2593 a.get_personality() un-changed
+ _GLIBCXX14_CONSTEXPR
propagating_allocator&
operator=(propagating_allocator&& a) noexcept
{
@@ -503,7 +518,8 @@ namespace __gnu_test
typedef trait_type propagate_on_container_move_assignment;
typedef trait_type propagate_on_container_swap;
- propagating_allocator select_on_container_copy_construction() const
+ constexpr propagating_allocator
+ select_on_container_copy_construction() const
{ return Propagate ? *this : propagating_allocator(); }
};
@@ -517,19 +533,24 @@ namespace __gnu_test
constexpr SimpleAllocator() noexcept { }
template <class T>
+ constexpr
SimpleAllocator(const SimpleAllocator<T>&) { }
+ _GLIBCXX20_CONSTEXPR
Tp *allocate(std::size_t n)
{ return std::allocator<Tp>().allocate(n); }
+ _GLIBCXX20_CONSTEXPR
void deallocate(Tp *p, std::size_t n)
{ std::allocator<Tp>().deallocate(p, n); }
};
template <class T, class U>
+ constexpr
bool operator==(const SimpleAllocator<T>&, const SimpleAllocator<U>&)
{ return true; }
template <class T, class U>
+ constexpr
bool operator!=(const SimpleAllocator<T>&, const SimpleAllocator<U>&)
{ return false; }
@@ -541,15 +562,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*
+ _GLIBCXX14_CONSTEXPR T*
allocate(std::size_t n)
{ return std::allocator<T>().allocate(n); }
- void
+ _GLIBCXX14_CONSTEXPR void
deallocate(T* p, std::size_t n)
{ std::allocator<T>().deallocate(p, n); }
@@ -557,15 +579,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>
@@ -573,7 +597,7 @@ namespace __gnu_test
ExplicitConsAlloc() { }
template<typename Up>
- explicit
+ explicit _GLIBCXX_CONSTEXPR
ExplicitConsAlloc(const ExplicitConsAlloc<Up>&) { }
template<typename Up>
@@ -592,6 +616,7 @@ namespace __gnu_test
CustomPointerAlloc() = default;
template<typename Up>
+ constexpr
CustomPointerAlloc(const CustomPointerAlloc<Up>&) { }
template<typename Up>
@@ -603,9 +628,11 @@ namespace __gnu_test
typedef Ptr<void> void_pointer;
typedef Ptr<const void> const_void_pointer;
+ _GLIBCXX14_CONSTEXPR
pointer allocate(std::size_t n, const_void_pointer = {})
{ return pointer(std::allocator<Tp>::allocate(n)); }
+ _GLIBCXX14_CONSTEXPR
void deallocate(pointer p, std::size_t n)
{ std::allocator<Tp>::deallocate(std::addressof(*p), n); }
};
@@ -623,16 +650,16 @@ namespace __gnu_test
explicit operator bool() const noexcept { return value != nullptr; }
- friend inline bool
+ friend constexpr bool
operator==(NullablePointer lhs, NullablePointer rhs) noexcept
{ return lhs.value == rhs.value; }
- friend inline bool
+ friend constexpr bool
operator!=(NullablePointer lhs, NullablePointer rhs) noexcept
{ return lhs.value != rhs.value; }
protected:
- explicit NullablePointer(Ptr p) noexcept : value(p) { }
+ constexpr explicit NullablePointer(Ptr p) noexcept : value(p) { }
Ptr value;
};
@@ -641,16 +668,16 @@ namespace __gnu_test
struct NullablePointer<void>
{
NullablePointer() = default;
- NullablePointer(std::nullptr_t) noexcept { }
- explicit NullablePointer(const volatile void*) noexcept { }
+ constexpr NullablePointer(std::nullptr_t) noexcept { }
+ constexpr explicit NullablePointer(const volatile void*) noexcept { }
- explicit operator bool() const noexcept { return false; }
+ constexpr explicit operator bool() const noexcept { return false; }
- friend inline bool
+ friend constexpr bool
operator==(NullablePointer, NullablePointer) noexcept
{ return true; }
- friend inline bool
+ friend constexpr bool
operator!=(NullablePointer, NullablePointer) noexcept
{ return false; }
};
diff --git a/libstdc++-v3/testsuite/util/testsuite_common_types.h b/libstdc++-v3/testsuite/util/testsuite_common_types.h
index cd36a20..98c0f53 100644
--- a/libstdc++-v3/testsuite/util/testsuite_common_types.h
+++ b/libstdc++-v3/testsuite/util/testsuite_common_types.h
@@ -22,14 +22,6 @@
#ifndef _TESTSUITE_COMMON_TYPES_H
#define _TESTSUITE_COMMON_TYPES_H 1
-#include <ext/typelist.h>
-
-#include <ext/new_allocator.h>
-#include <ext/malloc_allocator.h>
-#include <ext/mt_allocator.h>
-#include <ext/bitmap_allocator.h>
-#include <ext/pool_allocator.h>
-
#include <algorithm>
#include <vector>
@@ -53,6 +45,14 @@ namespace unord = std;
namespace unord = std::tr1;
#endif
+#include <ext/typelist.h>
+
+#include <ext/new_allocator.h>
+#include <ext/malloc_allocator.h>
+#include <ext/mt_allocator.h>
+#include <ext/bitmap_allocator.h>
+#include <ext/pool_allocator.h>
+
namespace __gnu_test
{
using __gnu_cxx::typelist::null_type;
diff --git a/libstdc++-v3/testsuite/util/testsuite_containers.h b/libstdc++-v3/testsuite/util/testsuite_containers.h
index 37491a4..4021585 100644
--- a/libstdc++-v3/testsuite/util/testsuite_containers.h
+++ b/libstdc++-v3/testsuite/util/testsuite_containers.h
@@ -20,10 +20,10 @@
#ifndef _GLIBCXX_TESTSUITE_CONTAINERS_H
#define _GLIBCXX_TESTSUITE_CONTAINERS_H
-#include <bits/boost_concept_check.h>
#include <cassert>
-#include <testsuite_container_traits.h>
#include <utility> // for rel_ops.
+#include <bits/boost_concept_check.h>
+#include <testsuite_container_traits.h>
// Container requirement testing.
namespace __gnu_test
@@ -210,6 +210,9 @@ namespace __gnu_test
clit = container.cbegin(bn);
assert( ++clit == container.cend(bn) );
+ clit = container.begin(bn);
+ assert( ++clit == container.cend(bn) );
+
assert( container.begin(bn) != container.cend(bn) );
}
};
@@ -304,6 +307,9 @@ namespace __gnu_test
assert( container.cbegin() != container.cend() );
assert( container.cbegin() != container.end() );
assert( container.begin() != container.cend() );
+
+ auto cit = container.begin();
+ assert( cit == container.cbegin() );
}
};
diff --git a/libstdc++-v3/testsuite/util/testsuite_error.h b/libstdc++-v3/testsuite/util/testsuite_error.h
index 5295d60b..03b09ee 100644
--- a/libstdc++-v3/testsuite/util/testsuite_error.h
+++ b/libstdc++-v3/testsuite/util/testsuite_error.h
@@ -19,12 +19,13 @@
// <http://www.gnu.org/licenses/>.
//
-#include <string>
-#include <testsuite_hooks.h>
-
#ifndef _TESTSUITE_ERROR_H
#define _TESTSUITE_ERROR_H 1
+#include <string>
+#include <system_error>
+#include <testsuite_hooks.h>
+
namespace __gnu_test
{
struct test_category : public std::error_category
diff --git a/libstdc++-v3/testsuite/util/testsuite_greedy_ops.h b/libstdc++-v3/testsuite/util/testsuite_greedy_ops.h
index 3545848..9103fcb 100644
--- a/libstdc++-v3/testsuite/util/testsuite_greedy_ops.h
+++ b/libstdc++-v3/testsuite/util/testsuite_greedy_ops.h
@@ -15,6 +15,8 @@
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
+#include <cstddef>
+
namespace greedy_ops
{
struct X
diff --git a/libstdc++-v3/testsuite/util/testsuite_hooks.h b/libstdc++-v3/testsuite/util/testsuite_hooks.h
index faa01ba..bf34fd1 100644
--- a/libstdc++-v3/testsuite/util/testsuite_hooks.h
+++ b/libstdc++-v3/testsuite/util/testsuite_hooks.h
@@ -58,16 +58,13 @@
# define _VERIFY_PRINT(S, F, L, P, C) __builtin_printf(S, F, L, P, C)
#endif
-#define VERIFY(fn) \
- do \
- { \
- if (! (fn)) \
- { \
- _VERIFY_PRINT("%s:%d: %s: Assertion '%s' failed.\n", \
- __FILE__, __LINE__, __PRETTY_FUNCTION__, #fn); \
- __builtin_abort(); \
- } \
- } while (false)
+#define VERIFY(...) \
+ ((void)((__VA_ARGS__) \
+ ? (void)(true ? true : bool(__VA_ARGS__)) \
+ : (_VERIFY_PRINT("%s:%d: %s: Assertion '%s' failed.\n", \
+ __FILE__, __LINE__, __PRETTY_FUNCTION__, \
+ #__VA_ARGS__), \
+ __builtin_abort())))
#ifdef _GLIBCXX_HAVE_UNISTD_H
# include <unistd.h>
diff --git a/libstdc++-v3/testsuite/util/testsuite_iterators.h b/libstdc++-v3/testsuite/util/testsuite_iterators.h
index 74a8739..70383b8 100644
--- a/libstdc++-v3/testsuite/util/testsuite_iterators.h
+++ b/libstdc++-v3/testsuite/util/testsuite_iterators.h
@@ -31,7 +31,7 @@
#include <bits/stl_iterator_base_types.h>
#if __cplusplus >= 201103L
-#include <bits/move.h>
+#include <utility>
#endif
#if __cplusplus > 201703L
@@ -61,10 +61,12 @@ namespace __gnu_test
T* first;
T* last;
+ _GLIBCXX_CONSTEXPR
BoundsContainer(T* _first, T* _last) : first(_first), last(_last)
{ }
- std::size_t size() const { return last - first; }
+ _GLIBCXX_CONSTEXPR std::size_t
+ size() const { return last - first; }
};
// Simple container for holding state of a set of output iterators.
@@ -74,11 +76,13 @@ namespace __gnu_test
T* incrementedto;
bool* writtento;
+ _GLIBCXX20_CONSTEXPR
OutputContainer(T* _first, T* _last)
: BoundsContainer<T>(_first, _last), incrementedto(_first),
writtento(new bool[this->size()]())
{ }
+ _GLIBCXX20_CONSTEXPR
~OutputContainer()
{ delete[] writtento; }
};
@@ -92,12 +96,14 @@ namespace __gnu_test
public:
OutputContainer<T>* SharedInfo;
+ _GLIBCXX_CONSTEXPR
WritableObject(T* ptr_in, OutputContainer<T>* SharedInfo_in):
ptr(ptr_in), SharedInfo(SharedInfo_in)
{ }
#if __cplusplus >= 201103L
template<class U>
+ _GLIBCXX14_CONSTEXPR
typename std::enable_if<std::is_assignable<T&, U>::value>::type
operator=(U&& new_val) const
{
@@ -107,6 +113,7 @@ namespace __gnu_test
}
#else
template<class U>
+ _GLIBCXX14_CONSTEXPR
void
operator=(const U& new_val)
{
@@ -128,6 +135,7 @@ namespace __gnu_test
struct output_iterator_wrapper
{
protected:
+ _GLIBCXX_CONSTEXPR
output_iterator_wrapper() : ptr(0), SharedInfo(0)
{ }
@@ -142,6 +150,7 @@ namespace __gnu_test
T* ptr;
ContainerType* SharedInfo;
+ _GLIBCXX14_CONSTEXPR
output_iterator_wrapper(T* _ptr, ContainerType* SharedInfo_in)
: ptr(_ptr), SharedInfo(SharedInfo_in)
{
@@ -155,6 +164,7 @@ namespace __gnu_test
operator=(const output_iterator_wrapper&) = default;
#endif
+ _GLIBCXX14_CONSTEXPR
WritableObject<T>
operator*() const
{
@@ -163,6 +173,7 @@ namespace __gnu_test
return WritableObject<T>(ptr, SharedInfo);
}
+ _GLIBCXX14_CONSTEXPR
output_iterator_wrapper&
operator++()
{
@@ -173,6 +184,7 @@ namespace __gnu_test
return *this;
}
+ _GLIBCXX14_CONSTEXPR
output_iterator_wrapper
operator++(int)
{
@@ -224,13 +236,19 @@ namespace __gnu_test
struct deref_proxy
{
T* ptr;
- operator const T&() const { return *ptr; }
+
+ _GLIBCXX_CONSTEXPR
+ operator const T&() const
+ { return *ptr; }
} p;
- deref_proxy operator*() const { return p; }
+ _GLIBCXX_CONSTEXPR
+ deref_proxy operator*() const
+ { return p; }
};
protected:
+ _GLIBCXX_CONSTEXPR
input_iterator_wrapper() : ptr(0), SharedInfo(0)
{ }
@@ -245,6 +263,7 @@ namespace __gnu_test
T* ptr;
ContainerType* SharedInfo;
+ _GLIBCXX14_CONSTEXPR
input_iterator_wrapper(T* _ptr, ContainerType* SharedInfo_in)
: ptr(_ptr), SharedInfo(SharedInfo_in)
{ ITERATOR_VERIFY(ptr >= SharedInfo->first && ptr <= SharedInfo->last); }
@@ -256,6 +275,7 @@ namespace __gnu_test
operator=(const input_iterator_wrapper&) = default;
#endif
+ _GLIBCXX14_CONSTEXPR
bool
operator==(const input_iterator_wrapper& in) const
{
@@ -264,26 +284,34 @@ namespace __gnu_test
return ptr == in.ptr;
}
+ _GLIBCXX14_CONSTEXPR
bool
operator!=(const input_iterator_wrapper& in) const
{
return !(*this == in);
}
- T&
- operator*() const
+ _GLIBCXX_CONSTEXPR
+ T* base() const
+ {
+ return ptr;
+ }
+
+ _GLIBCXX14_CONSTEXPR
+ T& operator*() const
{
ITERATOR_VERIFY(SharedInfo && ptr < SharedInfo->last);
ITERATOR_VERIFY(ptr >= SharedInfo->first);
return *ptr;
}
- T*
- operator->() const
+ _GLIBCXX14_CONSTEXPR
+ T* operator->() const
{
return &**this;
}
+ _GLIBCXX14_CONSTEXPR
input_iterator_wrapper&
operator++()
{
@@ -294,6 +322,7 @@ namespace __gnu_test
return *this;
}
+ _GLIBCXX14_CONSTEXPR
post_inc_proxy
operator++(int)
{
@@ -334,10 +363,12 @@ namespace __gnu_test
typedef BoundsContainer<T> ContainerType;
typedef std::forward_iterator_tag iterator_category;
+ _GLIBCXX14_CONSTEXPR
forward_iterator_wrapper(T* _ptr, ContainerType* SharedInfo_in)
: input_iterator_wrapper<T>(_ptr, SharedInfo_in)
{ }
+ _GLIBCXX14_CONSTEXPR
forward_iterator_wrapper()
{ }
@@ -348,17 +379,18 @@ namespace __gnu_test
operator=(const forward_iterator_wrapper&) = default;
#endif
- T&
- operator*() const
+ _GLIBCXX14_CONSTEXPR
+ T& operator*() const
{
ITERATOR_VERIFY(this->SharedInfo && this->ptr < this->SharedInfo->last);
return *(this->ptr);
}
- T*
- operator->() const
+ _GLIBCXX14_CONSTEXPR
+ T* operator->() const
{ return &**this; }
+ _GLIBCXX14_CONSTEXPR
forward_iterator_wrapper&
operator++()
{
@@ -367,6 +399,7 @@ namespace __gnu_test
return *this;
}
+ _GLIBCXX14_CONSTEXPR
forward_iterator_wrapper
operator++(int)
{
@@ -376,8 +409,8 @@ namespace __gnu_test
}
#if __cplusplus >= 201402L
- bool
- operator==(const forward_iterator_wrapper& it) const noexcept
+ constexpr
+ bool operator==(const forward_iterator_wrapper& it) const noexcept
{
// Since C++14 value-initialized forward iterators are comparable.
if (this->SharedInfo == nullptr || it.SharedInfo == nullptr)
@@ -388,8 +421,8 @@ namespace __gnu_test
return base_this == base_that;
}
- bool
- operator!=(const forward_iterator_wrapper& it) const noexcept
+ constexpr
+ bool operator!=(const forward_iterator_wrapper& it) const noexcept
{
return !(*this == it);
}
@@ -409,10 +442,12 @@ namespace __gnu_test
typedef BoundsContainer<T> ContainerType;
typedef std::bidirectional_iterator_tag iterator_category;
+ _GLIBCXX14_CONSTEXPR
bidirectional_iterator_wrapper(T* _ptr, ContainerType* SharedInfo_in)
: forward_iterator_wrapper<T>(_ptr, SharedInfo_in)
{ }
+ _GLIBCXX14_CONSTEXPR
bidirectional_iterator_wrapper()
: forward_iterator_wrapper<T>()
{ }
@@ -425,6 +460,7 @@ namespace __gnu_test
operator=(const bidirectional_iterator_wrapper&) = default;
#endif
+ _GLIBCXX14_CONSTEXPR
bidirectional_iterator_wrapper&
operator++()
{
@@ -433,6 +469,7 @@ namespace __gnu_test
return *this;
}
+ _GLIBCXX14_CONSTEXPR
bidirectional_iterator_wrapper
operator++(int)
{
@@ -441,6 +478,7 @@ namespace __gnu_test
return tmp;
}
+ _GLIBCXX14_CONSTEXPR
bidirectional_iterator_wrapper&
operator--()
{
@@ -449,6 +487,7 @@ namespace __gnu_test
return *this;
}
+ _GLIBCXX14_CONSTEXPR
bidirectional_iterator_wrapper
operator--(int)
{
@@ -472,10 +511,12 @@ namespace __gnu_test
typedef BoundsContainer<T> ContainerType;
typedef std::random_access_iterator_tag iterator_category;
+ _GLIBCXX14_CONSTEXPR
random_access_iterator_wrapper(T* _ptr, ContainerType* SharedInfo_in)
: bidirectional_iterator_wrapper<T>(_ptr, SharedInfo_in)
{ }
+ _GLIBCXX14_CONSTEXPR
random_access_iterator_wrapper()
: bidirectional_iterator_wrapper<T>()
{ }
@@ -488,6 +529,7 @@ namespace __gnu_test
operator=(const random_access_iterator_wrapper&) = default;
#endif
+ _GLIBCXX14_CONSTEXPR
random_access_iterator_wrapper&
operator++()
{
@@ -496,6 +538,7 @@ namespace __gnu_test
return *this;
}
+ _GLIBCXX14_CONSTEXPR
random_access_iterator_wrapper
operator++(int)
{
@@ -504,6 +547,7 @@ namespace __gnu_test
return tmp;
}
+ _GLIBCXX14_CONSTEXPR
random_access_iterator_wrapper&
operator--()
{
@@ -512,6 +556,7 @@ namespace __gnu_test
return *this;
}
+ _GLIBCXX14_CONSTEXPR
random_access_iterator_wrapper
operator--(int)
{
@@ -520,6 +565,7 @@ namespace __gnu_test
return tmp;
}
+ _GLIBCXX14_CONSTEXPR
random_access_iterator_wrapper&
operator+=(std::ptrdiff_t n)
{
@@ -536,10 +582,12 @@ namespace __gnu_test
return *this;
}
+ _GLIBCXX14_CONSTEXPR
random_access_iterator_wrapper&
operator-=(std::ptrdiff_t n)
{ return *this += -n; }
+ _GLIBCXX14_CONSTEXPR
random_access_iterator_wrapper
operator-(std::ptrdiff_t n) const
{
@@ -547,6 +595,7 @@ namespace __gnu_test
return tmp -= n;
}
+ _GLIBCXX14_CONSTEXPR
std::ptrdiff_t
operator-(const random_access_iterator_wrapper<T>& in) const
{
@@ -554,46 +603,66 @@ namespace __gnu_test
return this->ptr - in.ptr;
}
- T&
- operator[](std::ptrdiff_t n) const
+ _GLIBCXX14_CONSTEXPR
+ T& operator[](std::ptrdiff_t n) const
{ return *(*this + n); }
- bool
- operator<(const random_access_iterator_wrapper<T>& in) const
+#if __cplusplus >= 201103L
+ // Ensure that the iterator's difference_type is always used.
+ template<typename D> void operator+=(D) = delete;
+ template<typename D> void operator-=(D) = delete;
+ template<typename D> void operator[](D) const = delete;
+ template<typename D>
+ typename std::enable_if<std::is_integral<D>::value>::type
+ operator-(D) const = delete;
+#endif
+
+ _GLIBCXX14_CONSTEXPR
+ bool operator<(const random_access_iterator_wrapper<T>& in) const
{
ITERATOR_VERIFY(this->SharedInfo == in.SharedInfo);
return this->ptr < in.ptr;
}
- bool
- operator>(const random_access_iterator_wrapper<T>& in) const
+ _GLIBCXX14_CONSTEXPR
+ bool operator>(const random_access_iterator_wrapper<T>& in) const
{
return in < *this;
}
- bool
- operator>=(const random_access_iterator_wrapper<T>& in) const
+ _GLIBCXX14_CONSTEXPR
+ bool operator>=(const random_access_iterator_wrapper<T>& in) const
{
return !(*this < in);
}
- bool
- operator<=(const random_access_iterator_wrapper<T>& in) const
+ _GLIBCXX14_CONSTEXPR
+ bool operator<=(const random_access_iterator_wrapper<T>& in) const
{
return !(*this > in);
}
};
template<typename T>
+ _GLIBCXX14_CONSTEXPR
random_access_iterator_wrapper<T>
operator+(random_access_iterator_wrapper<T> it, std::ptrdiff_t n)
{ return it += n; }
template<typename T>
+ _GLIBCXX14_CONSTEXPR
random_access_iterator_wrapper<T>
operator+(std::ptrdiff_t n, random_access_iterator_wrapper<T> it)
{ return it += n; }
+#if __cplusplus >= 201103L
+ // Ensure that the iterator's difference_type is always used.
+ template<typename T, typename D>
+ void operator+(random_access_iterator_wrapper<T>, D) = delete;
+ template<typename T, typename D>
+ void operator+(D, random_access_iterator_wrapper<T>) = delete;
+#endif
+
/**
* @brief A container-type class for holding iterator wrappers
@@ -605,16 +674,22 @@ namespace __gnu_test
template <class T, template<class TT> class ItType>
struct test_container
{
+ typedef ItType<T> iterator;
+ typedef typename iterator::value_type value_type;
+
typename ItType<T>::ContainerType bounds;
+ _GLIBCXX_CONSTEXPR
test_container(T* _first, T* _last) : bounds(_first, _last)
{ }
template<std::size_t N>
explicit
+ _GLIBCXX_CONSTEXPR
test_container(T (&arr)[N]) : bounds(arr, arr+N)
{ }
+ _GLIBCXX14_CONSTEXPR
ItType<T>
it(int pos)
{
@@ -622,6 +697,7 @@ namespace __gnu_test
return ItType<T>(bounds.first + pos, &bounds);
}
+ _GLIBCXX14_CONSTEXPR
ItType<T>
it(T* pos)
{
@@ -629,18 +705,22 @@ namespace __gnu_test
return ItType<T>(pos, &bounds);
}
+ _GLIBCXX_CONSTEXPR
const T&
val(int pos)
{ return (bounds.first)[pos]; }
+ _GLIBCXX14_CONSTEXPR
ItType<T>
begin()
{ return it(bounds.first); }
+ _GLIBCXX14_CONSTEXPR
ItType<T>
end()
{ return it(bounds.last); }
+ _GLIBCXX_CONSTEXPR
std::size_t
size() const
{ return bounds.size(); }
@@ -680,6 +760,7 @@ namespace __gnu_test
// Use an integer-class type to try and break the library code.
using difference_type = std::ranges::__detail::__max_diff_type;
+ constexpr
contiguous_iterator_wrapper&
operator++()
{
@@ -687,6 +768,7 @@ namespace __gnu_test
return *this;
}
+ constexpr
contiguous_iterator_wrapper&
operator--()
{
@@ -694,6 +776,7 @@ namespace __gnu_test
return *this;
}
+ constexpr
contiguous_iterator_wrapper
operator++(int)
{
@@ -702,6 +785,7 @@ namespace __gnu_test
return tmp;
}
+ constexpr
contiguous_iterator_wrapper
operator--(int)
{
@@ -710,6 +794,7 @@ namespace __gnu_test
return tmp;
}
+ constexpr
contiguous_iterator_wrapper&
operator+=(difference_type n)
{
@@ -718,23 +803,28 @@ namespace __gnu_test
return *this;
}
- friend contiguous_iterator_wrapper
+ friend constexpr
+ contiguous_iterator_wrapper
operator+(contiguous_iterator_wrapper iter, difference_type n)
{ return iter += n; }
- friend contiguous_iterator_wrapper
+ friend constexpr
+ contiguous_iterator_wrapper
operator+(difference_type n, contiguous_iterator_wrapper iter)
{ return iter += n; }
+ constexpr
contiguous_iterator_wrapper&
operator-=(difference_type n)
{ return *this += -n; }
- friend contiguous_iterator_wrapper
+ friend constexpr
+ contiguous_iterator_wrapper
operator-(contiguous_iterator_wrapper iter, difference_type n)
{ return iter -= n; }
- friend difference_type
+ friend constexpr
+ difference_type
operator-(contiguous_iterator_wrapper l, contiguous_iterator_wrapper r)
{
const random_access_iterator_wrapper<T>& lbase = l;
@@ -742,6 +832,7 @@ namespace __gnu_test
return static_cast<difference_type>(lbase - rbase);
}
+ constexpr
decltype(auto) operator[](difference_type n) const
{
auto d = static_cast<std::ptrdiff_t>(n);
@@ -759,6 +850,7 @@ namespace __gnu_test
{
using input_iterator_wrapper<T>::input_iterator_wrapper;
+ constexpr
input_iterator_wrapper_nocopy()
: input_iterator_wrapper<T>(nullptr, nullptr)
{ }
@@ -773,6 +865,7 @@ namespace __gnu_test
using input_iterator_wrapper<T>::operator++;
+ constexpr
input_iterator_wrapper_nocopy&
operator++()
{
@@ -789,6 +882,7 @@ namespace __gnu_test
using input_iterator_wrapper<T>::operator++;
+ constexpr
input_iterator_wrapper_rval&
operator++()
{
@@ -796,8 +890,8 @@ namespace __gnu_test
return *this;
}
- T&&
- operator*() const
+ constexpr
+ T&& operator*() const
{ return std::move(input_iterator_wrapper<T>::operator*()); }
};
@@ -815,7 +909,9 @@ namespace __gnu_test
using Iter<T>::operator++;
- iterator& operator++() { Iter<T>::operator++(); return *this; }
+ constexpr
+ iterator& operator++()
+ { Iter<T>::operator++(); return *this; }
};
template<typename I>
@@ -823,21 +919,24 @@ namespace __gnu_test
{
T* end;
- friend bool operator==(const sentinel& s, const I& i) noexcept
+ friend constexpr bool
+ operator==(const sentinel& s, const I& i) noexcept
{ return s.end == i.ptr; }
- friend auto operator-(const sentinel& s, const I& i) noexcept
+ friend constexpr
+ auto operator-(const sentinel& s, const I& i) noexcept
requires std::random_access_iterator<I>
{ return std::iter_difference_t<I>(s.end - i.ptr); }
- friend auto operator-(const I& i, const sentinel& s) noexcept
+ friend constexpr auto
+ operator-(const I& i, const sentinel& s) noexcept
requires std::random_access_iterator<I>
{ return std::iter_difference_t<I>(i.ptr - s.end); }
};
protected:
- auto
- get_iterator(T* p)
+ constexpr
+ auto get_iterator(T* p)
{
if constexpr (std::default_initializable<Iter<T>>)
return Iter<T>(p, &bounds);
@@ -846,17 +945,19 @@ namespace __gnu_test
}
public:
+ constexpr
test_range(T* first, T* last) : bounds(first, last)
{ }
template<std::size_t N>
- explicit
+ explicit constexpr
test_range(T (&arr)[N]) : test_range(arr, arr+N)
{ }
- auto begin() & { return get_iterator(bounds.first); }
+ constexpr auto begin() &
+ { return get_iterator(bounds.first); }
- auto end() &
+ constexpr auto end() &
{
using I = decltype(get_iterator(bounds.last));
return sentinel<I>{bounds.last};
@@ -869,7 +970,9 @@ namespace __gnu_test
template<typename T, template<typename> class Iter>
struct test_range_nocopy : test_range<T, Iter>
{
- test_range_nocopy(T* first, T* last) : test_range<T, Iter>(first, last)
+ constexpr
+ test_range_nocopy(T* first, T* last)
+ : test_range<T, Iter>(first, last)
{}
test_range_nocopy(test_range_nocopy&&) = default;
@@ -904,6 +1007,7 @@ namespace __gnu_test
{
using test_range<T, Iter>::test_range;
+ constexpr
std::size_t size() const noexcept
{ return this->bounds.size(); }
};
@@ -939,18 +1043,22 @@ namespace __gnu_test
{
T* end;
- friend bool operator==(const sentinel& s, const I& i) noexcept
+ friend constexpr
+ bool operator==(const sentinel& s, const I& i) noexcept
{ return s.end == i.ptr; }
- friend std::iter_difference_t<I>
+ friend constexpr
+ std::iter_difference_t<I>
operator-(const sentinel& s, const I& i) noexcept
{ return std::iter_difference_t<I>(s.end - i.ptr); }
- friend std::iter_difference_t<I>
+ friend constexpr
+ std::iter_difference_t<I>
operator-(const I& i, const sentinel& s) noexcept
{ return std::iter_difference_t<I>(i.ptr - s.end); }
};
+ constexpr
auto end() &
{
using I = decltype(this->get_iterator(this->bounds.last));
diff --git a/libstdc++-v3/testsuite/util/testsuite_new_operators.h b/libstdc++-v3/testsuite/util/testsuite_new_operators.h
index bf0dab8..3e372b8 100644
--- a/libstdc++-v3/testsuite/util/testsuite_new_operators.h
+++ b/libstdc++-v3/testsuite/util/testsuite_new_operators.h
@@ -23,6 +23,7 @@
#define _GLIBCXX_TESTSUITE_NEW_OPERATORS_H
#include <new>
+#include <cstdlib>
#include <testsuite_hooks.h>
namespace __gnu_test
diff --git a/libstdc++-v3/testsuite/util/testsuite_random.h b/libstdc++-v3/testsuite/util/testsuite_random.h
index 533be4f..68968ae 100644
--- a/libstdc++-v3/testsuite/util/testsuite_random.h
+++ b/libstdc++-v3/testsuite/util/testsuite_random.h
@@ -27,6 +27,7 @@
#include <cmath>
#include <initializer_list>
#include <system_error>
+#include <random>
#include <testsuite_hooks.h>
namespace __gnu_test