aboutsummaryrefslogtreecommitdiff
path: root/libstdc++-v3/testsuite
diff options
context:
space:
mode:
Diffstat (limited to 'libstdc++-v3/testsuite')
-rw-r--r--libstdc++-v3/testsuite/17_intro/headers/c++1998/49745.cc2
-rw-r--r--libstdc++-v3/testsuite/17_intro/names.cc2
-rw-r--r--libstdc++-v3/testsuite/20_util/copyable_function/call.cc7
-rw-r--r--libstdc++-v3/testsuite/20_util/copyable_function/conv.cc35
-rw-r--r--libstdc++-v3/testsuite/20_util/copyable_function/incomplete_neg.cc18
-rw-r--r--libstdc++-v3/testsuite/20_util/function_ref/call.cc10
-rw-r--r--libstdc++-v3/testsuite/20_util/function_ref/conv.cc34
-rw-r--r--libstdc++-v3/testsuite/20_util/function_ref/incomplete_neg.cc18
-rw-r--r--libstdc++-v3/testsuite/20_util/move_only_function/call.cc7
-rw-r--r--libstdc++-v3/testsuite/20_util/move_only_function/conv.cc35
-rw-r--r--libstdc++-v3/testsuite/20_util/move_only_function/incomplete_neg.cc18
-rw-r--r--libstdc++-v3/testsuite/20_util/system_clock/99832.cc14
-rw-r--r--libstdc++-v3/testsuite/22_locale/num_put/put/char/lwg4084.cc8
-rw-r--r--libstdc++-v3/testsuite/23_containers/deque/capacity/shrink_to_fit.cc1
-rw-r--r--libstdc++-v3/testsuite/23_containers/flat_map/1.cc3
-rw-r--r--libstdc++-v3/testsuite/23_containers/flat_multimap/1.cc3
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_map/96088.cc2
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_multimap/96088.cc2
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_multiset/96088.cc2
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_set/96088.cc2
-rw-r--r--libstdc++-v3/testsuite/24_iterators/operations/prev_neg.cc2
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/ends_with/1.cc165
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/starts_with/1.cc158
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/unique_copy/lwg2439.cc127
-rw-r--r--libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/100334.cc7
-rw-r--r--libstdc++-v3/testsuite/29_atomics/atomic_integral/wait_notify.cc8
-rw-r--r--libstdc++-v3/testsuite/30_threads/barrier/cons.cc6
-rw-r--r--libstdc++-v3/testsuite/30_threads/barrier/lwg3898.cc45
-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/cons.cc7
-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_posix.cc153
-rw-r--r--libstdc++-v3/testsuite/experimental/names.cc2
-rw-r--r--libstdc++-v3/testsuite/std/memory/polymorphic/copy.cc157
-rw-r--r--libstdc++-v3/testsuite/std/memory/polymorphic/copy_alloc.cc270
-rw-r--r--libstdc++-v3/testsuite/std/memory/polymorphic/ctor.cc190
-rw-r--r--libstdc++-v3/testsuite/std/memory/polymorphic/ctor_poly.cc220
-rw-r--r--libstdc++-v3/testsuite/std/memory/polymorphic/incomplete.cc13
-rw-r--r--libstdc++-v3/testsuite/std/memory/polymorphic/invalid_neg.cc28
-rw-r--r--libstdc++-v3/testsuite/std/memory/polymorphic/move.cc177
-rw-r--r--libstdc++-v3/testsuite/std/memory/polymorphic/move_alloc.cc339
-rw-r--r--libstdc++-v3/testsuite/std/time/format/empty_spec.cc756
-rw-r--r--libstdc++-v3/testsuite/util/testsuite_abi.cc1
45 files changed, 3046 insertions, 190 deletions
diff --git a/libstdc++-v3/testsuite/17_intro/headers/c++1998/49745.cc b/libstdc++-v3/testsuite/17_intro/headers/c++1998/49745.cc
index 7fafe7b..3b9d2eb 100644
--- a/libstdc++-v3/testsuite/17_intro/headers/c++1998/49745.cc
+++ b/libstdc++-v3/testsuite/17_intro/headers/c++1998/49745.cc
@@ -131,5 +131,3 @@
#endif
int truncate = 0;
-
-// { dg-xfail-if "PR libstdc++/99995" { c++20 } }
diff --git a/libstdc++-v3/testsuite/17_intro/names.cc b/libstdc++-v3/testsuite/17_intro/names.cc
index a61e49d..f32205d 100644
--- a/libstdc++-v3/testsuite/17_intro/names.cc
+++ b/libstdc++-v3/testsuite/17_intro/names.cc
@@ -248,6 +248,8 @@
#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
diff --git a/libstdc++-v3/testsuite/20_util/copyable_function/call.cc b/libstdc++-v3/testsuite/20_util/copyable_function/call.cc
index cf99757..0ac5348 100644
--- a/libstdc++-v3/testsuite/20_util/copyable_function/call.cc
+++ b/libstdc++-v3/testsuite/20_util/copyable_function/call.cc
@@ -204,13 +204,14 @@ test05()
}
struct Incomplete;
+enum CompleteEnum : int;
void
test_params()
{
- std::copyable_function<void(Incomplete)> f1;
- std::copyable_function<void(Incomplete&)> f2;
- std::copyable_function<void(Incomplete&&)> f3;
+ std::copyable_function<void(Incomplete&)> f1;
+ std::copyable_function<void(Incomplete&&)> f2;
+ std::copyable_function<void(CompleteEnum)> f4;
}
int main()
diff --git a/libstdc++-v3/testsuite/20_util/copyable_function/conv.cc b/libstdc++-v3/testsuite/20_util/copyable_function/conv.cc
index e678e16..11c839b 100644
--- a/libstdc++-v3/testsuite/20_util/copyable_function/conv.cc
+++ b/libstdc++-v3/testsuite/20_util/copyable_function/conv.cc
@@ -2,6 +2,7 @@
// { dg-require-effective-target hosted }
#include <functional>
+#include <string_view>
#include <testsuite_hooks.h>
using std::copyable_function;
@@ -15,6 +16,21 @@ static_assert( !std::is_constructible_v<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
{
@@ -240,6 +256,24 @@ test06()
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();
@@ -248,4 +282,5 @@ int main()
test04();
test05();
test06();
+ test07();
}
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/function_ref/call.cc b/libstdc++-v3/testsuite/20_util/function_ref/call.cc
index a91c6b4..23253c3 100644
--- a/libstdc++-v3/testsuite/20_util/function_ref/call.cc
+++ b/libstdc++-v3/testsuite/20_util/function_ref/call.cc
@@ -164,16 +164,16 @@ test05()
}
struct Incomplete;
+enum CompleteEnum : int;
void
test_params()
{
auto f = [](auto&&) {};
- // There is discussion if this is supported.
- // std::function_ref<void(Incomplete)> f1(f);
- std::function_ref<void(Incomplete&)> f2(f);
- // See PR120259, this should be supported.
- // std::function_ref<void(Incomplete&&)> f3(f);
+ 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()
diff --git a/libstdc++-v3/testsuite/20_util/function_ref/conv.cc b/libstdc++-v3/testsuite/20_util/function_ref/conv.cc
index 7dc7b8c..7606d26 100644
--- a/libstdc++-v3/testsuite/20_util/function_ref/conv.cc
+++ b/libstdc++-v3/testsuite/20_util/function_ref/conv.cc
@@ -2,6 +2,7 @@
// { dg-require-effective-target hosted }
#include <functional>
+#include <string_view>
#include <testsuite_hooks.h>
using std::function_ref;
@@ -20,6 +21,21 @@ struct CountedArg
};
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.
@@ -244,6 +260,23 @@ test08()
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()
{
@@ -254,6 +287,7 @@ int main()
test05();
test06();
test07();
+ test09();
static_assert( test08() );
}
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/move_only_function/call.cc b/libstdc++-v3/testsuite/20_util/move_only_function/call.cc
index 217de37..72c8118 100644
--- a/libstdc++-v3/testsuite/20_util/move_only_function/call.cc
+++ b/libstdc++-v3/testsuite/20_util/move_only_function/call.cc
@@ -204,13 +204,14 @@ test05()
}
struct Incomplete;
+enum CompleteEnum : int;
void
test_params()
{
- std::move_only_function<void(Incomplete)> f1;
- std::move_only_function<void(Incomplete&)> f2;
- std::move_only_function<void(Incomplete&&)> f3;
+ std::move_only_function<void(Incomplete&)> f1;
+ std::move_only_function<void(Incomplete&&)> f2;
+ std::move_only_function<void(CompleteEnum)> f4;
}
int main()
diff --git a/libstdc++-v3/testsuite/20_util/move_only_function/conv.cc b/libstdc++-v3/testsuite/20_util/move_only_function/conv.cc
index 3da5e9e..ef8bb37b 100644
--- a/libstdc++-v3/testsuite/20_util/move_only_function/conv.cc
+++ b/libstdc++-v3/testsuite/20_util/move_only_function/conv.cc
@@ -2,6 +2,7 @@
// { dg-require-effective-target hosted }
#include <functional>
+#include <string_view>
#include <testsuite_hooks.h>
using std::move_only_function;
@@ -15,6 +16,21 @@ static_assert( !std::is_constructible_v<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
{
@@ -177,6 +193,24 @@ test06()
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();
@@ -185,4 +219,5 @@ int main()
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/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/22_locale/num_put/put/char/lwg4084.cc b/libstdc++-v3/testsuite/22_locale/num_put/put/char/lwg4084.cc
index b7c7da1..6ce4e8f 100644
--- a/libstdc++-v3/testsuite/22_locale/num_put/put/char/lwg4084.cc
+++ b/libstdc++-v3/testsuite/22_locale/num_put/put/char/lwg4084.cc
@@ -20,7 +20,11 @@ test_nan()
out << ' ' << nan << ' ' << -nan;
out << std::showpos;
out << ' ' << nan << ' ' << -nan;
+#ifdef _AIX // non-conforming
+ VERIFY( out.str() == " NaNQ -NaNQ NaNQ -NaNQ NaNQ -NaNQ +NaNQ -NaNQ" );
+#else
VERIFY( out.str() == " nan -nan NAN -NAN NAN -NAN +NAN -NAN" );
+#endif
}
void
@@ -36,7 +40,11 @@ test_inf()
out << ' ' << inf << ' ' << -inf;
out << std::showpos;
out << ' ' << inf << ' ' << -inf;
+#ifdef _AIX // non-conforming
+ VERIFY( out.str() == " INF -INF INF -INF INF -INF +INF -INF" );
+#else
VERIFY( out.str() == " inf -inf INF -INF INF -INF +INF -INF" );
+#endif
}
int main()
diff --git a/libstdc++-v3/testsuite/23_containers/deque/capacity/shrink_to_fit.cc b/libstdc++-v3/testsuite/23_containers/deque/capacity/shrink_to_fit.cc
index 4dbf405..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,6 +1,5 @@
// { dg-do run { target c++11 } }
// { dg-require-effective-target std_allocator_new }
-// { dg-xfail-run-if "AIX operator new" { powerpc-ibm-aix* } }
// 2010-01-08 Paolo Carlini <paolo.carlini@oracle.com>
diff --git a/libstdc++-v3/testsuite/23_containers/flat_map/1.cc b/libstdc++-v3/testsuite/23_containers/flat_map/1.cc
index a969020..1b59313 100644
--- a/libstdc++-v3/testsuite/23_containers/flat_map/1.cc
+++ b/libstdc++-v3/testsuite/23_containers/flat_map/1.cc
@@ -247,8 +247,9 @@ 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) { auto [k,v] = x; return k == 1 || v == 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}}) );
}
diff --git a/libstdc++-v3/testsuite/23_containers/flat_multimap/1.cc b/libstdc++-v3/testsuite/23_containers/flat_multimap/1.cc
index 1c5c9a8..d746614 100644
--- a/libstdc++-v3/testsuite/23_containers/flat_multimap/1.cc
+++ b/libstdc++-v3/testsuite/23_containers/flat_multimap/1.cc
@@ -225,8 +225,9 @@ 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) { auto [k,v] = x; return k == 1 || v == 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}}) );
}
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_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_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_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/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/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/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_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/29_atomics/atomic/wait_notify/100334.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/100334.cc
index 018c0c9..21ff570c 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/100334.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/100334.cc
@@ -47,16 +47,17 @@ int
main()
{
// all atomic share the same waiter
-// atomics_sharing_same_waiter<char> atomics;
atomics_sharing_same_waiter<char> atomics;
for (auto& atom : atomics.a)
{
atom->store(0);
}
- auto a = &std::__detail::__waiter_pool_base::_S_for(reinterpret_cast<char *>(atomics.a[0]));
- auto b = &std::__detail::__waiter_pool_base::_S_for(reinterpret_cast<char *>(atomics.a[1]));
+#if 0
+ auto a = &std::__detail::__waitable_state::_S_state_for((void*)(atomics.a[0]));
+ auto b = &std::__detail::__waitable_state::_S_state_for((void*)(atomics.a[1]));
VERIFY( a == b );
+#endif
auto fut0 = std::async(std::launch::async, [&] { atomics.a[0]->wait(0); });
auto fut1 = std::async(std::launch::async, [&] { atomics.a[1]->wait(0); });
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_integral/wait_notify.cc b/libstdc++-v3/testsuite/29_atomics/atomic_integral/wait_notify.cc
index c7f8779..6e74f2c 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic_integral/wait_notify.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_integral/wait_notify.cc
@@ -33,12 +33,16 @@ template<typename Tp>
std::atomic<Tp> a{ Tp(1) };
VERIFY( a.load() == Tp(1) );
a.wait( Tp(0) );
+ std::atomic<bool> b{false};
std::thread t([&]
{
- a.store(Tp(0));
- a.notify_one();
+ b.store(true, std::memory_order_relaxed);
+ a.store(Tp(0));
+ a.notify_one();
});
a.wait(Tp(1));
+ // Ensure we actually waited until a.store(0) happened:
+ VERIFY( b.load(std::memory_order_relaxed) );
t.join();
}
diff --git a/libstdc++-v3/testsuite/30_threads/barrier/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/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/cons.cc b/libstdc++-v3/testsuite/30_threads/semaphore/cons.cc
new file mode 100644
index 0000000..920f742
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/cons.cc
@@ -0,0 +1,7 @@
+// { dg-do compile { target c++20 } }
+
+#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/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_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/experimental/names.cc b/libstdc++-v3/testsuite/experimental/names.cc
index 4bedd53..94ae76f 100644
--- a/libstdc++-v3/testsuite/experimental/names.cc
+++ b/libstdc++-v3/testsuite/experimental/names.cc
@@ -25,7 +25,7 @@
#ifdef _AIX
// <netdb.h> declares endnetgrent_r with ptr parameter.
-# undef n
+# undef ptr
#endif
// Filesystem
diff --git a/libstdc++-v3/testsuite/std/memory/polymorphic/copy.cc b/libstdc++-v3/testsuite/std/memory/polymorphic/copy.cc
new file mode 100644
index 0000000..bea05ac
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/memory/polymorphic/copy.cc
@@ -0,0 +1,157 @@
+// { dg-do run { target c++26 } }
+
+#include <memory>
+#include <scoped_allocator>
+#include <utility>
+#include <vector>
+
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct Base {
+ friend constexpr
+ bool operator==(const Base& lhs, const Base& rhs)
+ { return lhs.eq(rhs); }
+
+private:
+ constexpr virtual bool
+ eq(const Base& other) const = 0;
+};
+
+struct Derived : Base
+{
+ constexpr Derived()
+ : x(0), y(0), z(0)
+ { }
+
+ constexpr Derived(int a, int b, int c)
+ : x(a), y(b), z(c)
+ { }
+
+private:
+ constexpr bool
+ eq(const Base& other) const override
+ {
+ if (auto op = dynamic_cast<const Derived*>(&other))
+ return this->x == op->x && this->y == op->y && this->z == op->z;
+ return false;
+ }
+
+ int x;
+ int y;
+ int z;
+};
+
+using __gnu_test::tracker_allocator;
+using Counter = __gnu_test::tracker_allocator_counter;
+using Polymorhic = std::polymorphic<Base, tracker_allocator<Base>>;
+const Polymorhic src(std::in_place_type<Derived>, 1, 2, 3);
+
+constexpr void
+test_ctor()
+{
+ Counter::reset();
+ Polymorhic i1(src);
+ VERIFY( *i1 == *src );
+ VERIFY( &*i1 != &*src );
+ VERIFY( Counter::get_allocation_count() >= sizeof(Derived) );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 2 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+
+ Counter::reset();
+ Polymorhic i2(std::allocator_arg, {}, src);
+ VERIFY( *i2 == *src );
+ VERIFY( &*i2 != &*src );
+ VERIFY( Counter::get_allocation_count() >= sizeof(Derived) );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 2 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+}
+
+constexpr void
+test_assign()
+{
+ Counter::reset();
+ Polymorhic i1(std::in_place_type<Derived>);
+ const size_t holderSize = Counter::get_allocation_count();
+ VERIFY( holderSize >= sizeof(Derived) );
+ Counter::reset();
+
+ i1 = src;
+ VERIFY( *i1 == *src );
+ VERIFY( &*i1 != &*src );
+ VERIFY( Counter::get_allocation_count() == holderSize );
+ VERIFY( Counter::get_deallocation_count() == holderSize );
+ VERIFY( Counter::get_construct_count() == 2 );
+ VERIFY( Counter::get_destruct_count() == 1 );
+
+ auto(std::move(i1));
+ Counter::reset();
+
+ i1 = src;
+ VERIFY( *i1 == *src );
+ VERIFY( &*i1 != &*src );
+ VERIFY( Counter::get_allocation_count() == holderSize );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 2 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+}
+
+constexpr void
+test_valueless()
+{
+ Polymorhic e(std::in_place_type<Derived>);
+ auto(std::move(e));
+ VERIFY( e.valueless_after_move() );
+
+ Counter::reset();
+ Polymorhic i1(e);
+ VERIFY( i1.valueless_after_move() );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+
+ Polymorhic i2(std::allocator_arg, {}, e);
+ VERIFY( i2.valueless_after_move() );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+
+ Polymorhic i3(src);
+ Counter::reset();
+ i3 = e;
+ VERIFY( i3.valueless_after_move() );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() >= sizeof(Derived) );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 1 );
+
+ Counter::reset();
+ i3 = e;
+ VERIFY( i3.valueless_after_move() );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+}
+
+constexpr void
+test_all()
+{
+ test_ctor();
+ test_assign();
+ test_valueless();
+}
+
+int main()
+{
+ test_all();
+
+ static_assert([] {
+ test_all();
+ return true;
+ });
+}
diff --git a/libstdc++-v3/testsuite/std/memory/polymorphic/copy_alloc.cc b/libstdc++-v3/testsuite/std/memory/polymorphic/copy_alloc.cc
new file mode 100644
index 0000000..f41c32e
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/memory/polymorphic/copy_alloc.cc
@@ -0,0 +1,270 @@
+// { dg-do run { target c++26 } }
+
+#include <memory>
+#include <scoped_allocator>
+#include <utility>
+#include <vector>
+
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct Base {
+ friend constexpr
+ bool operator==(const Base& lhs, const Base& rhs)
+ { return lhs.eq(rhs); }
+
+ virtual constexpr int
+ get_alloc_personality() const
+ { return -1; }
+
+private:
+ constexpr virtual bool
+ eq(const Base& other) const = 0;
+};
+
+template<typename T, typename Allocator>
+struct VecDerived : Base, std::vector<T, Allocator>
+{
+ using VecBase = std::vector<T, Allocator>;
+
+ using VecBase::VecBase;
+
+ constexpr int
+ get_alloc_personality() const override
+ { return this->get_allocator().get_personality(); }
+
+private:
+
+ constexpr bool
+ eq(const Base& other) const override
+ {
+ if (auto op = dynamic_cast<const VecDerived*>(&other))
+ return *static_cast<const VecBase*>(this)
+ == *static_cast<const VecBase*>(op);
+ return false;
+ }
+};
+
+using __gnu_test::propagating_allocator;
+using __gnu_test::tracker_allocator;
+using Counter = __gnu_test::tracker_allocator_counter;
+
+template<bool Propagate>
+constexpr void
+test_ctor()
+{
+ using PropAlloc = propagating_allocator<int, Propagate>;
+ using Vector = VecDerived<int, PropAlloc>;
+ using ScopedAlloc = std::scoped_allocator_adaptor<
+ propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>,
+ PropAlloc>;
+ using Polymorphic = std::polymorphic<Vector, ScopedAlloc>;
+
+ const Polymorphic src(std::allocator_arg, ScopedAlloc{11, 22},
+ std::in_place_type<Vector>, {1, 2, 3});
+
+ Counter::reset();
+ Polymorphic i1(src);
+ VERIFY( *i1 == *src );
+ VERIFY( &*i1 != &*src );
+ if (Propagate)
+ {
+ VERIFY( i1->get_alloc_personality() == 22 );
+ VERIFY( i1.get_allocator().get_personality() == 11 );
+ }
+ else
+ {
+ VERIFY( i1->get_alloc_personality() == 0 );
+ VERIFY( i1.get_allocator().get_personality() == 0 );
+ }
+ VERIFY( Counter::get_allocation_count() >= sizeof(Vector) );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 2 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+
+
+ Counter::reset();
+ Polymorphic i2(std::allocator_arg, ScopedAlloc{33, 44}, src);
+ VERIFY( *i2 == *src );
+ VERIFY( &*i2 != &*src );
+ VERIFY( i2->get_alloc_personality() == 44 );
+ VERIFY( i2.get_allocator().get_personality() == 33 );
+ VERIFY( Counter::get_allocation_count() >= sizeof(Vector) );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 2 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+}
+
+template<bool Propagate>
+constexpr void
+test_assign()
+{
+ using PropAlloc = propagating_allocator<int, Propagate>;
+ using Vector = VecDerived<int, PropAlloc>;
+ using ScopedAlloc = std::scoped_allocator_adaptor<
+ propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>,
+ PropAlloc>;
+ using Polymorphic = std::polymorphic<Vector, ScopedAlloc>;
+
+ const Polymorphic src(std::allocator_arg, ScopedAlloc{11, 22},
+ std::in_place_type<Vector>, {1, 2, 3});
+
+ Counter::reset();
+ Polymorphic i1(std::allocator_arg, ScopedAlloc{11, 22},
+ std::in_place_type<Vector>);
+ const size_t holderSize = Counter::get_allocation_count();
+ VERIFY( holderSize >= sizeof(Vector) );
+ Counter::reset();
+
+ i1 = src;
+ VERIFY( *i1 == *src );
+ VERIFY( &*i1 != &*src );
+ VERIFY( i1->get_alloc_personality() == 22 );
+ VERIFY( i1.get_allocator().get_personality() == 11 );
+ VERIFY( Counter::get_allocation_count() == holderSize );
+ VERIFY( Counter::get_deallocation_count() == holderSize );
+ VERIFY( Counter::get_construct_count() == 2 );
+ VERIFY( Counter::get_destruct_count() == 1 );
+
+ Polymorphic i2(std::allocator_arg, ScopedAlloc{33, 44});
+ Counter::reset();
+
+ i2 = src;
+ VERIFY( *i2 == *src );
+ VERIFY( &*i2 != &*src );
+ if (Propagate)
+ {
+ VERIFY( i2->get_alloc_personality() == 22 );
+ VERIFY( i2.get_allocator().get_personality() == 11 );
+ }
+ else
+ {
+ VERIFY( i2->get_alloc_personality() == 44 );
+ VERIFY( i2.get_allocator().get_personality() == 33 );
+ }
+ VERIFY( Counter::get_allocation_count() == holderSize );
+ VERIFY( Counter::get_deallocation_count() == holderSize );
+ VERIFY( Counter::get_construct_count() == 2 );
+ VERIFY( Counter::get_destruct_count() == 1 );
+
+ Polymorphic i3(std::allocator_arg, ScopedAlloc{11, 22});
+ auto(std::move(i3));
+ Counter::reset();
+
+ i3 = src;
+ VERIFY( *i3 == *src );
+ VERIFY( &*i3 != &*src );
+ VERIFY( i3->get_alloc_personality() == 22 );
+ VERIFY( i3.get_allocator().get_personality() == 11 );
+ VERIFY( Counter::get_allocation_count() == holderSize );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 2 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+
+ Polymorphic i4(std::allocator_arg, ScopedAlloc{33, 44});
+ auto(std::move(i4));
+ Counter::reset();
+
+ i4 = src;
+ VERIFY( *i4 == *src );
+ VERIFY( &*i4 != &*src );
+ if (Propagate)
+ {
+ VERIFY( i4->get_alloc_personality() == 22 );
+ VERIFY( i4.get_allocator().get_personality() == 11 );
+ }
+ else
+ {
+ VERIFY( i4->get_alloc_personality() == 44 );
+ VERIFY( i4.get_allocator().get_personality() == 33 );
+ }
+ VERIFY( Counter::get_allocation_count() == holderSize );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 2 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+}
+
+template<bool Propagate>
+constexpr void
+test_valueless()
+{
+ using PropAlloc = propagating_allocator<int, Propagate>;
+ using Vector = VecDerived<int, PropAlloc>;
+ using ScopedAlloc = std::scoped_allocator_adaptor<
+ propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>,
+ PropAlloc>;
+ using Polymorphic = std::polymorphic<Vector, ScopedAlloc>;
+
+ Polymorphic e(std::allocator_arg, ScopedAlloc{11, 22},
+ std::in_place_type<Vector>);
+ auto(std::move(e));
+ VERIFY( e.valueless_after_move() );
+
+ Counter::reset();
+ Polymorphic i1(e);
+ VERIFY( i1.valueless_after_move() );
+ if (Propagate)
+ VERIFY( i1.get_allocator().get_personality() == 11 );
+ else
+ VERIFY( i1.get_allocator().get_personality() == 0 );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+
+ Counter::reset();
+ Polymorphic i2(std::allocator_arg, ScopedAlloc{33, 44}, e);
+ VERIFY( i2.valueless_after_move() );
+ VERIFY( i2.get_allocator().get_personality() == 33 );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+
+ Polymorphic i3(std::allocator_arg, ScopedAlloc{33, 44});
+ Counter::reset();
+
+ i3 = e;
+ VERIFY( i3.valueless_after_move() );
+ if (Propagate)
+ VERIFY( i3.get_allocator().get_personality() == 11 );
+ else
+ VERIFY( i3.get_allocator().get_personality() == 33 );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() >= sizeof(Vector) );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 1 );
+
+ Counter::reset();
+ i2 = e;
+ VERIFY( i2.valueless_after_move() );
+ if (Propagate)
+ VERIFY( i2.get_allocator().get_personality() == 11 );
+ else
+ VERIFY( i2.get_allocator().get_personality() == 33 );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+}
+
+template<bool Propagate>
+constexpr void
+test_all()
+{
+ test_ctor<Propagate>();
+ test_assign<Propagate>();
+ test_valueless<Propagate>();
+}
+
+int main()
+{
+ test_all<true>();
+ test_all<false>();
+
+ static_assert([] {
+ test_all<true>();
+ test_all<false>();
+ return true;
+ });
+}
diff --git a/libstdc++-v3/testsuite/std/memory/polymorphic/ctor.cc b/libstdc++-v3/testsuite/std/memory/polymorphic/ctor.cc
new file mode 100644
index 0000000..bb4c947
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/memory/polymorphic/ctor.cc
@@ -0,0 +1,190 @@
+// { dg-do run { target c++26 } }
+
+#include <memory>
+#include <scoped_allocator>
+#include <utility>
+#include <vector>
+
+#ifndef __cpp_lib_polymorphic
+# error __cpp_lib_polymorphic feature test macro missing in <memory>
+#elif __cpp_lib_polymorphic != 202502
+# error __cpp_lib_polymorphic feature test macro has wrong value in <memory>
+#endif
+
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+using __gnu_test::uneq_allocator;
+using UneqAlloc = uneq_allocator<int>;
+using ScopedAlloc = std::scoped_allocator_adaptor<
+ uneq_allocator<std::vector<int, UneqAlloc>>,
+ UneqAlloc>;
+
+struct Obj
+{
+ int i;
+ char c[2];
+};
+
+constexpr void
+test_default_ctor()
+{
+ using __gnu_test::default_init_allocator;
+
+ std::polymorphic<Obj, default_init_allocator<Obj>> i1;
+ default_init_allocator<int> a{};
+
+ // The contained object and the allocator should be value-initialized.
+ VERIFY( i1->i == 0 );
+ VERIFY( i1->c[0] == 0 );
+ VERIFY( i1->c[1] == 0 );
+ VERIFY( i1.get_allocator() == a );
+
+ a.state = 5;
+ // Allocator-extended default constructor:
+ std::polymorphic<Obj, default_init_allocator<Obj>> i2(std::allocator_arg, a);
+ VERIFY( i2.get_allocator() == a );
+
+ // Object is constructed using allocator-aware constructor.
+ std::polymorphic<std::vector<int, UneqAlloc>, ScopedAlloc>
+ i3(std::allocator_arg, ScopedAlloc(11, 22));
+ VERIFY( i3->empty() );
+ VERIFY( i3->get_allocator().get_personality() == 22 );
+ VERIFY( i3.get_allocator().get_personality() == 11 );
+}
+
+constexpr void
+test_forwarding_ctor()
+{
+ Obj obj{1, {'2', '3'}};
+ auto verify = [](std::polymorphic<Obj> const& i)
+ {
+ VERIFY( i->i == 1 );
+ VERIFY( i->c[0] == '2' );
+ VERIFY( i->c[1] == '3' );
+ };
+
+ std::polymorphic<Obj> i1(std::as_const(obj));
+ verify(i1);
+ std::polymorphic<Obj> i2(std::move(std::as_const(obj)));
+ verify(i2);
+ std::polymorphic<Obj> i3(obj);
+ verify(i3);
+ std::polymorphic<Obj> i4(std::move(obj));
+ verify(i4);
+
+ std::polymorphic<Obj> i5({1, {'2', '3'}});
+ verify(i5);
+
+ std::vector<int, UneqAlloc> v{1, 2, 3, 4, 5};
+ // Object is constructed using allocator-aware constructor.
+ std::polymorphic<std::vector<int, UneqAlloc>, ScopedAlloc>
+ i7(std::allocator_arg, ScopedAlloc(11, 22), v);
+ VERIFY( i7->size() == 5 );
+ VERIFY( v.size() == 5 );
+ VERIFY( i7->get_allocator().get_personality() == 22 );
+ VERIFY( i7.get_allocator().get_personality() == 11 );
+
+ std::polymorphic<std::vector<int, UneqAlloc>, ScopedAlloc>
+ i8(std::allocator_arg, ScopedAlloc(11, 22), std::move(v));
+ VERIFY( i8->size() == 5 );
+ VERIFY( v.size() == 0 );
+ VERIFY( i8->get_allocator().get_personality() == 22 );
+ VERIFY( i8.get_allocator().get_personality() == 11 );
+}
+
+constexpr void
+test_inplace_ctor()
+{
+ std::polymorphic<Obj> i1(std::in_place_type<Obj>);
+ VERIFY( i1->i == 0 );
+ VERIFY( i1->c[0] == 0 );
+ VERIFY( i1->c[1] == 0 );
+
+ std::polymorphic<Obj> i2(std::in_place_type<Obj>, 10);
+ VERIFY( i2->i == 10 );
+ VERIFY( i2->c[0] == 0 );
+ VERIFY( i2->c[1] == 0 );
+
+ std::polymorphic<Obj, uneq_allocator<Obj>>
+ i3(std::allocator_arg, 42, std::in_place_type<Obj>);
+ VERIFY( i3->i == 0 );
+ VERIFY( i3->c[0] == 0 );
+ VERIFY( i3->c[1] == 0 );
+ VERIFY( i3.get_allocator().get_personality() == 42 );
+
+ std::polymorphic<Obj, uneq_allocator<Obj>>
+ i4(std::allocator_arg, 42, std::in_place_type<Obj>, 10);
+ VERIFY( i4->i == 10 );
+ VERIFY( i4->c[0] == 0 );
+ VERIFY( i4->c[1] == 0 );
+ VERIFY( i4.get_allocator().get_personality() == 42 );
+
+ std::polymorphic<std::vector<int>>
+ i5(std::in_place_type<std::vector<int>>);
+ VERIFY( i5->size() == 0 );
+
+ std::polymorphic<std::vector<int>>
+ i6(std::in_place_type<std::vector<int>>, 5, 13);
+ VERIFY( i6->size() == 5 );
+ VERIFY( i6->at(0) == 13 );
+
+ std::polymorphic<std::vector<int>>
+ i7(std::in_place_type<std::vector<int>>, {1, 2, 3, 4});
+ VERIFY( i7->size() == 4 );
+ VERIFY( i7->at(2) == 3 );
+
+ std::polymorphic<std::vector<int, UneqAlloc>>
+ i8(std::in_place_type<std::vector<int, UneqAlloc>>, UneqAlloc{42});
+ VERIFY( i8->size() == 0 );
+ VERIFY( i8->get_allocator().get_personality() == 42 );
+
+ std::polymorphic<std::vector<int, UneqAlloc>>
+ i9(std::in_place_type<std::vector<int, UneqAlloc>>, 5, 13, UneqAlloc{42});
+ VERIFY( i9->size() == 5 );
+ VERIFY( i9->at(0) == 13 );
+ VERIFY( i9->get_allocator().get_personality() == 42 );
+
+ std::polymorphic<std::vector<int, UneqAlloc>>
+ i10(std::in_place_type<std::vector<int, UneqAlloc>>, {1, 2, 3, 4}, UneqAlloc{42});
+ VERIFY( i10->size() == 4 );
+ VERIFY( i10->at(2) == 3 );
+ VERIFY( i10->get_allocator().get_personality() == 42 );
+
+ std::polymorphic<std::vector<int, UneqAlloc>, ScopedAlloc>
+ i14(std::allocator_arg, ScopedAlloc(11, 22),
+ std::in_place_type<std::vector<int, UneqAlloc>>);
+ VERIFY( i14->size() == 0 );
+ VERIFY( i14->get_allocator().get_personality() == 22 );
+ VERIFY( i14.get_allocator().get_personality() == 11 );
+
+ std::polymorphic<std::vector<int, UneqAlloc>, ScopedAlloc>
+ i15(std::allocator_arg, ScopedAlloc(11, 22),
+ std::in_place_type<std::vector<int, UneqAlloc>>, 5, 13);
+ VERIFY( i15->size() == 5 );
+ VERIFY( i15->at(0) == 13 );
+ VERIFY( i15->get_allocator().get_personality() == 22 );
+ VERIFY( i15.get_allocator().get_personality() == 11 );
+
+ std::polymorphic<std::vector<int, UneqAlloc>, ScopedAlloc>
+ i16(std::allocator_arg, ScopedAlloc(11, 22),
+ std::in_place_type<std::vector<int, UneqAlloc>>, {1, 2, 3, 4});
+ VERIFY( i16->size() == 4 );
+ VERIFY( i16->at(2) == 3 );
+ VERIFY( i16->get_allocator().get_personality() == 22 );
+ VERIFY( i16.get_allocator().get_personality() == 11 );
+}
+
+int main()
+{
+ test_default_ctor();
+ test_forwarding_ctor();
+ test_inplace_ctor();
+
+ static_assert([] {
+ test_default_ctor();
+ test_forwarding_ctor();
+ test_inplace_ctor();
+ return true;
+ });
+}
diff --git a/libstdc++-v3/testsuite/std/memory/polymorphic/ctor_poly.cc b/libstdc++-v3/testsuite/std/memory/polymorphic/ctor_poly.cc
new file mode 100644
index 0000000..03519a1
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/memory/polymorphic/ctor_poly.cc
@@ -0,0 +1,220 @@
+// { dg-do run { target c++26 } }
+
+#include <memory>
+#include <scoped_allocator>
+#include <utility>
+#include <vector>
+
+#ifndef __cpp_lib_polymorphic
+# error __cpp_lib_polymorphic feature test macro missing in <memory>
+#elif __cpp_lib_polymorphic != 202502
+# error __cpp_lib_polymorphic feature test macro has wrong value in <memory>
+#endif
+
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct Base {
+ friend constexpr
+ bool operator==(const Base& lhs, const Base& rhs)
+ { return lhs.eq(rhs); }
+
+ virtual constexpr int
+ get_personality() const
+ { return -1; }
+
+private:
+ constexpr virtual bool
+ eq(const Base& other) const
+ { return true; }
+};
+
+struct ObjDerived : Base
+{
+ constexpr ObjDerived()
+ : x(0), y(0), z(0)
+ { }
+
+ constexpr ObjDerived(int a, int b, int c)
+ : x(a), y(b), z(c)
+ { }
+
+ virtual constexpr int
+ get_personality() const
+ { return -2; }
+
+private:
+ constexpr bool
+ eq(const Base& other) const override
+ {
+ if (auto op = dynamic_cast<const ObjDerived*>(&other))
+ return this->x == op->x && this->y == op->y && this->z == op->z;
+ return false;
+ }
+
+ int x;
+ int y;
+ int z;
+};
+
+template<typename T, typename Allocator>
+struct VecDerived : Base, std::vector<T, Allocator>
+{
+ using VecBase = std::vector<T, Allocator>;
+
+ using VecBase::VecBase;
+
+ constexpr int
+ get_personality() const override
+ { return this->get_allocator().get_personality(); }
+
+private:
+
+ constexpr bool
+ eq(const Base& other) const override
+ {
+ if (auto op = dynamic_cast<const VecDerived*>(&other))
+ return *static_cast<const VecBase*>(this)
+ == *static_cast<const VecBase*>(op);
+ return false;
+ }
+};
+
+using __gnu_test::uneq_allocator;
+using UneqAlloc = uneq_allocator<int>;
+using ScopedAlloc = std::scoped_allocator_adaptor<
+ uneq_allocator<Base>,
+ UneqAlloc>;
+
+constexpr void
+test_default_ctor()
+{
+ using __gnu_test::default_init_allocator;
+
+ std::polymorphic<Base, default_init_allocator<Base>> i1;
+ default_init_allocator<int> a{};
+
+ // The contained object and the allocator should be value-initialized.
+ VERIFY( *i1 == Base() );
+ VERIFY( i1->get_personality() == -1 );
+ VERIFY( i1.get_allocator() == a );
+
+ a.state = 5;
+ // Allocator-extended default constructor:
+ std::polymorphic<Base, default_init_allocator<Base>> i2(std::allocator_arg, a);
+ VERIFY( *i1 == Base() );
+ VERIFY( i1->get_personality() == -1 );
+}
+
+constexpr void
+test_forwarding_ctor()
+{
+ const ObjDerived src(1, 2, 3);
+
+ std::polymorphic<Base> i1(src);
+ VERIFY( *i1 == src );
+ VERIFY( i1->get_personality() == -2 );
+ std::polymorphic<Base> i2(std::move(src));
+ VERIFY( *i2 == src );
+ VERIFY( i2->get_personality() == -2 );
+
+ ObjDerived obj = src;
+ std::polymorphic<Base> i3(obj);
+ VERIFY( *i3 == src );
+ VERIFY( i3->get_personality() == -2 );
+ std::polymorphic<Base> i4(std::move(obj));
+ VERIFY( *i4 == src );
+ VERIFY( i4->get_personality() == -2 );
+
+ const VecDerived<int, UneqAlloc> v{1, 2, 3, 4, 5};
+ // Object is constructed using allocator-aware constructor.
+ std::polymorphic<Base, ScopedAlloc>
+ i5(std::allocator_arg, ScopedAlloc(11, 22), v);
+ VERIFY( *i5 == v );
+ VERIFY( i5->get_personality() == 22 );
+ VERIFY( i5.get_allocator().get_personality() == 11 );
+
+ std::polymorphic<Base, ScopedAlloc>
+ i6(std::allocator_arg, ScopedAlloc(11, 22), auto(v));
+ VERIFY( *i6 == v );
+ VERIFY( i6->get_personality() == 22 );
+ VERIFY( i6.get_allocator().get_personality() == 11 );
+}
+
+constexpr void
+test_inplace_ctor()
+{
+ std::polymorphic<Base> i1(std::in_place_type<ObjDerived>);
+ VERIFY( *i1 == ObjDerived() );
+ VERIFY( i1->get_personality() == -2 );
+
+ std::polymorphic<Base> i2(std::in_place_type<ObjDerived>, 10, 20, 30);
+ VERIFY( *i2 == ObjDerived(10, 20, 30) );
+ VERIFY( i2->get_personality() == -2 );
+
+ std::polymorphic<Base, uneq_allocator<Base>>
+ i3(std::allocator_arg, 42, std::in_place_type<ObjDerived>);
+ VERIFY( *i3 == ObjDerived() );
+ VERIFY( i3->get_personality() == -2 );
+ VERIFY( i3.get_allocator().get_personality() == 42 );
+
+ std::polymorphic<Base, uneq_allocator<Base>>
+ i4(std::allocator_arg, 42, std::in_place_type<ObjDerived>, 10, 20, 30);
+ VERIFY( *i4 == ObjDerived(10, 20, 30) );
+ VERIFY( i4->get_personality() == -2 );
+ VERIFY( i4.get_allocator().get_personality() == 42 );
+
+ const VecDerived<int, UneqAlloc> ze;
+ const VecDerived<int, UneqAlloc> fe(5, 13);
+ const VecDerived<int, UneqAlloc> il{1, 2, 3 ,4};
+
+ std::polymorphic<Base>
+ i5(std::in_place_type<VecDerived<int, UneqAlloc>>, UneqAlloc{42});
+ VERIFY( *i5 == ze );
+ VERIFY( i5->get_personality() == 42 );
+
+ std::polymorphic<Base>
+ i6(std::in_place_type<VecDerived<int, UneqAlloc>>, 5, 13, UneqAlloc{42});
+ VERIFY( *i6 == fe );
+ VERIFY( i6->get_personality() == 42 );
+
+ std::polymorphic<Base>
+ i7(std::in_place_type<VecDerived<int, UneqAlloc>>, {1, 2, 3, 4}, UneqAlloc{42});
+ VERIFY( *i7 == il );
+ VERIFY( i7->get_personality() == 42 );
+
+ std::polymorphic<Base, ScopedAlloc>
+ i8(std::allocator_arg, ScopedAlloc(11, 22),
+ std::in_place_type<VecDerived<int, UneqAlloc>>);
+ VERIFY( *i8 == ze );
+ VERIFY( i8->get_personality() == 22 );
+ VERIFY( i8.get_allocator().get_personality() == 11 );
+
+ std::polymorphic<Base, ScopedAlloc>
+ i9(std::allocator_arg, ScopedAlloc(11, 22),
+ std::in_place_type<VecDerived<int, UneqAlloc>>, 5, 13);
+ VERIFY( *i9 == fe );
+ VERIFY( i9->get_personality() == 22 );
+ VERIFY( i9.get_allocator().get_personality() == 11 );
+
+ std::polymorphic<Base, ScopedAlloc>
+ i10(std::allocator_arg, ScopedAlloc(11, 22),
+ std::in_place_type<VecDerived<int, UneqAlloc>>, {1, 2, 3, 4});
+ VERIFY( *i10 == il );
+ VERIFY( i10->get_personality() == 22 );
+ VERIFY( i10.get_allocator().get_personality() == 11 );
+}
+
+int main()
+{
+ test_default_ctor();
+ test_forwarding_ctor();
+ test_inplace_ctor();
+
+ static_assert([] {
+ test_default_ctor();
+ test_forwarding_ctor();
+ test_inplace_ctor();
+ return true;
+ });
+}
diff --git a/libstdc++-v3/testsuite/std/memory/polymorphic/incomplete.cc b/libstdc++-v3/testsuite/std/memory/polymorphic/incomplete.cc
new file mode 100644
index 0000000..e5dd78f
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/memory/polymorphic/incomplete.cc
@@ -0,0 +1,13 @@
+// { dg-do compile { target c++26 } }
+
+#include <memory>
+
+struct Incomplete;
+
+std::polymorphic<Incomplete>*
+test_move(std::polymorphic<Incomplete>& i1, std::polymorphic<Incomplete>& i2)
+{
+ i1 = std::move(i2);
+ swap(i1, i2);
+ return new std::polymorphic<Incomplete>(std::move(i1));
+}
diff --git a/libstdc++-v3/testsuite/std/memory/polymorphic/invalid_neg.cc b/libstdc++-v3/testsuite/std/memory/polymorphic/invalid_neg.cc
new file mode 100644
index 0000000..a01af3f
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/memory/polymorphic/invalid_neg.cc
@@ -0,0 +1,28 @@
+// { dg-do compile { target c++26 } }
+
+#include <memory>
+
+// In every specialization polymorphic<T, Allocator>, if the type
+// allocator_traits<Allocator>::value_type is not the same type as T,
+// the program is ill-formed.
+using T1 = std::polymorphic<int, std::allocator<long>>::value_type; // { dg-error "here" }
+
+// A program that instantiates the definition of the template
+// polymorphic<T, Allocator> with a type for the T parameter that is
+// a non-object type, an array type, in_place_t,
+// a specialization of in_place_type_t, or a cv-qualified type is ill-formed.
+
+using T2 = std::polymorphic<int&>::value_type; // { dg-error "here" }
+
+using T3 = std::polymorphic<int[1]>::value_type; // { dg-error "here" }
+
+using T4 = std::polymorphic<std::in_place_t>::value_type; // { dg-error "here" }
+
+using T5 = std::polymorphic<std::in_place_type_t<int>>::value_type; // { dg-error "here" }
+
+using T6 = std::polymorphic<const int>::value_type; // { dg-error "here" }
+
+using T7 = std::polymorphic<volatile int>::value_type; // { dg-error "here" }
+
+// { dg-error "static assertion failed" "" { target *-*-* } 0 }
+// { dg-prune-output "forming pointer to reference" }
diff --git a/libstdc++-v3/testsuite/std/memory/polymorphic/move.cc b/libstdc++-v3/testsuite/std/memory/polymorphic/move.cc
new file mode 100644
index 0000000..c802159
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/memory/polymorphic/move.cc
@@ -0,0 +1,177 @@
+// { dg-do run { target c++26 } }
+
+#include <memory>
+#include <scoped_allocator>
+#include <utility>
+#include <vector>
+#include <optional>
+
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct Base {
+ friend constexpr
+ bool operator==(const Base& lhs, const Base& rhs)
+ { return lhs.eq(rhs); }
+
+private:
+ constexpr virtual bool
+ eq(const Base& other) const = 0;
+};
+
+struct Derived : Base
+{
+ constexpr Derived()
+ : x(0), y(0), z(0)
+ { }
+
+ constexpr Derived(int a, int b, int c)
+ : x(a), y(b), z(c)
+ { }
+
+private:
+ constexpr bool
+ eq(const Base& other) const override
+ {
+ if (auto op = dynamic_cast<const Derived*>(&other))
+ return this->x == op->x && this->y == op->y && this->z == op->z;
+ return false;
+ }
+
+ int x;
+ int y;
+ int z;
+};
+
+using __gnu_test::tracker_allocator;
+using Counter = __gnu_test::tracker_allocator_counter;
+using Polymorphic = std::polymorphic<Base, tracker_allocator<Base>>;
+const Polymorphic val(std::in_place_type<Derived>, 1, 2, 3);
+
+constexpr void
+verifyNoAllocations()
+{
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+}
+
+constexpr void
+test_ctor()
+{
+ std::optional<Polymorphic> src;
+ auto make = [&src] -> Polymorphic&& {
+ src.emplace(val);
+ Counter::reset();
+ return std::move(*src);
+ };
+
+ Polymorphic i1(make());
+ VERIFY( src->valueless_after_move() );
+ VERIFY( *i1 == *val );
+ verifyNoAllocations();
+
+ Polymorphic i2(std::allocator_arg, {}, make());
+ VERIFY( src->valueless_after_move() );
+ VERIFY( *i2 == *val );
+ verifyNoAllocations();
+}
+
+constexpr void
+test_assign()
+{
+ std::optional<Polymorphic> src;
+ auto make = [&src] -> Polymorphic&& {
+ src.emplace(val);
+ Counter::reset();
+ return std::move(*src);
+ };
+
+ Polymorphic i1(std::in_place_type<Derived>);
+
+ i1 = make();
+ VERIFY( src->valueless_after_move() );
+ VERIFY( *i1 == *val );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() >= sizeof(Derived) );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 1 );
+
+ auto(std::move(i1));
+ i1 = make();
+ VERIFY( *i1 == *val );
+ VERIFY( src->valueless_after_move() );
+ verifyNoAllocations();
+}
+
+constexpr void
+test_swap()
+{
+ const Polymorphic val1(std::in_place_type<Derived>, 1, 2, 3);
+ const Polymorphic val2(std::in_place_type<Derived>, 2, 4, 6);
+
+ Polymorphic i1(val1);
+ Polymorphic i2(val2);
+ Counter::reset();
+ i1.swap(i2);
+ VERIFY( *i2 == *val1 );
+ VERIFY( *i1 == *val2 );
+ verifyNoAllocations();
+
+ auto(std::move(i1));
+
+ Counter::reset();
+ i1.swap(i2);
+ VERIFY( *i1 == *val1 );
+ VERIFY( i2.valueless_after_move() );
+ verifyNoAllocations();
+}
+
+constexpr void
+test_valueless()
+{
+ auto e = [] {
+ Polymorphic res(std::in_place_type<Derived>);
+ auto(std::move(res));
+ Counter::reset();
+ return res;
+ };
+
+ Polymorphic i1(e());
+ VERIFY( i1.valueless_after_move() );
+ verifyNoAllocations();
+
+ Polymorphic i2(std::allocator_arg, {}, e());
+ VERIFY( i2.valueless_after_move() );
+ verifyNoAllocations();
+
+ Polymorphic i3(val);
+ i3 = e();
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() >= sizeof(Derived) );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 1 );
+
+ i3 = e();
+ verifyNoAllocations();
+}
+
+constexpr void
+test_all()
+{
+ test_ctor();
+ test_assign();
+ test_swap();
+ test_valueless();
+}
+
+int main()
+{
+ test_all();
+
+ static_assert([] {
+ test_all();
+ return true;
+ });
+}
diff --git a/libstdc++-v3/testsuite/std/memory/polymorphic/move_alloc.cc b/libstdc++-v3/testsuite/std/memory/polymorphic/move_alloc.cc
new file mode 100644
index 0000000..09afedb
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/memory/polymorphic/move_alloc.cc
@@ -0,0 +1,339 @@
+// { dg-do run { target c++26 } }
+
+#include <memory>
+#include <scoped_allocator>
+#include <utility>
+#include <vector>
+#include <optional>
+
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct Base {
+ friend constexpr
+ bool operator==(const Base& lhs, const Base& rhs)
+ { return lhs.eq(rhs); }
+
+ virtual constexpr int
+ get_alloc_personality() const
+ { return -1; }
+
+private:
+ constexpr virtual bool
+ eq(const Base& other) const = 0;
+};
+
+template<typename T, typename Allocator>
+struct VecDerived : Base, std::vector<T, Allocator>
+{
+ using VecBase = std::vector<T, Allocator>;
+
+ using VecBase::VecBase;
+
+ constexpr int
+ get_alloc_personality() const override
+ { return this->get_allocator().get_personality(); }
+
+private:
+
+ constexpr bool
+ eq(const Base& other) const override
+ {
+ if (auto op = dynamic_cast<const VecDerived*>(&other))
+ return *static_cast<const VecBase*>(this)
+ == *static_cast<const VecBase*>(op);
+ return false;
+ }
+};
+
+using __gnu_test::propagating_allocator;
+using __gnu_test::tracker_allocator;
+using Counter = __gnu_test::tracker_allocator_counter;
+
+constexpr void
+verifyNoAllocations()
+{
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+}
+
+template<bool Propagate>
+constexpr void
+test_ctor()
+{
+ using PropAlloc = propagating_allocator<int, Propagate>;
+ using Vector = VecDerived<int, PropAlloc>;
+ using ScopedAlloc = std::scoped_allocator_adaptor<
+ propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>,
+ PropAlloc>;
+ using Polymorphic = std::polymorphic<Vector, ScopedAlloc>;
+
+ const Polymorphic val(std::in_place_type<Vector>, {1, 2, 3});
+ std::optional<Polymorphic> src;
+ auto make = [&val, &src] -> Polymorphic&& {
+ src.emplace(std::allocator_arg, ScopedAlloc{11, 22}, val);
+ Counter::reset();
+ return std::move(*src);
+ };
+
+ Polymorphic i1(make());
+ VERIFY( src->valueless_after_move() );
+ VERIFY( *i1 == *val );
+ VERIFY( i1->get_alloc_personality() == 22 );
+ VERIFY( i1.get_allocator().get_personality() == 11 );
+ verifyNoAllocations();
+
+ Polymorphic i2(std::allocator_arg, ScopedAlloc{11, 22}, make());
+ VERIFY( src->valueless_after_move() );
+ VERIFY( *i2 == *val );
+ VERIFY( i2->get_alloc_personality() == 22 );
+ VERIFY( i2.get_allocator().get_personality() == 11 );
+ verifyNoAllocations();
+
+ Polymorphic i3(std::allocator_arg, ScopedAlloc{33, 44}, make());
+ // We move-from contained object
+ VERIFY( !src->valueless_after_move() );
+ VERIFY( *i3 == *val );
+ VERIFY( i3->get_alloc_personality() == 44 );
+ VERIFY( i3.get_allocator().get_personality() == 33 );
+ VERIFY( Counter::get_allocation_count() >= sizeof(Vector) );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 2 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+}
+
+template<bool Propagate>
+constexpr void
+test_assign()
+{
+ using PropAlloc = propagating_allocator<int, Propagate>;
+ using Vector = VecDerived<int, PropAlloc>;
+ using ScopedAlloc = std::scoped_allocator_adaptor<
+ propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>,
+ PropAlloc>;
+ using Polymorphic = std::polymorphic<Vector, ScopedAlloc>;
+
+ const Polymorphic val(std::in_place_type<Vector>, {1, 2, 3});
+ std::optional<Polymorphic> src;
+ auto make = [&val, &src] -> Polymorphic&& {
+ src.emplace(std::allocator_arg, ScopedAlloc{11, 22}, val);
+ Counter::reset();
+ return std::move(*src);
+ };
+
+ Counter::reset();
+ Polymorphic i1(std::allocator_arg, ScopedAlloc{11, 22});
+ const std::size_t holderSize = Counter::get_allocation_count();
+ VERIFY( holderSize >= sizeof(Vector) );
+
+ i1 = make();
+ VERIFY( src->valueless_after_move() );
+ VERIFY( *i1 == *val );
+ VERIFY( i1->get_alloc_personality() == 22 );
+ VERIFY( i1.get_allocator().get_personality() == 11 );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() == holderSize );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 1 );
+
+ Polymorphic i2(std::allocator_arg, ScopedAlloc{33, 44});
+
+ i2 = make();
+ VERIFY( *i2 == *val );
+ if (Propagate)
+ {
+ VERIFY( src->valueless_after_move() );
+ VERIFY( i2->get_alloc_personality() == 22 );
+ VERIFY( i2.get_allocator().get_personality() == 11 );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 0 );
+ }
+ else
+ {
+ // We allocate new holder and move-from contained object
+ VERIFY( !src->valueless_after_move() );
+ VERIFY( i2->get_alloc_personality() == 44 );
+ VERIFY( i2.get_allocator().get_personality() == 33 );
+ VERIFY( Counter::get_allocation_count() == holderSize );
+ VERIFY( Counter::get_construct_count() == 2 );
+ }
+ VERIFY( Counter::get_deallocation_count() == holderSize );
+ VERIFY( Counter::get_destruct_count() == 1 );
+
+ Polymorphic i3(std::allocator_arg, ScopedAlloc{11, 22},
+ std::in_place_type<Vector>);
+ auto(std::move(i3));
+
+ i3 = make();
+ VERIFY( *i3 == *val );
+ VERIFY( src->valueless_after_move() );
+ VERIFY( i3->get_alloc_personality() == 22 );
+ VERIFY( i3.get_allocator().get_personality() == 11 );
+ verifyNoAllocations();
+
+ Polymorphic i4(std::allocator_arg, ScopedAlloc{33, 44},
+ std::in_place_type<Vector>);
+ auto(std::move(i4));
+
+ i4 = make();
+ VERIFY( *i4 == *val );
+ if (Propagate)
+ {
+ VERIFY( src->valueless_after_move() );
+ VERIFY( i4->get_alloc_personality() == 22 );
+ VERIFY( i4.get_allocator().get_personality() == 11 );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 0 );
+ }
+ else
+ {
+ // We allocate new holder and move-from contained object
+ VERIFY( !src->valueless_after_move() );
+ VERIFY( i4->get_alloc_personality() == 44 );
+ VERIFY( i4.get_allocator().get_personality() == 33 );
+ VERIFY( Counter::get_allocation_count() == holderSize );
+ VERIFY( Counter::get_construct_count() == 2 );
+ }
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+}
+
+template<bool Propagate>
+constexpr void
+test_swap()
+{
+ using PropAlloc = propagating_allocator<int, Propagate>;
+ using Vector = VecDerived<int, PropAlloc>;
+ using ScopedAlloc = std::scoped_allocator_adaptor<
+ propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>,
+ PropAlloc>;
+ using Polymorphic = std::polymorphic<Vector, ScopedAlloc>;
+
+ const Polymorphic val1(std::in_place_type<Vector>, {1, 2, 3});
+ const Polymorphic val2(std::in_place_type<Vector>, {2, 4, 6});
+
+ Polymorphic i1(std::allocator_arg, ScopedAlloc{11, 22}, val1);
+ Polymorphic i2(std::allocator_arg, ScopedAlloc{11, 22}, val2);
+ Counter::reset();
+ i1.swap(i2);
+ VERIFY( *i2 == *val1 );
+ VERIFY( *i1 == *val2 );
+ verifyNoAllocations();
+
+ auto(std::move(i1));
+
+ Counter::reset();
+ i1.swap(i2);
+ VERIFY( *i1 == *val1 );
+ VERIFY( i2.valueless_after_move() );
+ verifyNoAllocations();
+
+ if (!Propagate)
+ return;
+
+ Polymorphic i3(std::allocator_arg, ScopedAlloc{33, 44}, val2);
+ Counter::reset();
+ i1.swap(i3);
+ VERIFY( *i1 == *val2 );
+ VERIFY( i1->get_alloc_personality() == 44 );
+ VERIFY( i1.get_allocator().get_personality() == 33 );
+ VERIFY( *i3 == *val1 );
+ VERIFY( i3->get_alloc_personality() == 22 );
+ VERIFY( i3.get_allocator().get_personality() == 11 );
+ verifyNoAllocations();
+
+ i1.swap(i2);
+ VERIFY( i1.valueless_after_move() );
+ VERIFY( i1.get_allocator().get_personality() == 11 );
+ VERIFY( *i2 == *val2 );
+ VERIFY( i2->get_alloc_personality() == 44 );
+ VERIFY( i2.get_allocator().get_personality() == 33 );
+ verifyNoAllocations();
+}
+
+template<bool Propagate>
+constexpr void
+test_valueless()
+{
+ using PropAlloc = propagating_allocator<int, Propagate>;
+ using Vector = VecDerived<int, PropAlloc>;
+ using ScopedAlloc = std::scoped_allocator_adaptor<
+ propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>,
+ PropAlloc>;
+ using Polymorphic = std::polymorphic<Vector, ScopedAlloc>;
+
+ auto e = [] {
+ Polymorphic res(std::allocator_arg, ScopedAlloc{11, 22},
+ std::in_place_type<Vector>);
+ auto(std::move(res));
+ Counter::reset();
+ return res;
+ };
+
+ Polymorphic i1(e());
+ VERIFY( i1.valueless_after_move() );
+ VERIFY( i1.get_allocator().get_personality() == 11 );
+ verifyNoAllocations();
+
+ Polymorphic i2(std::allocator_arg, ScopedAlloc{33, 44}, e());
+ VERIFY( i2.valueless_after_move() );
+ VERIFY( i2.get_allocator().get_personality() == 33 );
+ verifyNoAllocations();
+
+ Polymorphic i3(std::allocator_arg, ScopedAlloc{33, 44});
+
+ i3 = e();
+ VERIFY( i3.valueless_after_move() );
+ if (Propagate)
+ VERIFY( i3.get_allocator().get_personality() == 11 );
+ else
+ VERIFY( i3.get_allocator().get_personality() == 33 );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() >= sizeof(Vector) );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 1 );
+
+ i2 = e();
+ VERIFY( i2.valueless_after_move() );
+ if (Propagate)
+ VERIFY( i2.get_allocator().get_personality() == 11 );
+ else
+ VERIFY( i2.get_allocator().get_personality() == 33 );
+ verifyNoAllocations();
+
+ i3.swap(i2);
+ VERIFY( i2.valueless_after_move() );
+ VERIFY( i1.valueless_after_move() );
+ verifyNoAllocations();
+
+ if (!Propagate)
+ return;
+
+ Polymorphic i4(std::allocator_arg, ScopedAlloc{33, 44}, e());
+ i4.swap(i1);
+ verifyNoAllocations();
+}
+
+template<bool Propagate>
+constexpr void
+test_all()
+{
+ test_ctor<Propagate>();
+ test_assign<Propagate>();
+ test_swap<Propagate>();
+ test_valueless<Propagate>();
+}
+
+int main()
+{
+ test_all<true>();
+ test_all<false>();
+
+ static_assert([] {
+ test_all<true>();
+ test_all<false>();
+ return true;
+ });
+}
diff --git a/libstdc++-v3/testsuite/std/time/format/empty_spec.cc b/libstdc++-v3/testsuite/std/time/format/empty_spec.cc
new file mode 100644
index 0000000..a3c64f5
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/time/format/empty_spec.cc
@@ -0,0 +1,756 @@
+// { dg-do run { target c++20 } }
+// { dg-require-effective-target hosted }
+// { dg-timeout-factor 2 }
+
+#include <chrono>
+#include <ranges>
+#include <sstream>
+#include <testsuite_hooks.h>
+
+using namespace std::chrono;
+
+#define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S)
+#define WIDEN(S) WIDEN_(_CharT, S)
+
+template<typename CharT, typename T>
+void
+test_no_empty_spec()
+{
+ try
+ {
+ T t{};
+
+ if constexpr (std::is_same_v<CharT, char>)
+ (void)std::vformat("{}", std::make_format_args(t));
+#ifdef _GLIBCXX_USE_WCHAR_T
+ else
+ (void)std::vformat(L"{}", std::make_wformat_args(t));
+#endif // _GLIBCXX_USE_WCHAR_T
+ VERIFY(false);
+ }
+ catch (const std::format_error&)
+ {
+ VERIFY(true);
+ }
+}
+
+template<typename T, typename _CharT>
+void verify(const T& t, std::basic_string_view<_CharT> str)
+{
+ std::basic_string<_CharT> res;
+
+ res = std::format(WIDEN("{}"), t);
+ VERIFY( res == str );
+
+ std::basic_stringstream<_CharT> os;
+ os << t;
+ res = std::move(os).str();
+ VERIFY( res == str );
+}
+
+template<typename T, typename CharT>
+void verify(const T& t, const CharT* str)
+{ verify(t, std::basic_string_view<CharT>(str)); }
+
+template<typename _CharT>
+void
+test_padding()
+{
+ std::basic_string<_CharT> res;
+
+ res = std::format(WIDEN("{:5}"), day(2));
+ VERIFY( res == WIDEN("02 ") );
+
+ res = std::format(WIDEN("{:>6}"), weekday(4));
+ VERIFY( res == WIDEN(" Thu") );
+
+ res = std::format(WIDEN("{:^7}"), month(3));
+ VERIFY( res == WIDEN(" Mar ") );
+
+ res = std::format(WIDEN("{:-<4}"), day(30));
+ VERIFY( res == WIDEN("30--") );
+
+ res = std::format(WIDEN("{:+>30}"), weekday(9));
+ VERIFY( res == WIDEN("++++++9 is not a valid weekday") );
+
+ res = std::format(WIDEN("{:=^27}"), month(16));
+ VERIFY( res == WIDEN("==16 is not a valid month==") );
+}
+
+template<typename Ret = void>
+struct Rep
+{
+ using Return
+ = std::conditional_t<std::is_void_v<Ret>, Rep, Ret>;
+
+ Rep(long v = 0) : val(v) {}
+
+ operator long() 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 <<]"); }
+
+ long val;
+};
+
+template<typename Ret, typename Other>
+ requires std::is_integral_v<Other>
+struct std::common_type<Rep<Ret>, Other>
+{
+ using type = Rep<Ret>;
+};
+
+template<typename Ret, typename Other>
+ requires std::is_integral_v<Other>
+struct std::common_type<Other, Rep<Ret>>
+ : std::common_type<Rep<Ret>, Other>
+{ };
+
+template<typename Ret>
+struct std::numeric_limits<Rep<Ret>>
+ : std::numeric_limits<long>
+{ };
+
+template<typename Ret, typename _CharT>
+struct std::formatter<Rep<Ret>, _CharT>
+ : std::formatter<long, _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<long, _CharT>::format(t.val, ctx);
+ return std::ranges::copy(suffix, out).out;
+ }
+};
+
+using deciseconds = duration<seconds::rep, std::deci>;
+
+template<typename _CharT>
+void
+test_duration()
+{
+ std::basic_string<_CharT> res;
+
+ const milliseconds di(40);
+ verify( di, WIDEN("40ms") );
+ res = std::format(WIDEN("{:>6}"), di);
+ VERIFY( res == WIDEN(" 40ms") );
+
+ verify( -di, WIDEN("-40ms") );
+ res = std::format(WIDEN("{:>6}"), -di);
+ VERIFY( res == WIDEN(" -40ms") );
+
+ 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===") );
+}
+
+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_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[via format]") );
+ verify( hms<deciseconds>(asLong),
+ WIDEN("22:24:54.1[via format]") );
+ verify( hms<seconds>(asLong),
+ WIDEN("22:24:54") );
+ verify( hms<milliseconds>(-asLong),
+ WIDEN("-22:24:54.123[via format]") );
+ verify( hms<deciseconds>(-asLong),
+ WIDEN("-22:24:54.1[via format]") );
+ 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[via format]") );
+ verify( hms<deciseconds>(asRep),
+ WIDEN("22:24:54.1[via format]") );
+ verify( hms<seconds>(asLong),
+ WIDEN("22:24:54") );
+ verify( hms<milliseconds>(-asLong),
+ WIDEN("-22:24:54.123[via format]") );
+ verify( hms<deciseconds>(-asLong),
+ WIDEN("-22:24:54.1[via format]") );
+ verify( hms<seconds>(-asLong),
+ WIDEN("-22:24:54") );
+}
+
+template<typename CharT>
+void
+test_durations()
+{
+ test_duration<CharT>();
+ test_duration_cust<CharT>();
+
+ test_hh_mm_ss<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,
+ // Should be -0100-14-01
+ WIDEN("-100-14-01 is not a valid date") );
+ verify( year(2025)/month(11)/100,
+ // Should be 2025-11-100 ?
+ WIDEN("2025-11-99 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,
+ // Should be 32768-212-10?
+ WIDEN("-32768-84-10 is not a valid date") );
+ verify( year(-32768)/month(2)/105,
+ // Should be 32768-02-99?
+ WIDEN("-32768-02-99 is not a valid date") );
+ verify( year(-32768)/month(14)/55,
+ WIDEN("-32768-14-55 is not a valid date") );
+}
+
+template<typename _CharT>
+void
+test_year_month_last()
+{
+ verify( year(2024)/month(1)/last,
+ WIDEN("2024/Jan/last") );
+ verify( year(2025)/month(14)/last,
+ WIDEN("2025/14 is not a valid month/last") );
+ verify( year(-32768)/month(2)/last,
+ WIDEN("-32768 is not a valid year/Feb/last") );
+ verify( year(-32768)/month(0)/last,
+ WIDEN("-32768 is not a valid year/0 is not a valid month/last") );
+}
+
+template<typename _CharT>
+void
+test_year_month_weekday()
+{
+ verify( year(2024)/month(1)/weekday(2)[1],
+ WIDEN("2024/Jan/Tue[1]") );
+ verify( year(-1)/month(3)/weekday(9)[2],
+ WIDEN("-0001/Mar/9 is not a valid weekday[2]") );
+ verify( year(-32768)/month(13)/weekday(1)[7],
+ WIDEN("-32768 is not a valid year/13 is not a valid month/Mon[7 is not a valid index]") );
+ verify( year(-100)/month(13)/weekday(10)[3],
+ WIDEN("-0100/13 is not a valid month/10 is not a valid weekday[3]") );
+ verify( year(-32768)/month(13)/weekday(130)[0],
+ WIDEN("-32768 is not a valid year/13 is not a valid month/130 is not a valid weekday[0 is not a valid index]") );
+}
+
+template<typename _CharT>
+void
+test_year_month_weekday_last()
+{
+ verify( year(2024)/month(1)/weekday(2)[last],
+ WIDEN("2024/Jan/Tue[last]") );
+ verify( year(-1)/month(3)/weekday(9)[last],
+ WIDEN("-0001/Mar/9 is not a valid weekday[last]") );
+ verify( year(-32768)/month(13)/weekday(1)[last],
+ WIDEN("-32768 is not a valid year/13 is not a valid month/Mon[last]") );
+ verify( year(-100)/month(13)/weekday(10)[last],
+ WIDEN("-0100/13 is not a valid month/10 is not a valid weekday[last]") );
+ verify( year(-32768)/month(13)/weekday(130)[last],
+ WIDEN("-32768 is not a valid year/13 is not a valid month/130 is not a valid weekday[last]") );
+}
+
+template<typename CharT>
+void
+test_calendar()
+{
+ test_day<CharT>();
+ test_month<CharT>();
+ test_year<CharT>();
+
+ test_weekday<CharT>();
+ test_weekday_indexed<CharT>();
+ test_weekday_last<CharT>();
+
+ test_month_day<CharT>();
+ test_month_day_last<CharT>();
+ test_month_weekday<CharT>();
+ test_month_weekday_last<CharT>();
+
+ test_year_month<CharT>();
+ test_year_month_day<CharT>();
+ test_year_month_last<CharT>();
+ test_year_month_weekday<CharT>();
+ test_year_month_weekday_last<CharT>();
+}
+
+template<typename Clock, typename Dur, typename Dur2>
+constexpr auto
+wall_cast(const local_time<Dur2>& tp)
+{
+ using TP = time_point<Clock, std::common_type_t<Dur, days>>;
+ if constexpr (std::is_same_v<Clock, utc_clock> || std::is_same_v<Clock, file_clock>)
+ return clock_cast<Clock>(wall_cast<system_clock, Dur>(tp));
+ else if constexpr (std::is_same_v<Clock, tai_clock>)
+ return TP(floor<Dur>(tp.time_since_epoch()) + days(4383));
+ else if constexpr (std::is_same_v<Clock, gps_clock>)
+ return TP(floor<Dur>(tp.time_since_epoch()) - days(3657));
+ else // system_clock, local_t
+ return time_point<Clock, Dur>(floor<Dur>(tp.time_since_epoch()));
+}
+
+using decadays = duration<days::rep, std::ratio_multiply<std::deca, days::period>>;
+using kilodays = duration<days::rep, std::ratio_multiply<std::kilo, days::period>>;
+
+template<typename _CharT, typename Clock>
+void
+test_time_point(bool daysAsTime)
+{
+ std::basic_string<_CharT> res;
+
+ const auto lt = local_days(2024y/March/22) + 13h + 24min + 54s + 111222333ns;
+ auto strip_time = [daysAsTime](std::basic_string_view<_CharT> sv)
+ { return daysAsTime ? sv : sv.substr(0, 10); };
+
+ verify( wall_cast<Clock, nanoseconds>(lt),
+ WIDEN("2024-03-22 13:24:54.111222333") );
+ verify( wall_cast<Clock, microseconds>(lt),
+ WIDEN("2024-03-22 13:24:54.111222") );
+ verify( wall_cast<Clock, milliseconds>(lt),
+ WIDEN("2024-03-22 13:24:54.111") );
+ verify( wall_cast<Clock, seconds>(lt),
+ WIDEN("2024-03-22 13:24:54") );
+ verify( wall_cast<Clock, minutes>(lt),
+ WIDEN("2024-03-22 13:24:00") );
+ verify( wall_cast<Clock, hours>(lt),
+ WIDEN("2024-03-22 13:00:00") );
+ verify( wall_cast<Clock, days>(lt),
+ strip_time(WIDEN("2024-03-22 00:00:00")) );
+ verify( wall_cast<Clock, decadays>(lt),
+ strip_time(WIDEN("2024-03-18 00:00:00")) );
+ verify( wall_cast<Clock, kilodays>(lt),
+ strip_time(WIDEN("2022-01-08 00:00:00")) );
+}
+
+template<typename _CharT>
+void
+test_leap_second()
+{
+ std::basic_string<_CharT> res;
+
+ const auto st = sys_days(2012y/June/30) + 23h + 59min + 59s + 111222333ns;
+ auto tp = clock_cast<utc_clock>(st);
+ tp += 1s;
+
+ verify( floor<nanoseconds>(tp),
+ WIDEN("2012-06-30 23:59:60.111222333") );
+ verify( floor<microseconds>(tp),
+ WIDEN("2012-06-30 23:59:60.111222") );
+ verify( floor<milliseconds>(tp),
+ WIDEN("2012-06-30 23:59:60.111") );
+ verify( floor<seconds>(tp),
+ WIDEN("2012-06-30 23:59:60") );
+}
+
+#if _GLIBCXX_USE_CXX11_ABI
+template<typename Dur, typename Dur2>
+auto
+make_zoned(const sys_time<Dur2>& st, const time_zone* tz)
+{ return zoned_time<Dur>(tz, floor<Dur>(st)); }
+
+template<typename _CharT>
+void
+test_zoned_time()
+{
+ const auto st = sys_days(2024y/March/22) + 13h + 24min + 54s + 111222333ns;
+ const time_zone* tz = locate_zone("Europe/Sofia");
+ VERIFY( tz != nullptr );
+
+ verify( make_zoned<nanoseconds>(st, tz),
+ WIDEN("2024-03-22 15:24:54.111222333 EET") );
+ verify( make_zoned<microseconds>(st, tz),
+ WIDEN("2024-03-22 15:24:54.111222 EET") );
+ verify( make_zoned<milliseconds>(st, tz),
+ WIDEN("2024-03-22 15:24:54.111 EET") );
+ verify( make_zoned<seconds>(st, tz),
+ WIDEN("2024-03-22 15:24:54 EET") );
+ verify( make_zoned<minutes>(st, tz),
+ WIDEN("2024-03-22 15:24:00 EET") );
+ verify( make_zoned<hours>(st, tz),
+ WIDEN("2024-03-22 15:00:00 EET") );
+ verify( make_zoned<days>(st, tz),
+ WIDEN("2024-03-22 02:00:00 EET") );
+ verify( make_zoned<decadays>(st, tz),
+ WIDEN("2024-03-18 02:00:00 EET") );
+ verify( make_zoned<kilodays>(st, tz),
+ WIDEN("2022-01-08 02:00:00 EET") );
+}
+#endif
+
+template<typename Dur, typename Dur2>
+auto
+local_fmt(const local_time<Dur2>& lt, std::string* zone)
+{ return local_time_format(floor<Dur>(lt), zone); }
+
+template<typename _CharT>
+void
+test_local_time_format()
+{
+ std::basic_string<_CharT> res;
+
+ std::string abbrev = "Zone";
+ const auto lt = local_days(2024y/March/22) + 13h + 24min + 54s + 111222333ns;
+
+ res = std::format(WIDEN("{}"), local_fmt<nanoseconds>(lt, &abbrev));
+ VERIFY( res == WIDEN("2024-03-22 13:24:54.111222333 Zone") );
+ res = std::format(WIDEN("{}"), local_fmt<microseconds>(lt, &abbrev));
+ VERIFY( res == WIDEN("2024-03-22 13:24:54.111222 Zone") );
+ res = std::format(WIDEN("{}"), local_fmt<milliseconds>(lt, &abbrev));
+ VERIFY( res == WIDEN("2024-03-22 13:24:54.111 Zone") );
+ res = std::format(WIDEN("{}"), local_fmt<seconds>(lt, &abbrev));
+ VERIFY( res == WIDEN("2024-03-22 13:24:54 Zone") );
+ res = std::format(WIDEN("{}"), local_fmt<minutes>(lt, &abbrev));
+ VERIFY( res == WIDEN("2024-03-22 13:24:00 Zone") );
+ res = std::format(WIDEN("{}"), local_fmt<hours>(lt, &abbrev));
+ VERIFY( res == WIDEN("2024-03-22 13:00:00 Zone") );
+ res = std::format(WIDEN("{}"), local_fmt<days>(lt, &abbrev));
+ VERIFY( res == WIDEN("2024-03-22 00:00:00 Zone") );
+ res = std::format(WIDEN("{}"), local_fmt<decadays>(lt, &abbrev));
+ VERIFY( res == WIDEN("2024-03-18 00:00:00 Zone") );
+ res = std::format(WIDEN("{}"), local_fmt<kilodays>(lt, &abbrev));
+ VERIFY( res == WIDEN("2022-01-08 00:00:00 Zone") );
+}
+
+template<typename CharT>
+void
+test_time_points()
+{
+ test_time_point<CharT, local_t>(false);
+ test_time_point<CharT, system_clock>(false);
+ test_time_point<CharT, utc_clock>(true);
+ test_time_point<CharT, tai_clock>(true);
+ test_time_point<CharT, gps_clock>(true);
+ test_time_point<CharT, file_clock>(true);
+ test_leap_second<CharT>();
+#if _GLIBCXX_USE_CXX11_ABI
+ test_zoned_time<CharT>();
+#endif
+ test_local_time_format<CharT>();
+
+ test_no_empty_spec<CharT, sys_time<years>>();
+ test_no_empty_spec<CharT, sys_time<duration<float>>>();
+}
+
+template<typename CharT>
+void
+test_all()
+{
+ test_padding<CharT>();
+ test_durations<CharT>();
+ test_calendar<CharT>();
+ test_time_points<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/util/testsuite_abi.cc b/libstdc++-v3/testsuite/util/testsuite_abi.cc
index 90cda2f..7bffc6b 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");