aboutsummaryrefslogtreecommitdiff
path: root/libstdc++-v3
diff options
context:
space:
mode:
Diffstat (limited to 'libstdc++-v3')
-rw-r--r--libstdc++-v3/ChangeLog51
-rw-r--r--libstdc++-v3/acinclude.m46
-rwxr-xr-xlibstdc++-v3/configure20
-rw-r--r--libstdc++-v3/doc/doxygen/user.cfg.in1
-rw-r--r--libstdc++-v3/include/Makefile.am1
-rw-r--r--libstdc++-v3/include/Makefile.in1
-rw-r--r--libstdc++-v3/include/bits/chrono_io.h9
-rw-r--r--libstdc++-v3/include/bits/version.def9
-rw-r--r--libstdc++-v3/include/bits/version.h9
-rw-r--r--libstdc++-v3/include/precompiled/stdc++.h1
-rw-r--r--libstdc++-v3/include/std/mdspan309
-rw-r--r--libstdc++-v3/src/c++23/std.cc.in10
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/extents/class_mandates_neg.cc8
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy.cc82
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints.cc62
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape.cc160
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/extents/custom_integer.cc87
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/extents/misc.cc224
-rw-r--r--libstdc++-v3/testsuite/std/time/format/pr120114.cc125
19 files changed, 1166 insertions, 9 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index 8aa7ec8..b7cce6d 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -1,3 +1,54 @@
+2025-05-07 Jonathan Wakely <jwakely@redhat.com>
+
+ PR libstdc++/120159
+ * src/c++23/std.cc.in (is_layout_compatible_v): Export.
+
+2025-05-07 Jonathan Wakely <jwakely@redhat.com>
+
+ * src/c++23/std.cc.in: Fix export for std::extents.
+
+2025-05-07 Luc Grosheintz <luc.grosheintz@gmail.com>
+
+ * testsuite/23_containers/mdspan/extents/class_mandates_neg.cc: New test.
+ * testsuite/23_containers/mdspan/extents/ctor_copy.cc: New test.
+ * testsuite/23_containers/mdspan/extents/ctor_ints.cc: New test.
+ * testsuite/23_containers/mdspan/extents/ctor_shape.cc: New test.
+ * testsuite/23_containers/mdspan/extents/custom_integer.cc: New test.
+ * testsuite/23_containers/mdspan/extents/misc.cc: New test.
+
+2025-05-07 Luc Grosheintz <luc.grosheintz@gmail.com>
+
+ PR libstdc++/107761
+ * include/std/mdspan (extents): New class.
+ * src/c++23/std.cc.in: Add 'using std::extents'.
+
+2025-05-07 Luc Grosheintz <luc.grosheintz@gmail.com>
+
+ * doc/doxygen/user.cfg.in: Add <mdspan>.
+ * include/Makefile.am: Ditto.
+ * include/Makefile.in: Ditto.
+ * include/precompiled/stdc++.h: Ditto.
+ * include/std/mdspan: New file.
+
+2025-05-07 Luc Grosheintz <luc.grosheintz@gmail.com>
+
+ * include/bits/version.def: Add internal feature testing macro
+ __glibcxx_mdspan.
+ * include/bits/version.h: Regenerate.
+
+2025-05-07 Tomasz KamiƄski <tkaminsk@redhat.com>
+
+ PR libstdc++/120114
+ * include/bits/chrono_io.h (__formatter_chrono::_M_format): Use __field_width.
+ * testsuite/std/time/format/pr120114.cc: New test.
+
+2025-05-07 Jonathan Wakely <jwakely@redhat.com>
+
+ PR libstdc++/120147
+ * acinclude.m4 (GLIBCXX_ENABLE_BACKTRACE): Restore use of
+ AC_LANG_CPLUSPLUS.
+ * configure: Regenerate.
+
2025-05-06 Jonathan Wakely <jwakely@redhat.com>
PR libstdc++/70560
diff --git a/libstdc++-v3/acinclude.m4 b/libstdc++-v3/acinclude.m4
index 0fc74d0..204bed5b 100644
--- a/libstdc++-v3/acinclude.m4
+++ b/libstdc++-v3/acinclude.m4
@@ -5290,7 +5290,8 @@ AC_DEFUN([GLIBCXX_ENABLE_BACKTRACE], [
BACKTRACE_CPPFLAGS="-D_GNU_SOURCE"
- GLIBCXX_LANG_PUSH
+ AC_LANG_CPLUSPLUS
+ old_CXXFLAGS="$CXXFLAGS"
# libbacktrace's own configure.ac only tests atomics for int,
# but the code actually uses atomics for size_t and pointers as well.
@@ -5356,7 +5357,8 @@ EOF
rm -f conftest*
fi
- GLIBCXX_LANG_POP
+ CXXFLAGS="$old_CXXFLAGS"
+ AC_LANG_RESTORE
if test "$glibcxx_cv_libbacktrace_atomics" = yes; then
BACKTRACE_CPPFLAGS="$BACKTRACE_CPPFLAGS -DHAVE_ATOMIC_FUNCTIONS=1"
diff --git a/libstdc++-v3/configure b/libstdc++-v3/configure
index 3fd03b8..0529ff5 100755
--- a/libstdc++-v3/configure
+++ b/libstdc++-v3/configure
@@ -53537,7 +53537,13 @@ fi
BACKTRACE_CPPFLAGS="-D_GNU_SOURCE"
- GLIBCXX_LANG_PUSH
+ ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+ old_CXXFLAGS="$CXXFLAGS"
# libbacktrace's own configure.ac only tests atomics for int,
# but the code actually uses atomics for size_t and pointers as well.
@@ -53578,7 +53584,7 @@ main ()
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_cxx_try_link "$LINENO"; then :
glibcxx_cv_libbacktrace_atomics=yes
else
glibcxx_cv_libbacktrace_atomics=no
@@ -53595,7 +53601,7 @@ $as_echo "$glibcxx_cv_libbacktrace_atomics" >&6; }
CXXFLAGS='-O0 -S'
cat > conftest.$ac_ext << EOF
-#line 53598 "configure"
+#line 53604 "configure"
#include <stddef.h>
int main()
{
@@ -53633,7 +53639,13 @@ $as_echo "$glibcxx_cv_libbacktrace_atomics" >&6; }
rm -f conftest*
fi
- GLIBCXX_LANG_POP
+ CXXFLAGS="$old_CXXFLAGS"
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
if test "$glibcxx_cv_libbacktrace_atomics" = yes; then
BACKTRACE_CPPFLAGS="$BACKTRACE_CPPFLAGS -DHAVE_ATOMIC_FUNCTIONS=1"
diff --git a/libstdc++-v3/doc/doxygen/user.cfg.in b/libstdc++-v3/doc/doxygen/user.cfg.in
index 19ae67a..e926c67 100644
--- a/libstdc++-v3/doc/doxygen/user.cfg.in
+++ b/libstdc++-v3/doc/doxygen/user.cfg.in
@@ -880,6 +880,7 @@ INPUT = @srcdir@/doc/doxygen/doxygroups.cc \
include/list \
include/locale \
include/map \
+ include/mdspan \
include/memory \
include/memory_resource \
include/mutex \
diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index 537774c..1140fa0 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -38,6 +38,7 @@ std_freestanding = \
${std_srcdir}/generator \
${std_srcdir}/iterator \
${std_srcdir}/limits \
+ ${std_srcdir}/mdspan \
${std_srcdir}/memory \
${std_srcdir}/numbers \
${std_srcdir}/numeric \
diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in
index 7b96b22..c96e981 100644
--- a/libstdc++-v3/include/Makefile.in
+++ b/libstdc++-v3/include/Makefile.in
@@ -396,6 +396,7 @@ std_freestanding = \
${std_srcdir}/generator \
${std_srcdir}/iterator \
${std_srcdir}/limits \
+ ${std_srcdir}/mdspan \
${std_srcdir}/memory \
${std_srcdir}/numbers \
${std_srcdir}/numeric \
diff --git a/libstdc++-v3/include/bits/chrono_io.h b/libstdc++-v3/include/bits/chrono_io.h
index b7f6f5f..620227a 100644
--- a/libstdc++-v3/include/bits/chrono_io.h
+++ b/libstdc++-v3/include/bits/chrono_io.h
@@ -705,8 +705,13 @@ namespace __format
if (__write_direct)
return __out;
- auto __str = std::move(__sink).get();
- return __format::__write_padded_as_spec(__str, __str.size(),
+ auto __str = __sink.view();
+ size_t __width;
+ if constexpr (__unicode::__literal_encoding_is_unicode<_CharT>())
+ __width = __unicode::__field_width(__str);
+ else
+ __width = __str.size();
+ return __format::__write_padded_as_spec(__str, __width,
__fc, _M_spec);
}
diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def
index 282667e..f4d3de8 100644
--- a/libstdc++-v3/include/bits/version.def
+++ b/libstdc++-v3/include/bits/version.def
@@ -1000,6 +1000,15 @@ ftms = {
};
ftms = {
+ name = mdspan;
+ no_stdname = true; // FIXME: remove
+ values = {
+ v = 1; // FIXME: 202207
+ cxxmin = 23;
+ };
+};
+
+ftms = {
name = ssize;
values = {
v = 201902;
diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h
index bb7c047..d5d75ce 100644
--- a/libstdc++-v3/include/bits/version.h
+++ b/libstdc++-v3/include/bits/version.h
@@ -1114,6 +1114,15 @@
#endif /* !defined(__cpp_lib_span) && defined(__glibcxx_want_span) */
#undef __glibcxx_want_span
+#if !defined(__cpp_lib_mdspan)
+# if (__cplusplus >= 202100L)
+# define __glibcxx_mdspan 1L
+# if defined(__glibcxx_want_all) || defined(__glibcxx_want_mdspan)
+# endif
+# endif
+#endif /* !defined(__cpp_lib_mdspan) && defined(__glibcxx_want_mdspan) */
+#undef __glibcxx_want_mdspan
+
#if !defined(__cpp_lib_ssize)
# if (__cplusplus >= 202002L)
# define __glibcxx_ssize 201902L
diff --git a/libstdc++-v3/include/precompiled/stdc++.h b/libstdc++-v3/include/precompiled/stdc++.h
index f4b312d..e7d89c9 100644
--- a/libstdc++-v3/include/precompiled/stdc++.h
+++ b/libstdc++-v3/include/precompiled/stdc++.h
@@ -228,6 +228,7 @@
#include <flat_map>
#include <flat_set>
#include <generator>
+#include <mdspan>
#include <print>
#include <spanstream>
#include <stacktrace>
diff --git a/libstdc++-v3/include/std/mdspan b/libstdc++-v3/include/std/mdspan
new file mode 100644
index 0000000..aee96dd
--- /dev/null
+++ b/libstdc++-v3/include/std/mdspan
@@ -0,0 +1,309 @@
+// <mdspan> -*- C++ -*-
+
+// Copyright The GNU Toolchain Authors.
+//
+// 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.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file mdspan
+ * This is a Standard C++ Library header.
+ */
+
+#ifndef _GLIBCXX_MDSPAN
+#define _GLIBCXX_MDSPAN 1
+
+#ifdef _GLIBCXX_SYSHDR
+#pragma GCC system_header
+#endif
+
+#include <span>
+#include <array>
+#include <type_traits>
+#include <limits>
+#include <utility>
+
+#define __glibcxx_want_mdspan
+#include <bits/version.h>
+
+#ifdef __glibcxx_mdspan
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+ namespace __mdspan
+ {
+ template<typename _IndexType, array _Extents>
+ class _ExtentsStorage
+ {
+ public:
+ static consteval bool
+ _S_is_dyn(size_t __ext) noexcept
+ { return __ext == dynamic_extent; }
+
+ template<typename _OIndexType>
+ static constexpr _IndexType
+ _S_int_cast(const _OIndexType& __other) noexcept
+ { return _IndexType(__other); }
+
+ static constexpr size_t _S_rank = _Extents.size();
+
+ // For __r in [0, _S_rank], _S_dynamic_index[__r] is the number
+ // of dynamic extents up to (and not including) __r.
+ //
+ // If __r is the index of a dynamic extent, then
+ // _S_dynamic_index[__r] is the index of that extent in
+ // _M_dynamic_extents.
+ static constexpr auto _S_dynamic_index = [] consteval
+ {
+ array<size_t, _S_rank+1> __ret;
+ size_t __dyn = 0;
+ for(size_t __i = 0; __i < _S_rank; ++__i)
+ {
+ __ret[__i] = __dyn;
+ __dyn += _S_is_dyn(_Extents[__i]);
+ }
+ __ret[_S_rank] = __dyn;
+ return __ret;
+ }();
+
+ static constexpr size_t _S_rank_dynamic = _S_dynamic_index[_S_rank];
+
+ // For __r in [0, _S_rank_dynamic), _S_dynamic_index_inv[__r] is the
+ // index of the __r-th dynamic extent in _Extents.
+ static constexpr auto _S_dynamic_index_inv = [] consteval
+ {
+ array<size_t, _S_rank_dynamic> __ret;
+ for (size_t __i = 0, __r = 0; __i < _S_rank; ++__i)
+ if (_S_is_dyn(_Extents[__i]))
+ __ret[__r++] = __i;
+ return __ret;
+ }();
+
+ static constexpr size_t
+ _S_static_extent(size_t __r) noexcept
+ { return _Extents[__r]; }
+
+ constexpr _IndexType
+ _M_extent(size_t __r) const noexcept
+ {
+ auto __se = _Extents[__r];
+ if (__se == dynamic_extent)
+ return _M_dynamic_extents[_S_dynamic_index[__r]];
+ else
+ return __se;
+ }
+
+ template<size_t _OtherRank, typename _GetOtherExtent>
+ constexpr void
+ _M_init_dynamic_extents(_GetOtherExtent __get_extent) noexcept
+ {
+ for(size_t __i = 0; __i < _S_rank_dynamic; ++__i)
+ {
+ size_t __di = __i;
+ if constexpr (_OtherRank != _S_rank_dynamic)
+ __di = _S_dynamic_index_inv[__i];
+ _M_dynamic_extents[__i] = _S_int_cast(__get_extent(__di));
+ }
+ }
+
+ constexpr
+ _ExtentsStorage() noexcept = default;
+
+ template<typename _OIndexType, array _OExtents>
+ constexpr
+ _ExtentsStorage(const _ExtentsStorage<_OIndexType, _OExtents>&
+ __other) noexcept
+ {
+ _M_init_dynamic_extents<_S_rank>([&__other](size_t __i)
+ { return __other._M_extent(__i); });
+ }
+
+ template<typename _OIndexType, size_t _Nm>
+ constexpr
+ _ExtentsStorage(span<const _OIndexType, _Nm> __exts) noexcept
+ {
+ _M_init_dynamic_extents<_Nm>(
+ [&__exts](size_t __i) -> const _OIndexType&
+ { return __exts[__i]; });
+ }
+
+ private:
+ using _S_storage = __array_traits<_IndexType, _S_rank_dynamic>::_Type;
+ [[no_unique_address]] _S_storage _M_dynamic_extents;
+ };
+
+ template<typename _OIndexType, typename _SIndexType>
+ concept __valid_index_type =
+ is_convertible_v<_OIndexType, _SIndexType> &&
+ is_nothrow_constructible_v<_SIndexType, _OIndexType>;
+
+ template<size_t _Extent, typename _IndexType>
+ concept
+ __valid_static_extent = _Extent == dynamic_extent
+ || _Extent <= numeric_limits<_IndexType>::max();
+ }
+
+ template<typename _IndexType, size_t... _Extents>
+ class extents
+ {
+ static_assert(is_integral_v<_IndexType>, "_IndexType must be integral.");
+ static_assert(
+ (__mdspan::__valid_static_extent<_Extents, _IndexType> && ...),
+ "Extents must either be dynamic or representable as _IndexType");
+
+ public:
+ using index_type = _IndexType;
+ using size_type = make_unsigned_t<index_type>;
+ using rank_type = size_t;
+
+ static constexpr rank_type
+ rank() noexcept { return _S_storage::_S_rank; }
+
+ static constexpr rank_type
+ rank_dynamic() noexcept { return _S_storage::_S_rank_dynamic; }
+
+ static constexpr size_t
+ static_extent(rank_type __r) noexcept
+ {
+ __glibcxx_assert(__r < rank());
+ if constexpr (rank() == 0)
+ __builtin_trap();
+ else
+ return _S_storage::_S_static_extent(__r);
+ }
+
+ constexpr index_type
+ extent(rank_type __r) const noexcept
+ {
+ __glibcxx_assert(__r < rank());
+ if constexpr (rank() == 0)
+ __builtin_trap();
+ else
+ return _M_dynamic_extents._M_extent(__r);
+ }
+
+ constexpr
+ extents() noexcept = default;
+
+ private:
+ static consteval bool
+ _S_is_less_dynamic(size_t __ext, size_t __oext)
+ { return (__ext != dynamic_extent) && (__oext == dynamic_extent); }
+
+ template<typename _OIndexType, size_t... _OExtents>
+ static consteval bool
+ _S_ctor_explicit()
+ {
+ return (_S_is_less_dynamic(_Extents, _OExtents) || ...)
+ || (numeric_limits<index_type>::max()
+ < numeric_limits<_OIndexType>::max());
+ }
+
+ template<size_t... _OExtents>
+ static consteval bool
+ _S_is_compatible_extents()
+ {
+ if constexpr (sizeof...(_OExtents) != rank())
+ return false;
+ else
+ return ((_OExtents == dynamic_extent || _Extents == dynamic_extent
+ || _OExtents == _Extents) && ...);
+ }
+
+ public:
+ template<typename _OIndexType, size_t... _OExtents>
+ requires (_S_is_compatible_extents<_OExtents...>())
+ constexpr explicit(_S_ctor_explicit<_OIndexType, _OExtents...>())
+ extents(const extents<_OIndexType, _OExtents...>& __other) noexcept
+ : _M_dynamic_extents(__other._M_dynamic_extents)
+ { }
+
+ template<__mdspan::__valid_index_type<index_type>... _OIndexTypes>
+ requires (sizeof...(_OIndexTypes) == rank()
+ || sizeof...(_OIndexTypes) == rank_dynamic())
+ constexpr explicit extents(_OIndexTypes... __exts) noexcept
+ : _M_dynamic_extents(span<const _IndexType, sizeof...(_OIndexTypes)>(
+ initializer_list{_S_storage::_S_int_cast(__exts)...}))
+ { }
+
+ template<__mdspan::__valid_index_type<index_type> _OIndexType, size_t _Nm>
+ requires (_Nm == rank() || _Nm == rank_dynamic())
+ constexpr explicit(_Nm != rank_dynamic())
+ extents(span<_OIndexType, _Nm> __exts) noexcept
+ : _M_dynamic_extents(span<const _OIndexType, _Nm>(__exts))
+ { }
+
+
+ template<__mdspan::__valid_index_type<index_type> _OIndexType, size_t _Nm>
+ requires (_Nm == rank() || _Nm == rank_dynamic())
+ constexpr explicit(_Nm != rank_dynamic())
+ extents(const array<_OIndexType, _Nm>& __exts) noexcept
+ : _M_dynamic_extents(span<const _OIndexType, _Nm>(__exts))
+ { }
+
+ template<typename _OIndexType, size_t... _OExtents>
+ friend constexpr bool
+ operator==(const extents& __self,
+ const extents<_OIndexType, _OExtents...>& __other) noexcept
+ {
+ if constexpr (!_S_is_compatible_extents<_OExtents...>())
+ return false;
+ else
+ {
+ for (size_t __i = 0; __i < __self.rank(); ++__i)
+ if (!cmp_equal(__self.extent(__i), __other.extent(__i)))
+ return false;
+ return true;
+ }
+ }
+
+ private:
+ using _S_storage = __mdspan::_ExtentsStorage<
+ _IndexType, array<size_t, sizeof...(_Extents)>{_Extents...}>;
+ [[no_unique_address]] _S_storage _M_dynamic_extents;
+
+ template<typename _OIndexType, size_t... _OExtents>
+ friend class extents;
+ };
+
+ namespace __mdspan
+ {
+ template<typename _IndexType, size_t... _Counts>
+ auto __build_dextents_type(integer_sequence<size_t, _Counts...>)
+ -> extents<_IndexType, ((void) _Counts, dynamic_extent)...>;
+
+ template<typename _Tp>
+ consteval size_t
+ __dynamic_extent() { return dynamic_extent; }
+ }
+
+ template<typename _IndexType, size_t _Rank>
+ using dextents = decltype(__mdspan::__build_dextents_type<_IndexType>(
+ make_index_sequence<_Rank>()));
+
+ template<typename... _Integrals>
+ requires (is_convertible_v<_Integrals, size_t> && ...)
+ explicit extents(_Integrals...) ->
+ extents<size_t, __mdspan::__dynamic_extent<_Integrals>()...>;
+
+_GLIBCXX_END_NAMESPACE_VERSION
+}
+#endif
+#endif
diff --git a/libstdc++-v3/src/c++23/std.cc.in b/libstdc++-v3/src/c++23/std.cc.in
index 930a489..d45ae63 100644
--- a/libstdc++-v3/src/c++23/std.cc.in
+++ b/libstdc++-v3/src/c++23/std.cc.in
@@ -1833,7 +1833,14 @@ export namespace std
}
}
-// FIXME <mdspan>
+// <mdspan>
+#if __glibcxx_mdspan
+export namespace std
+{
+ using std::extents;
+ // FIXME layout_*, default_accessor and mdspan
+}
+#endif
// 20.2 <memory>
export namespace std
@@ -3107,6 +3114,7 @@ export namespace std
#if __cpp_lib_is_layout_compatible
using std::is_corresponding_member;
using std::is_layout_compatible;
+ using std::is_layout_compatible_v;
#endif
#if __cpp_lib_is_pointer_interconvertible
using std::is_pointer_interconvertible_base_of;
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/extents/class_mandates_neg.cc b/libstdc++-v3/testsuite/23_containers/mdspan/extents/class_mandates_neg.cc
new file mode 100644
index 0000000..b654e39
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/class_mandates_neg.cc
@@ -0,0 +1,8 @@
+// { dg-do compile { target c++23 } }
+#include<mdspan>
+
+std::extents<char, size_t(1) << 9> e1; // { dg-error "from here" }
+std::extents<double, 1> e2; // { dg-error "from here" }
+// { dg-prune-output "dynamic or representable as _IndexType" }
+// { dg-prune-output "must be integral" }
+// { dg-prune-output "invalid use of incomplete type" }
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy.cc b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy.cc
new file mode 100644
index 0000000..a7b3a169
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy.cc
@@ -0,0 +1,82 @@
+// { dg-do run { target c++23 } }
+#include <mdspan>
+
+#include <testsuite_hooks.h>
+
+// Test the copy ctor and the ctor from other extents.
+
+constexpr auto dyn = std::dynamic_extent;
+
+// Not constructible
+static_assert(!std::is_constructible_v<std::extents<int>,
+ std::extents<int, 1>>);
+
+static_assert(!std::is_constructible_v<std::extents<int, 1, 1>,
+ std::extents<int, 1>>);
+
+static_assert(!std::is_constructible_v<std::extents<int, dyn>,
+ std::extents<int, dyn, dyn>>);
+
+static_assert(!std::is_constructible_v<std::extents<int, 2, 2>,
+ std::extents<int, 1, 2>>);
+
+// Nothrow constructible
+static_assert(std::is_nothrow_constructible_v<std::extents<int, 1>,
+ std::extents<unsigned int, dyn>>);
+static_assert(std::is_nothrow_constructible_v<std::extents<unsigned int, dyn>,
+ std::extents<int, 1>>);
+
+// Implicit conversion
+static_assert(!std::is_convertible_v<std::extents<unsigned int>,
+ std::extents<int>>);
+static_assert(std::is_convertible_v<std::extents<int>,
+ std::extents<unsigned int>>);
+
+static_assert(!std::is_convertible_v<std::extents<unsigned int, 1>,
+ std::extents<int, 1>>);
+static_assert(std::is_convertible_v<std::extents<int, 1>,
+ std::extents<unsigned int, 1>>);
+
+static_assert(!std::is_convertible_v<std::extents<int, dyn>,
+ std::extents<int, 1>>);
+static_assert(std::is_convertible_v<std::extents<int, 1>,
+ std::extents<int, dyn>>);
+
+static_assert(!std::is_convertible_v<std::extents<unsigned int, 1>,
+ std::extents<int, dyn>>);
+static_assert(std::is_convertible_v<std::extents<int, 1>,
+ std::extents<unsigned int, dyn>>);
+
+template<typename T, size_t... Extents, typename Other>
+ constexpr void
+ test_ctor(const Other& other)
+ {
+ auto e = std::extents<T, Extents...>(other);
+ VERIFY(e == other);
+ }
+
+constexpr int
+test_all()
+{
+ auto e0 = std::extents<int>();
+ test_ctor<int>(e0);
+
+ auto e1 = std::extents<int, 1, 2, 3>();
+ test_ctor<int, 1, 2, 3>(e1);
+ test_ctor<int, 1, dyn, 3>(e1);
+ test_ctor<unsigned int, 1, dyn, 3>(e1);
+
+ auto e2 = std::extents<unsigned int, 1, dyn, 3>{1, 2, 3};
+ test_ctor<int, 1, 2, 3>(e2);
+ test_ctor<int, 1, dyn, 3>(e2);
+ test_ctor<int, 1, dyn, dyn>(e2);
+ return true;
+}
+
+int
+main()
+{
+ test_all();
+ static_assert(test_all());
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints.cc b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints.cc
new file mode 100644
index 0000000..3a70efd
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints.cc
@@ -0,0 +1,62 @@
+// { dg-do run { target c++23 } }
+#include <mdspan>
+
+#include <testsuite_hooks.h>
+
+constexpr auto dyn = std::dynamic_extent;
+
+class A {};
+
+// Not constructible if the number of integer-like arguments isn't either
+// rank() or rank_dynamic().
+static_assert(!std::is_constructible_v<std::extents<int>, int>);
+static_assert(!std::is_constructible_v<std::extents<int, dyn, dyn>, int>);
+static_assert(!std::is_constructible_v<std::extents<int, 1, dyn, 3>, int, int>);
+
+// Not constructible from non integer-like objects.
+static_assert(!std::is_constructible_v<std::extents<int, 1>, int, A>);
+
+// No implicit conversion from integer-like objects.
+template<typename Extent, typename... OExtents>
+ constexpr bool
+ is_explicit()
+ {
+ return std::is_nothrow_constructible_v<Extent, OExtents...>
+ && !std::is_convertible_v<Extent, OExtents...>;
+ }
+
+static_assert(is_explicit<std::extents<int, 1>, int>());
+static_assert(is_explicit<std::extents<int, 1>, unsigned int>());
+static_assert(is_explicit<std::extents<unsigned int, 1>, int>());
+
+constexpr bool
+test_all()
+{
+ auto expected = std::extents<int, 1, 2, 3>(1, 2, 3);
+
+ // From all extents.
+ VERIFY((std::extents<int, 1, 2, 3>(1, 2, 3)) == expected);
+ VERIFY((std::extents<int, dyn, 2, 3>(1, 2, 3)) == expected);
+ VERIFY((std::extents<int, dyn, 2, dyn>(1, 2, 3)) == expected);
+
+ VERIFY((std::extents<int, 1, 2, 3>{1, 2, 3}) == expected);
+ VERIFY((std::extents<int, dyn, 2, 3>{1, 2, 3}) == expected);
+ VERIFY((std::extents<int, dyn, 2, dyn>{1, 2, 3}) == expected);
+
+ // From only dynamic extents.
+ VERIFY((std::extents<int, dyn, 2, 3>(1)) == expected);
+ VERIFY((std::extents<int, dyn, 2, dyn>(1, 3)) == expected);
+
+ VERIFY((std::extents<int, dyn, 2, 3>{1}) == expected);
+ VERIFY((std::extents<int, dyn, 2, dyn>{1, 3}) == expected);
+
+ return true;
+}
+
+int
+main()
+{
+ test_all();
+ static_assert(test_all());
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape.cc b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape.cc
new file mode 100644
index 0000000..01624f2
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape.cc
@@ -0,0 +1,160 @@
+// { dg-do run { target c++23 } }
+#include <mdspan>
+
+#include <testsuite_hooks.h>
+
+constexpr auto dyn = std::dynamic_extent;
+
+template<typename Extent, typename T, size_t N>
+ constexpr bool
+ constructible()
+ {
+ return std::is_nothrow_constructible_v<Extent, std::array<T, N>>
+ && std::is_nothrow_constructible_v<Extent, std::span<T, N>>;
+ }
+
+template<typename Extent, typename T, size_t N>
+ constexpr bool
+ not_constructible()
+ {
+ return !std::is_constructible_v<Extent, std::array<T, N>>
+ && !std::is_constructible_v<Extent, std::span<T, N>>;
+ }
+
+template<typename Extent, typename T, size_t N>
+ constexpr bool
+ convertible()
+ {
+ return std::is_convertible_v<std::array<T, N>, Extent>
+ && std::is_convertible_v<std::span<T, N>, Extent>;
+ }
+
+template<typename Extent, typename T, size_t N>
+ constexpr bool
+ not_convertible()
+ {
+ return !std::is_convertible_v<std::array<T, N>, Extent>
+ && !std::is_convertible_v<std::span<T, N>, Extent>;
+ }
+
+static_assert(constructible<std::extents<int, 1, 2>, int, 2>());
+static_assert(not_constructible<std::extents<int, 1, 2>, int, 1>());
+
+static_assert(constructible<std::extents<int>, int, 0>());
+static_assert(convertible<std::extents<int>, int, 0>());
+static_assert(convertible<std::extents<unsigned int>, int, 0>());
+static_assert(convertible<std::extents<int>, unsigned int, 0>());
+
+static_assert(constructible<std::extents<int, 1, dyn>, int, 1>());
+static_assert(convertible<std::extents<int, 1, dyn>, int, 1>());
+static_assert(convertible<std::extents<unsigned int, 1, dyn>, int, 1>());
+static_assert(convertible<std::extents<int, 1, dyn>, unsigned int, 1>());
+
+static_assert(constructible<std::extents<int, 1, dyn>, int, 2>());
+static_assert(not_convertible<std::extents<int, 1, dyn>, int, 2>());
+static_assert(not_convertible<std::extents<unsigned int, 1, dyn>, int, 2>());
+static_assert(not_convertible<std::extents<int, 1, dyn>, unsigned int, 2>());
+
+// Non-integer, but convertible.
+static_assert(constructible<std::extents<int, dyn>, double, 1>());
+static_assert(convertible<std::extents<int, dyn>, double, 1>());
+
+namespace all_extents
+{
+ template<typename Shape>
+ constexpr void
+ test_ctor(Shape shape)
+ {
+ auto expected = std::extents<int, 1, 2, 3>();
+ VERIFY((std::extents<int, 1, dyn, 3>(shape)) == expected);
+ VERIFY((std::extents<int, dyn, dyn, dyn>(shape)) == expected);
+ VERIFY((std::extents<int, 1, 2, 3>(shape)) == expected);
+ }
+
+ constexpr void
+ test_common_shapes()
+ {
+ auto array = std::array<int, 3>{1, 2, 3};
+ auto span_const = std::span<const int, 3>(array);
+ auto span = std::span<int, 3>(array);
+
+ test_ctor(array);
+ test_ctor(span);
+ test_ctor(span_const);
+ }
+
+ constexpr void
+ test_empty_shapes()
+ {
+ auto shape = std::array<int, 0>();
+ auto span = std::span<int, 0>(shape);
+
+ auto expected = std::extents<int>();
+ VERIFY((std::extents<int>(shape)) == expected);
+ VERIFY((std::extents<int>(span)) == expected);
+ }
+
+ constexpr bool
+ test_all()
+ {
+ test_common_shapes();
+ test_empty_shapes();
+ return true;
+ }
+}
+
+namespace only_dynamic_extents
+{
+ template<typename Extents, typename Shape>
+ constexpr void
+ test_ctor(const Shape& shape)
+ {
+ Extents e = shape;
+
+ VERIFY(e.rank_dynamic() == shape.size());
+
+ size_t di = 0;
+ for(size_t i = 0; i < e.rank(); ++i)
+ if(e.static_extent(i) == dyn)
+ VERIFY(e.extent(i) == shape[di++]);
+ }
+
+ template<typename Extents, typename T, size_t N>
+ constexpr void
+ test_all_shape_types(std::array<T, N> shape)
+ {
+ test_ctor<Extents>(shape);
+ test_ctor<Extents>(std::span<T, N>(shape));
+ test_ctor<Extents>(std::span<const T, N>(shape));
+ }
+
+ constexpr void
+ test_common_shapes()
+ {
+ auto s = std::array<int, 0>{};
+ auto s2 = std::array<int, 1>{2};
+ auto s123 = std::array<int, 3>{1, 2, 3};
+
+ test_all_shape_types<std::extents<int, 1, dyn, 3>>(s2);
+ test_all_shape_types<std::extents<int, dyn, dyn, dyn>>(s123);
+ test_all_shape_types<std::extents<int, 1, 2, 3>>(s);
+ }
+
+ constexpr bool
+ test_all()
+ {
+ test_common_shapes();
+ return true;
+ }
+}
+
+int
+main()
+{
+ all_extents::test_all();
+ static_assert(all_extents::test_all());
+
+ only_dynamic_extents::test_all();
+ static_assert(only_dynamic_extents::test_all());
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/extents/custom_integer.cc b/libstdc++-v3/testsuite/23_containers/mdspan/extents/custom_integer.cc
new file mode 100644
index 0000000..2907ad1
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/custom_integer.cc
@@ -0,0 +1,87 @@
+// { dg-do run { target c++23 } }
+#include <mdspan>
+
+#include <testsuite_hooks.h>
+
+// Test construction from a custom integer-like object, that has
+// no copy/move ctor or copy/move assignment operator.
+
+constexpr size_t dyn = std::dynamic_extent;
+
+class IntLike
+{
+public:
+ explicit
+ IntLike(int i)
+ : _M_i(i)
+ { }
+
+ IntLike() = delete;
+ IntLike(const IntLike&) = delete;
+ IntLike(IntLike&&) = delete;
+
+ const IntLike&
+ operator=(const IntLike&) = delete;
+
+ const IntLike&
+ operator=(IntLike&&) = delete;
+
+ constexpr
+ operator int() const noexcept
+ { return _M_i; }
+
+private:
+ int _M_i;
+};
+
+static_assert(std::is_convertible_v<IntLike, int>);
+static_assert(std::is_nothrow_constructible_v<int, IntLike>);
+
+void
+test_shape(const auto& s2, const auto& s23)
+{
+ std::extents<int, 2, 3> expected;
+
+ std::extents<int, 2, 3> e1(s23);
+ VERIFY(e1 == expected);
+
+ std::extents<int, dyn, 3> e2(s2);
+ VERIFY(e2 == expected);
+
+ std::extents<int, dyn, 3> e3(s23);
+ VERIFY(e3 == expected);
+
+ std::extents<int, dyn, dyn> e4(s23);
+ VERIFY(e4 == expected);
+}
+
+void
+test_pack()
+{
+ std::extents<int, 2, 3> expected;
+
+ std::extents<int, dyn, 3> e1(IntLike(2));
+ VERIFY(e1 == expected);
+
+ std::extents<int, dyn, 3> e2(IntLike(2), IntLike(3));
+ VERIFY(e2 == expected);
+
+ std::extents<int, dyn, dyn> e3(IntLike(2), IntLike(3));
+ VERIFY(e3 == expected);
+}
+
+int
+main()
+{
+ auto a2 = std::array<IntLike, 1>{IntLike(2)};
+ auto s2 = std::span<IntLike, 1>(a2);
+
+ auto a23 = std::array<IntLike, 2>{IntLike(2), IntLike(3)};
+ auto s23 = std::span<IntLike, 2>(a23);
+
+ test_shape(a2, a23);
+ test_shape(s2, s23);
+ test_pack();
+
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/extents/misc.cc b/libstdc++-v3/testsuite/23_containers/mdspan/extents/misc.cc
new file mode 100644
index 0000000..16204aa
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/misc.cc
@@ -0,0 +1,224 @@
+// { dg-do run { target c++23 } }
+#include <mdspan>
+
+#include <testsuite_hooks.h>
+
+constexpr size_t dyn = std::dynamic_extent;
+
+// Check class traits.
+static_assert(std::regular<std::extents<int>>);
+static_assert(std::regular<std::extents<int, 1>>);
+static_assert(std::regular<std::extents<int, dyn>>);
+
+static_assert(std::is_trivially_copyable_v<std::extents<int>>);
+static_assert(std::is_trivially_copyable_v<std::extents<int, 1>>);
+static_assert(std::is_trivially_copyable_v<std::extents<int, dyn>>);
+
+// Check member typedefs.
+static_assert(std::is_same_v<std::extents<int, 1, 2>::rank_type, size_t>);
+
+static_assert(std::is_unsigned_v<std::extents<int, 2>::size_type>);
+static_assert(std::is_unsigned_v<std::extents<unsigned int, 2>::size_type>);
+
+static_assert(std::is_same_v<std::extents<char, 2>::index_type, char>);
+static_assert(std::is_same_v<std::extents<int, 2>::index_type, int>);
+static_assert(std::is_same_v<std::extents<unsigned int, 2>::index_type,
+ unsigned int>);
+
+// Check `rank`.
+static_assert(std::extents<int, 1>::rank() == 1);
+static_assert(std::extents<int, dyn>::rank() == 1);
+static_assert(std::extents<int, 2, dyn>::rank() == 2);
+
+// Check `rank_dynamic`.
+static_assert(std::extents<int, 1>::rank_dynamic() == 0);
+static_assert(std::extents<int, dyn>::rank_dynamic() == 1);
+static_assert(std::extents<int, 2, dyn>::rank_dynamic() == 1);
+static_assert(std::extents<int, dyn, dyn>::rank_dynamic() == 2);
+
+template<typename T, size_t... Extents>
+ constexpr bool
+ check_rank_return_types()
+ {
+ auto e = std::extents<T, Extents...>();
+ return std::is_same_v<decltype(e.rank()), size_t>
+ && std::is_same_v<decltype(e.rank_dynamic()), size_t>;
+ }
+
+static_assert(check_rank_return_types<int, 1>());
+
+// Check that the static extents don't take up space.
+static_assert(sizeof(std::extents<int, 1, dyn>) == sizeof(int));
+static_assert(sizeof(std::extents<char, 1, dyn>) == sizeof(char));
+
+template<typename Extents>
+class Container
+{
+ int dummy;
+ [[no_unique_address]] std::extents<size_t> b0;
+};
+
+static_assert(sizeof(Container<std::extents<char, 1, 2>>) == sizeof(int));
+static_assert(sizeof(Container<std::extents<size_t, 1, 2>>) == sizeof(int));
+
+// operator=
+static_assert(std::is_nothrow_assignable_v<std::extents<int, dyn, 2>,
+ std::extents<int, 1, 2>>);
+
+constexpr bool
+test_assign()
+{
+ auto e1 = std::extents<int, 1, 2>();
+ auto e2 = std::extents<int, 1, 2>();
+
+ e2 = e1;
+ VERIFY(e2 == e1);
+
+ auto e5 = std::extents<int, 1, dyn>();
+ e5 = e1;
+ VERIFY(e5 == e1);
+
+ auto e3 = std::extents<int, dyn, dyn>(1, 2);
+ auto e4 = std::extents<int, dyn, dyn>(3, 4);
+ e3 = e4;
+ VERIFY(e3 == e4);
+ return true;
+}
+
+// Deduction guide
+template<size_t Rank, typename... Extents>
+constexpr void
+test_deduction(Extents... exts)
+{
+ std::array<size_t, sizeof...(exts)> shape{static_cast<size_t>(exts)...};
+ std::dextents<size_t, Rank> expected(shape);
+ std::extents e(exts...);
+ static_assert(std::is_same_v<decltype(e), std::dextents<size_t, Rank>>);
+ VERIFY(e == expected);
+}
+
+constexpr bool
+test_deduction_all()
+{
+ test_deduction<0>();
+ test_deduction<1>(1);
+ test_deduction<2>(1.0, 2.0f);
+ test_deduction<3>(int(1), char(2), size_t(3));
+ return true;
+}
+
+class A {};
+
+template<typename... Extents>
+ concept deducible = requires
+ {
+ { std::extents(Extents{}...) }
+ -> std::convertible_to<std::dextents<size_t, sizeof...(Extents)>>;
+ };
+
+static_assert(deducible<int>);
+static_assert(!deducible<A, A>);
+
+// dextents
+static_assert(std::is_same_v<std::dextents<int, 0>, std::extents<int>>);
+static_assert(std::is_same_v<std::dextents<int, 1>, std::extents<int, dyn>>);
+static_assert(std::is_same_v<std::dextents<int, 5>,
+ std::extents<int, dyn, dyn, dyn, dyn, dyn>>);
+
+static_assert(std::dextents<int, 5>::rank() == 5);
+static_assert(std::dextents<int, 5>::rank_dynamic() == 5);
+static_assert(std::is_same_v<typename std::dextents<int, 5>::index_type, int>);
+
+// static_extent
+static_assert(std::extents<int, 1, 2>::static_extent(0) == 1);
+static_assert(std::extents<int, 1, 2>::static_extent(1) == 2);
+
+static_assert(std::extents<int, 1, dyn>::static_extent(0) == 1);
+static_assert(std::extents<int, 1, dyn>::static_extent(1) == dyn);
+
+static_assert(std::extents<int, dyn, dyn>::static_extent(0) == dyn);
+static_assert(std::extents<int, dyn, dyn>::static_extent(1) == dyn);
+
+// extent
+template<typename Extent>
+ constexpr void
+ test_extent(const Extent& e,
+ const std::array<typename Extent::index_type, Extent::rank()>& shape)
+ {
+ for(size_t i = 0; i < e.rank(); ++i)
+ VERIFY(e.extent(i) == shape[i]);
+ }
+
+constexpr bool
+test_extent_all()
+{
+ test_extent(std::extents<int, 1, 2>{}, {1, 2});
+ test_extent(std::extents<int, 1, dyn>{2}, {1, 2});
+ test_extent(std::extents<int, dyn, dyn>{1, 2}, {1, 2});
+ return true;
+}
+
+// operator==
+template<typename Lhs, typename Rhs>
+ constexpr void
+ test_ops_eq(const Lhs& lhs, const Rhs& rhs, bool expected)
+ {
+ VERIFY((lhs == rhs) == expected);
+ VERIFY((lhs != rhs) == !expected);
+ }
+
+constexpr void
+test_op_eq_rank_zero()
+{
+ auto e1 = std::extents<int>();
+ auto e2 = std::extents<int>();
+ auto e3 = std::extents<unsigned int>();
+
+ test_ops_eq(e1, e2, true);
+ test_ops_eq(e1, e3, true);
+}
+
+constexpr void
+test_op_eq_common()
+{
+ auto e1 = std::extents<int, 1, 2, 3>();
+ auto e2 = std::extents<int, 1, 2, 3>();
+ auto e3 = std::extents<int, 1, dyn, 3>(2);
+ auto e4 = std::extents<int, 1, dyn, 3>(3);
+
+ auto e5 = std::extents<int, 1>();
+ auto e6 = std::extents<int, 1, 3, 3>();
+
+ test_ops_eq(e1, e2, true);
+ test_ops_eq(e1, e3, true);
+ test_ops_eq(e1, e4, false);
+
+ test_ops_eq(e1, e5, false);
+ test_ops_eq(e1, e6, false);
+ test_ops_eq(e3, e6, false);
+}
+
+constexpr bool
+test_op_eq_all()
+{
+ test_op_eq_rank_zero();
+ test_op_eq_common();
+ return true;
+}
+
+int
+main()
+{
+ test_assign();
+ static_assert(test_assign());
+
+ test_deduction_all();
+ static_assert(test_deduction_all());
+
+ test_extent_all();
+ static_assert(test_extent_all());
+
+ test_op_eq_all();
+ static_assert(test_op_eq_all());
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/std/time/format/pr120114.cc b/libstdc++-v3/testsuite/std/time/format/pr120114.cc
new file mode 100644
index 0000000..c630bb3
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/time/format/pr120114.cc
@@ -0,0 +1,125 @@
+// { dg-do run { target c++23 } }
+// { dg-options "-fexec-charset=UTF-8" }
+// { dg-timeout-factor 2 }
+
+#include <algorithm>
+#include <chrono>
+#include <testsuite_hooks.h>
+
+#define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S)
+#define WIDEN(S) WIDEN_(_CharT, S)
+
+template<typename _CharT>
+void
+test_from_format_string()
+{
+ std::basic_string<_CharT> res;
+ using namespace std::chrono_literals;
+ auto date = 2025y/std::chrono::May/05d;
+
+ res = std::format(WIDEN("{:+<13%F\U0001f921}"), date);
+ VERIFY( res == WIDEN("2025-05-05\U0001f921+") );
+
+ res = std::format(WIDEN("{:->15%F\U0001f921}"), date);
+ VERIFY( res == WIDEN("---2025-05-05\U0001f921") );
+
+ res = std::format(WIDEN("{:=^20%F\U0001f921}"), date);
+ VERIFY( res == WIDEN("====2025-05-05\U0001f921====") );
+}
+
+template<typename _CharT>
+void
+test_formatted_value()
+{
+ // Custom time_put facet which returns Ideographic Telegraph Symbol
+ // for given month for Om.
+ struct TimePut : std::time_put<_CharT>
+ {
+ using iter_type = std::time_put<_CharT>::iter_type;
+ using char_type = std::time_put<_CharT>::char_type;
+
+ iter_type
+ do_put(iter_type out, std::ios_base& io, char_type fill, const tm* t,
+ char format, char modifier) const override
+ {
+ if (format != 'm' && modifier != 'm')
+ return std::time_put<_CharT>::do_put(out, io, fill, t, format, modifier);
+ std::basic_string_view<_CharT> str;
+ switch (t->tm_mon)
+ {
+ case 0:
+ str = WIDEN("\u32C0");
+ break;
+ case 1:
+ str = WIDEN("\u32C1");
+ break;
+ case 2:
+ str = WIDEN("\u32C2");
+ break;
+ case 3:
+ str = WIDEN("\u32C3");
+ break;
+ case 4:
+ str = WIDEN("\u32C4");
+ break;
+ case 5:
+ str = WIDEN("\u32C5");
+ break;
+ case 6:
+ str = WIDEN("\u32C6");
+ break;
+ case 7:
+ str = WIDEN("\u32C7");
+ break;
+ case 8:
+ str = WIDEN("\u32C8");
+ break;
+ case 9:
+ str = WIDEN("\u32C9");
+ break;
+ case 10:
+ str = WIDEN("\u32CA");
+ break;
+ case 11:
+ str = WIDEN("\u32CB");
+ break;
+ };
+ return std::copy(str.begin(), str.end(), out);
+ }
+ };
+ const std::locale loc(std::locale::classic(), new TimePut);
+
+ std::basic_string<_CharT> res;
+
+ res = std::format(loc, WIDEN("{:<1L%Om}"), std::chrono::January);
+ VERIFY( res == WIDEN("\u32C0") );
+
+ res = std::format(loc, WIDEN("{:>2L%Om}"), std::chrono::February);
+ VERIFY( res == WIDEN("\u32C1") );
+
+ res = std::format(loc, WIDEN("{:<3L%Om}"), std::chrono::March);
+ VERIFY( res == WIDEN("\u32C2 ") );
+
+ res = std::format(loc, WIDEN("{:^4L%Om}"), std::chrono::April);
+ VERIFY( res == WIDEN(" \u32C3 ") );
+
+ res = std::format(loc, WIDEN("{:>5L%Om}"), std::chrono::May);
+ VERIFY( res == WIDEN(" \u32C4") );
+
+ res = std::format(loc, WIDEN("{:+<6L%Om}"), std::chrono::June);
+ VERIFY( res == WIDEN("\u32C5++++") );
+
+ res = std::format(loc, WIDEN("{:=^7L%Om}"), std::chrono::July);
+ VERIFY( res == WIDEN("==\u32C6===") );
+
+ res = std::format(loc, WIDEN("{:->8L%Om}"), std::chrono::August);
+ VERIFY( res == WIDEN("------\u32C7") );
+}
+
+int main()
+{
+ test_from_format_string<char>();
+ test_from_format_string<wchar_t>();
+ test_formatted_value<char>();
+ test_formatted_value<wchar_t>();
+}