https://gcc.gnu.org/g:3052b336455e19a773b06e1eaa681917b3d93169

commit r15-7827-g3052b336455e19a773b06e1eaa681917b3d93169
Author: Giuseppe D'Angelo <giuseppe.dang...@kdab.com>
Date:   Sun Feb 16 19:37:07 2025 +0100

    libstdc++: implement constexpr memory algorithms
    
    This commit adds support for C++26's constexpr specialized memory
    algorithms, introduced by P2283R2, P3508R0, P3369R0.
    
    The uninitialized_default, value, copy, move and fill algorithms are
    affected, in all of their variants (iterator-based, range-based and _n
    versions.)
    
    The changes are mostly mechanical -- add `constexpr` to a number of
    signatures when compiling in C++26 and above modes. The internal helper
    guard class for range algorithms instead can be marked unconditionally.
    
    uninitialized_default_construct is implemented in terms of the
    _Construct_novalue helper, which requires support for C++26's constexpr
    placement new from the compiler (P2747R2, which GCC implements). We can
    simply mark it as constexpr in C++26 language modes, even if the
    compiler does not support P2747R2 (e.g. Clang 17/18), because C++23's
    P2448R2 makes it OK to mark functions as constexpr even if they never
    qualify, and other compilers implement this.
    
    The only "real" change to the implementation of the algorithms is that
    during constant evaluation I need to dispatch to a constexpr-friendly
    version of them.
    
    For each algorithm family I've added only one test to cover it and its
    variants; the idea is to avoid too much repetition and simplify future
    maintenance.
    
    libstdc++-v3/ChangeLog:
    
            * include/bits/ranges_uninitialized.h: Mark the specialized
            memory algorithms as constexpr in C++26. Also mark the members
            of the _DestroyGuard helper class.
            * include/bits/stl_uninitialized.h: Ditto.
            * include/bits/stl_construct.h: (_Construct_novalue) Mark it
            as constexpr in C++26.
            * include/bits/version.def (raw_memory_algorithms): Bump the
            feature-testing macro for C++26.
            * include/bits/version.h: Regenerate.
            * testsuite/20_util/headers/memory/synopsis.cc: Add constexpr to
            the uninitialized_* algorithms (when in C++26) in the test.
            * testsuite/20_util/specialized_algorithms/feature_test_macro.cc:
            New test.
            * 
testsuite/20_util/specialized_algorithms/uninitialized_copy/constexpr.cc:
            New test.
            * 
testsuite/20_util/specialized_algorithms/uninitialized_default_construct/constexpr.cc:
            New test.
            * 
testsuite/20_util/specialized_algorithms/uninitialized_fill/constexpr.cc:
            New test.
            * 
testsuite/20_util/specialized_algorithms/uninitialized_move/constexpr.cc:
            New test.
            * 
testsuite/20_util/specialized_algorithms/uninitialized_value_construct/constexpr.cc:
            New test.
    
    Reviewed-by: Patrick Palka <ppa...@redhat.com>

Diff:
---
 libstdc++-v3/include/bits/ranges_uninitialized.h   | 21 +++++++
 libstdc++-v3/include/bits/stl_construct.h          |  1 +
 libstdc++-v3/include/bits/stl_uninitialized.h      | 39 +++++++++++++
 libstdc++-v3/include/bits/version.def              |  5 ++
 libstdc++-v3/include/bits/version.h                |  7 ++-
 .../testsuite/20_util/headers/memory/synopsis.cc   | 12 ++++
 .../specialized_algorithms/feature_test_macro.cc   | 14 +++++
 .../uninitialized_copy/constexpr.cc                | 58 ++++++++++++++++++
 .../uninitialized_default_construct/constexpr.cc   | 67 +++++++++++++++++++++
 .../uninitialized_fill/constexpr.cc                | 68 ++++++++++++++++++++++
 .../uninitialized_move/constexpr.cc                | 51 ++++++++++++++++
 .../uninitialized_value_construct/constexpr.cc     | 64 ++++++++++++++++++++
 12 files changed, 406 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/bits/ranges_uninitialized.h 
b/libstdc++-v3/include/bits/ranges_uninitialized.h
index ced7bda5e37c..990929efaa9b 100644
--- a/libstdc++-v3/include/bits/ranges_uninitialized.h
+++ b/libstdc++-v3/include/bits/ranges_uninitialized.h
@@ -105,15 +105,18 @@ namespace ranges
        const _Iter* _M_cur;
 
       public:
+       constexpr
        explicit
        _DestroyGuard(const _Iter& __iter)
          : _M_first(__iter), _M_cur(std::__addressof(__iter))
        { }
 
+       constexpr
        void
        release() noexcept
        { _M_cur = nullptr; }
 
+       constexpr
        ~_DestroyGuard()
        {
          if (_M_cur != nullptr)
@@ -126,10 +129,12 @@ namespace ranges
        && is_trivially_destructible_v<iter_value_t<_Iter>>
       struct _DestroyGuard<_Iter>
       {
+       constexpr
        explicit
        _DestroyGuard(const _Iter&)
        { }
 
+       constexpr
        void
        release() noexcept
        { }
@@ -141,6 +146,7 @@ namespace ranges
     template<__detail::__nothrow_forward_iterator _Iter,
             __detail::__nothrow_sentinel<_Iter> _Sent>
       requires default_initializable<iter_value_t<_Iter>>
+      _GLIBCXX26_CONSTEXPR
       _Iter
       operator()(_Iter __first, _Sent __last) const
       {
@@ -159,6 +165,7 @@ namespace ranges
 
     template<__detail::__nothrow_forward_range _Range>
       requires default_initializable<range_value_t<_Range>>
+      _GLIBCXX26_CONSTEXPR
       borrowed_iterator_t<_Range>
       operator()(_Range&& __r) const
       {
@@ -173,6 +180,7 @@ namespace ranges
   {
     template<__detail::__nothrow_forward_iterator _Iter>
       requires default_initializable<iter_value_t<_Iter>>
+      _GLIBCXX26_CONSTEXPR
       _Iter
       operator()(_Iter __first, iter_difference_t<_Iter> __n) const
       {
@@ -198,6 +206,7 @@ namespace ranges
     template<__detail::__nothrow_forward_iterator _Iter,
             __detail::__nothrow_sentinel<_Iter> _Sent>
       requires default_initializable<iter_value_t<_Iter>>
+      _GLIBCXX26_CONSTEXPR
       _Iter
       operator()(_Iter __first, _Sent __last) const
       {
@@ -217,6 +226,7 @@ namespace ranges
 
     template<__detail::__nothrow_forward_range _Range>
       requires default_initializable<range_value_t<_Range>>
+      _GLIBCXX26_CONSTEXPR
       borrowed_iterator_t<_Range>
       operator()(_Range&& __r) const
       {
@@ -231,6 +241,7 @@ namespace ranges
   {
     template<__detail::__nothrow_forward_iterator _Iter>
       requires default_initializable<iter_value_t<_Iter>>
+      _GLIBCXX26_CONSTEXPR
       _Iter
       operator()(_Iter __first, iter_difference_t<_Iter> __n) const
       {
@@ -261,6 +272,7 @@ namespace ranges
             __detail::__nothrow_forward_iterator _Out,
             __detail::__nothrow_sentinel<_Out> _OSent>
       requires constructible_from<iter_value_t<_Out>, iter_reference_t<_Iter>>
+      _GLIBCXX26_CONSTEXPR
       uninitialized_copy_result<_Iter, _Out>
       operator()(_Iter __ifirst, _ISent __ilast,
                 _Out __ofirst, _OSent __olast) const
@@ -292,6 +304,7 @@ namespace ranges
     template<input_range _IRange, __detail::__nothrow_forward_range _ORange>
       requires constructible_from<range_value_t<_ORange>,
                                  range_reference_t<_IRange>>
+      _GLIBCXX26_CONSTEXPR
       uninitialized_copy_result<borrowed_iterator_t<_IRange>,
                                borrowed_iterator_t<_ORange>>
       operator()(_IRange&& __inr, _ORange&& __outr) const
@@ -311,6 +324,7 @@ namespace ranges
     template<input_iterator _Iter, __detail::__nothrow_forward_iterator _Out,
             __detail::__nothrow_sentinel<_Out> _Sent>
       requires constructible_from<iter_value_t<_Out>, iter_reference_t<_Iter>>
+      _GLIBCXX26_CONSTEXPR
       uninitialized_copy_n_result<_Iter, _Out>
       operator()(_Iter __ifirst, iter_difference_t<_Iter> __n,
                 _Out __ofirst, _Sent __olast) const
@@ -350,6 +364,7 @@ namespace ranges
             __detail::__nothrow_sentinel<_Out> _OSent>
       requires constructible_from<iter_value_t<_Out>,
                                  iter_rvalue_reference_t<_Iter>>
+      _GLIBCXX26_CONSTEXPR
       uninitialized_move_result<_Iter, _Out>
       operator()(_Iter __ifirst, _ISent __ilast,
                 _Out __ofirst, _OSent __olast) const
@@ -384,6 +399,7 @@ namespace ranges
     template<input_range _IRange, __detail::__nothrow_forward_range _ORange>
       requires constructible_from<range_value_t<_ORange>,
               range_rvalue_reference_t<_IRange>>
+      _GLIBCXX26_CONSTEXPR
       uninitialized_move_result<borrowed_iterator_t<_IRange>,
                                borrowed_iterator_t<_ORange>>
       operator()(_IRange&& __inr, _ORange&& __outr) const
@@ -404,6 +420,7 @@ namespace ranges
       __detail::__nothrow_sentinel<_Out> _Sent>
        requires constructible_from<iter_value_t<_Out>,
                                    iter_rvalue_reference_t<_Iter>>
+      _GLIBCXX26_CONSTEXPR
       uninitialized_move_n_result<_Iter, _Out>
       operator()(_Iter __ifirst, iter_difference_t<_Iter> __n,
                 _Out __ofirst, _Sent __olast) const
@@ -441,6 +458,7 @@ namespace ranges
     template<__detail::__nothrow_forward_iterator _Iter,
             __detail::__nothrow_sentinel<_Iter> _Sent, typename _Tp>
       requires constructible_from<iter_value_t<_Iter>, const _Tp&>
+      _GLIBCXX26_CONSTEXPR
       _Iter
       operator()(_Iter __first, _Sent __last, const _Tp& __x) const
       {
@@ -460,6 +478,7 @@ namespace ranges
 
     template<__detail::__nothrow_forward_range _Range, typename _Tp>
       requires constructible_from<range_value_t<_Range>, const _Tp&>
+      _GLIBCXX26_CONSTEXPR
       borrowed_iterator_t<_Range>
       operator()(_Range&& __r, const _Tp& __x) const
       {
@@ -473,6 +492,7 @@ namespace ranges
   {
     template<__detail::__nothrow_forward_iterator _Iter, typename _Tp>
       requires constructible_from<iter_value_t<_Iter>, const _Tp&>
+      _GLIBCXX26_CONSTEXPR
       _Iter
       operator()(_Iter __first, iter_difference_t<_Iter> __n,
                 const _Tp& __x) const
@@ -573,6 +593,7 @@ namespace ranges
 }
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
+
 #endif // concepts
 #endif // C++20
 #endif // _RANGES_UNINITIALIZED_H
diff --git a/libstdc++-v3/include/bits/stl_construct.h 
b/libstdc++-v3/include/bits/stl_construct.h
index bd8235e901bd..23b8fb754710 100644
--- a/libstdc++-v3/include/bits/stl_construct.h
+++ b/libstdc++-v3/include/bits/stl_construct.h
@@ -144,6 +144,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
 
   template<typename _T1>
+    _GLIBCXX26_CONSTEXPR
     inline void
     _Construct_novalue(_T1* __p)
     { ::new(static_cast<void*>(__p)) _T1; }
diff --git a/libstdc++-v3/include/bits/stl_uninitialized.h 
b/libstdc++-v3/include/bits/stl_uninitialized.h
index ed836663a442..b1428db48b00 100644
--- a/libstdc++-v3/include/bits/stl_uninitialized.h
+++ b/libstdc++-v3/include/bits/stl_uninitialized.h
@@ -226,6 +226,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
    *  Like std::copy, but does not require an initialized output range.
   */
   template<typename _InputIterator, typename _ForwardIterator>
+    _GLIBCXX26_CONSTEXPR
     inline _ForwardIterator
     uninitialized_copy(_InputIterator __first, _InputIterator __last,
                       _ForwardIterator __result)
@@ -256,6 +257,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       using _Src = decltype(std::__niter_base(__first));
       using _ValT = typename iterator_traits<_ForwardIterator>::value_type;
 
+#if __glibcxx_raw_memory_algorithms >= 202411L // >= C++26
+      if consteval {
+       return std::__do_uninit_copy(__first, __last, __result);
+      }
+#endif
       if constexpr (!__is_trivially_constructible(_ValT, decltype(*__first)))
        return std::__do_uninit_copy(__first, __last, __result);
       else if constexpr (__memcpyable<_Dest, _Src>::__value)
@@ -381,6 +387,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
    *  Like std::fill, but does not require an initialized output range.
   */
   template<typename _ForwardIterator, typename _Tp>
+    _GLIBCXX26_CONSTEXPR
     inline void
     uninitialized_fill(_ForwardIterator __first, _ForwardIterator __last,
                       const _Tp& __x)
@@ -400,6 +407,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #if __cplusplus >= 201103L
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wc++17-extensions"
+#if __glibcxx_raw_memory_algorithms >= 202411L // >= C++26
+      if consteval {
+       return std::__do_uninit_fill(__first, __last, __x);
+      }
+#endif
       if constexpr (__is_byte<_ValueType>::__value)
        if constexpr (is_same<_ValueType, _Tp>::value
                        || is_integral<_Tp>::value)
@@ -509,6 +521,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
    *  Like std::fill_n, but does not require an initialized output range.
   */
   template<typename _ForwardIterator, typename _Size, typename _Tp>
+    _GLIBCXX26_CONSTEXPR
     inline _ForwardIterator
     uninitialized_fill_n(_ForwardIterator __first, _Size __n, const _Tp& __x)
     {
@@ -522,6 +535,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        _ValueType;
 
 #if __cplusplus >= 201103L
+#if __glibcxx_raw_memory_algorithms >= 202411L // >= C++26
+      if consteval {
+       return std::__do_uninit_fill_n(__first, __n, __x);
+      }
+#endif
       if constexpr (__is_byte<_ValueType>::__value)
        if constexpr (is_integral<_Tp>::value)
          if constexpr (is_integral<_Size>::value)
@@ -815,6 +833,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __uninitialized_default_1
     {
       template<typename _ForwardIterator>
+        _GLIBCXX26_CONSTEXPR
         static void
         __uninit_default(_ForwardIterator __first, _ForwardIterator __last)
         {
@@ -829,6 +848,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __uninitialized_default_1<true>
     {
       template<typename _ForwardIterator>
+        _GLIBCXX26_CONSTEXPR
         static void
         __uninit_default(_ForwardIterator __first, _ForwardIterator __last)
         {
@@ -882,6 +902,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // __uninitialized_default
   // Fills [first, last) with value-initialized value_types.
   template<typename _ForwardIterator>
+    _GLIBCXX26_CONSTEXPR
     inline void
     __uninitialized_default(_ForwardIterator __first,
                            _ForwardIterator __last)
@@ -979,6 +1000,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __uninitialized_default_novalue_1
     {
       template<typename _ForwardIterator>
+       _GLIBCXX26_CONSTEXPR
        static void
        __uninit_default_novalue(_ForwardIterator __first,
                                 _ForwardIterator __last)
@@ -994,6 +1016,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __uninitialized_default_novalue_1<true>
     {
       template<typename _ForwardIterator>
+        _GLIBCXX26_CONSTEXPR
         static void
         __uninit_default_novalue(_ForwardIterator, _ForwardIterator)
        {
@@ -1004,6 +1027,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __uninitialized_default_novalue_n_1
     {
       template<typename _ForwardIterator, typename _Size>
+       _GLIBCXX26_CONSTEXPR
        static _ForwardIterator
        __uninit_default_novalue_n(_ForwardIterator __first, _Size __n)
        {
@@ -1019,6 +1043,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __uninitialized_default_novalue_n_1<true>
     {
       template<typename _ForwardIterator, typename _Size>
+        _GLIBCXX26_CONSTEXPR
        static _ForwardIterator
        __uninit_default_novalue_n(_ForwardIterator __first, _Size __n)
        { return std::next(__first, __n); }
@@ -1027,6 +1052,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // __uninitialized_default_novalue
   // Fills [first, last) with default-initialized value_types.
   template<typename _ForwardIterator>
+    _GLIBCXX26_CONSTEXPR
     inline void
     __uninitialized_default_novalue(_ForwardIterator __first,
                                    _ForwardIterator __last)
@@ -1042,6 +1068,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // __uninitialized_default_novalue_n
   // Fills [first, first + n) with default-initialized value_types.
   template<typename _ForwardIterator, typename _Size>
+    _GLIBCXX26_CONSTEXPR
     inline _ForwardIterator
     __uninitialized_default_novalue_n(_ForwardIterator __first, _Size __n)
     {
@@ -1055,6 +1082,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   template<typename _InputIterator, typename _Size,
           typename _ForwardIterator>
+    _GLIBCXX26_CONSTEXPR
     _ForwardIterator
     __uninitialized_copy_n(_InputIterator __first, _Size __n,
                           _ForwardIterator __result, input_iterator_tag)
@@ -1068,6 +1096,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   template<typename _RandomAccessIterator, typename _Size,
           typename _ForwardIterator>
+    _GLIBCXX26_CONSTEXPR
     inline _ForwardIterator
     __uninitialized_copy_n(_RandomAccessIterator __first, _Size __n,
                           _ForwardIterator __result,
@@ -1076,6 +1105,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   template<typename _InputIterator, typename _Size,
           typename _ForwardIterator>
+    _GLIBCXX26_CONSTEXPR
     pair<_InputIterator, _ForwardIterator>
     __uninitialized_copy_n_pair(_InputIterator __first, _Size __n,
                                _ForwardIterator __result, input_iterator_tag)
@@ -1089,6 +1119,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   template<typename _RandomAccessIterator, typename _Size,
           typename _ForwardIterator>
+    _GLIBCXX26_CONSTEXPR
     inline pair<_RandomAccessIterator, _ForwardIterator>
     __uninitialized_copy_n_pair(_RandomAccessIterator __first, _Size __n,
                           _ForwardIterator __result,
@@ -1112,6 +1143,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
    *  Like copy_n(), but does not require an initialized output range.
   */
   template<typename _InputIterator, typename _Size, typename _ForwardIterator>
+    _GLIBCXX26_CONSTEXPR
     inline _ForwardIterator
     uninitialized_copy_n(_InputIterator __first, _Size __n,
                         _ForwardIterator __result)
@@ -1120,6 +1152,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   /// @cond undocumented
   template<typename _InputIterator, typename _Size, typename _ForwardIterator>
+    _GLIBCXX26_CONSTEXPR
     inline pair<_InputIterator, _ForwardIterator>
     __uninitialized_copy_n_pair(_InputIterator __first, _Size __n,
                              _ForwardIterator __result)
@@ -1139,6 +1172,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
    *  @since C++17
   */
   template <typename _ForwardIterator>
+    _GLIBCXX26_CONSTEXPR
     inline void
     uninitialized_default_construct(_ForwardIterator __first,
                                    _ForwardIterator __last)
@@ -1154,6 +1188,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
    *  @since C++17
   */
   template <typename _ForwardIterator, typename _Size>
+    _GLIBCXX26_CONSTEXPR
     inline _ForwardIterator
     uninitialized_default_construct_n(_ForwardIterator __first, _Size __count)
     {
@@ -1167,6 +1202,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
    *  @since C++17
   */
   template <typename _ForwardIterator>
+    _GLIBCXX26_CONSTEXPR
     inline void
     uninitialized_value_construct(_ForwardIterator __first,
                                  _ForwardIterator __last)
@@ -1182,6 +1218,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
    *  @since C++17
   */
   template <typename _ForwardIterator, typename _Size>
+    _GLIBCXX26_CONSTEXPR
     inline _ForwardIterator
     uninitialized_value_construct_n(_ForwardIterator __first, _Size __count)
     {
@@ -1197,6 +1234,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
    *  @since C++17
   */
   template <typename _InputIterator, typename _ForwardIterator>
+    _GLIBCXX26_CONSTEXPR
     inline _ForwardIterator
     uninitialized_move(_InputIterator __first, _InputIterator __last,
                       _ForwardIterator __result)
@@ -1215,6 +1253,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
    *  @since C++17
   */
   template <typename _InputIterator, typename _Size, typename _ForwardIterator>
+    _GLIBCXX26_CONSTEXPR
     inline pair<_InputIterator, _ForwardIterator>
     uninitialized_move_n(_InputIterator __first, _Size __count,
                         _ForwardIterator __result)
diff --git a/libstdc++-v3/include/bits/version.def 
b/libstdc++-v3/include/bits/version.def
index 665b92acae5a..0cdc2e82fc55 100644
--- a/libstdc++-v3/include/bits/version.def
+++ b/libstdc++-v3/include/bits/version.def
@@ -521,6 +521,11 @@ ftms = {
 
 ftms = {
   name = raw_memory_algorithms;
+  values = {
+    v = 202411;
+    cxxmin = 26;
+    extra_cond = "__cpp_constexpr >= 202406L";
+  };
   values = {
     v = 201606;
     cxxmin = 17;
diff --git a/libstdc++-v3/include/bits/version.h 
b/libstdc++-v3/include/bits/version.h
index b47b75a1ca97..ec52cba517fa 100644
--- a/libstdc++-v3/include/bits/version.h
+++ b/libstdc++-v3/include/bits/version.h
@@ -581,7 +581,12 @@
 #undef __glibcxx_want_gcd_lcm
 
 #if !defined(__cpp_lib_raw_memory_algorithms)
-# if (__cplusplus >= 201703L)
+# if (__cplusplus >  202302L) && (__cpp_constexpr >= 202406L)
+#  define __glibcxx_raw_memory_algorithms 202411L
+#  if defined(__glibcxx_want_all) || 
defined(__glibcxx_want_raw_memory_algorithms)
+#   define __cpp_lib_raw_memory_algorithms 202411L
+#  endif
+# elif (__cplusplus >= 201703L)
 #  define __glibcxx_raw_memory_algorithms 201606L
 #  if defined(__glibcxx_want_all) || 
defined(__glibcxx_want_raw_memory_algorithms)
 #   define __cpp_lib_raw_memory_algorithms 201606L
diff --git a/libstdc++-v3/testsuite/20_util/headers/memory/synopsis.cc 
b/libstdc++-v3/testsuite/20_util/headers/memory/synopsis.cc
index c9edfb2c0ff1..450a6a7bfc6b 100644
--- a/libstdc++-v3/testsuite/20_util/headers/memory/synopsis.cc
+++ b/libstdc++-v3/testsuite/20_util/headers/memory/synopsis.cc
@@ -73,18 +73,30 @@ namespace std
   template <class T> T* addressof(T&) noexcept;
 #endif
   template <class InputIterator, class ForwardIterator>
+#if __cplusplus >= 202400L
+  constexpr
+#endif
   ForwardIterator
   uninitialized_copy(InputIterator first, InputIterator last,
                     ForwardIterator result);
 #if __cplusplus >= 201103L
   template <class InputIterator, class Size, class ForwardIterator>
+#if __cplusplus >= 202400L
+  constexpr
+#endif
   ForwardIterator
   uninitialized_copy_n(InputIterator first, Size n, ForwardIterator result);
 #endif
   template <class ForwardIterator, class T>
+#if __cplusplus >= 202400L
+  constexpr
+#endif
   void uninitialized_fill(ForwardIterator first, ForwardIterator last,
                          const T& x);
   template <class ForwardIterator, class Size, class T>
+#if __cplusplus >= 202400L
+  constexpr
+#endif
   void uninitialized_fill_n(ForwardIterator first, Size n, const T& x);
 
 #if __cplusplus >= 201103L
diff --git 
a/libstdc++-v3/testsuite/20_util/specialized_algorithms/feature_test_macro.cc 
b/libstdc++-v3/testsuite/20_util/specialized_algorithms/feature_test_macro.cc
new file mode 100644
index 000000000000..0252753aa664
--- /dev/null
+++ 
b/libstdc++-v3/testsuite/20_util/specialized_algorithms/feature_test_macro.cc
@@ -0,0 +1,14 @@
+// { dg-do compile { target c++17 } }
+// { dg-add-options no_pch }
+
+#include <memory>
+
+#ifndef __cpp_lib_raw_memory_algorithms
+# error "Feature-test macro for raw memory algorithms missing"
+#elif __cplusplus > 202302L
+# if __cpp_lib_raw_memory_algorithms < 202411L
+#  error "Feature-test macro for raw memory algorithms has wrong value"
+# endif
+#elif __cpp_lib_raw_memory_algorithms < 201606L
+# error "Feature-test macro for raw memory algorithms has wrong value"
+#endif
diff --git 
a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/constexpr.cc
 
b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/constexpr.cc
new file mode 100644
index 000000000000..6f05b0ce309d
--- /dev/null
+++ 
b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/constexpr.cc
@@ -0,0 +1,58 @@
+// { dg-do compile { target c++26 } }
+
+#include <algorithm>
+#include <memory>
+#include <span>
+#include <string>
+#include <vector>
+
+template<typename T>
+constexpr
+bool
+test01_impl(std::vector<T> input)
+{
+  static_assert(std::copy_constructible<T>);
+  static_assert(std::equality_comparable<T>);
+
+  const std::size_t input_size = input.size();
+  std::allocator<T> alloc;
+  T* ptr = alloc.allocate(input_size);
+
+  std::uninitialized_copy(input.begin(), input.end(), ptr);
+  if (!std::equal(input.begin(), input.end(), ptr, ptr + input_size))
+    return false;
+  std::destroy(ptr, ptr + input_size);
+
+  std::uninitialized_copy_n(input.begin(), input_size, ptr);
+  if (!std::equal(input.begin(), input.end(), ptr, ptr + input_size))
+    return false;
+  std::destroy_n(ptr, input_size);
+
+  std::span<T> output(ptr, ptr + input_size);
+  std::ranges::uninitialized_copy(input, output);
+  if (!std::ranges::equal(input, output))
+    return false;
+  std::ranges::destroy(output);
+
+  std::ranges::uninitialized_copy_n(input.begin(), input_size, ptr, ptr + 
input_size);
+  if (!std::ranges::equal(input.begin(), input.end(), ptr, ptr + input_size))
+    return false;
+  std::ranges::destroy_n(ptr, input_size);
+
+  alloc.deallocate(ptr, input_size);
+  return true;
+}
+
+constexpr
+bool
+test01()
+{
+  return
+    test01_impl<char>({'a', 'b', 'c'}) &&
+    test01_impl<int>({1, 2, 3, 4}) &&
+    test01_impl<double>({1.0, 2.0, 3.0, 4.0}) &&
+    test01_impl<std::string>({"a", "b", "cc", "dddd", "eeeeeeeeeeeeeeee"}) &&
+    test01_impl<std::vector<int>>({ {0}, {0, 1}, {0, 1, 2}});
+}
+
+static_assert(test01());
diff --git 
a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_default_construct/constexpr.cc
 
b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_default_construct/constexpr.cc
new file mode 100644
index 000000000000..db39c8b4d051
--- /dev/null
+++ 
b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_default_construct/constexpr.cc
@@ -0,0 +1,67 @@
+// { dg-do compile { target c++26 } }
+
+#include <algorithm>
+#include <memory>
+#include <span>
+#include <string>
+#include <vector>
+
+template<typename T>
+constexpr
+bool
+test01_impl()
+{
+  static_assert(std::default_initializable<T>);
+  static_assert(std::equality_comparable<T>);
+
+  constexpr std::size_t size = 42;
+  std::allocator<T> alloc;
+  T* ptr = alloc.allocate(size);
+
+  auto check = [&]() -> bool
+  {
+    if constexpr (!std::is_trivially_default_constructible_v<T>)
+      return std::all_of(ptr, ptr + size, [](auto &&x) { return x == T(); });
+    else
+      return true;
+  };
+
+  std::uninitialized_default_construct(ptr, ptr + size);
+  if (!check())
+    return false;
+  std::destroy(ptr, ptr + size);
+
+  std::uninitialized_default_construct_n(ptr, size);
+  if (!check())
+    return false;
+  std::destroy_n(ptr, size);
+
+  std::span<T> storage(ptr, ptr + size);
+  std::ranges::uninitialized_default_construct(storage);
+  if (!check())
+    return false;
+  std::ranges::destroy(storage);
+
+  std::ranges::uninitialized_default_construct_n(ptr, size);
+  if (!check())
+    return false;
+  std::ranges::destroy_n(ptr, size);
+
+  alloc.deallocate(ptr, size);
+  return true;
+}
+
+constexpr
+bool
+test01()
+{
+  return
+    test01_impl<char>() &&
+    test01_impl<int>() &&
+    test01_impl<double>() &&
+    test01_impl<std::string>() &&
+    test01_impl<std::vector<int>>() &&
+    test01_impl<std::unique_ptr<int>>();
+}
+
+static_assert(test01());
diff --git 
a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill/constexpr.cc
 
b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill/constexpr.cc
new file mode 100644
index 000000000000..e43cd35a92d9
--- /dev/null
+++ 
b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill/constexpr.cc
@@ -0,0 +1,68 @@
+// { dg-do compile { target c++26 } }
+
+#include <algorithm>
+#include <memory>
+#include <span>
+#include <string>
+#include <vector>
+
+template<typename T, typename U = T>
+constexpr
+bool
+test01_impl(const U& value = U())
+{
+  static_assert(std::constructible_from<T, U>);
+  //static_assert(std::equality_comparable_with<T, U>); // unique_ptr fails 
with nullptr_t
+
+  constexpr std::size_t size = 42;
+  std::allocator<T> alloc;
+  T* ptr = alloc.allocate(size);
+
+  auto check = [&]() -> bool
+  {
+    return std::all_of(ptr, ptr + size, [&](auto &&x) { return x == value; });
+  };
+
+  std::uninitialized_fill(ptr, ptr + size, value);
+  if (!check())
+    return false;
+  std::destroy(ptr, ptr + size);
+
+  std::uninitialized_fill_n(ptr, size, value);
+  if (!check())
+    return false;
+  std::destroy_n(ptr, size);
+
+  std::span<T> storage(ptr, ptr + size);
+  std::ranges::uninitialized_fill(storage, value);
+  if (!check())
+    return false;
+  std::ranges::destroy(storage);
+
+  std::ranges::uninitialized_fill_n(ptr, size, value);
+  if (!check())
+    return false;
+  std::ranges::destroy_n(ptr, size);
+
+  alloc.deallocate(ptr, size);
+  return true;
+}
+
+constexpr
+bool
+test01()
+{
+  return
+    test01_impl<char>('\0') &&
+    test01_impl<char>('x') &&
+    test01_impl<int>(0) &&
+    test01_impl<int>(42) &&
+    test01_impl<double>(3.14) &&
+    test01_impl<std::string>() &&
+    test01_impl<std::string>(std::string("test")) &&
+    test01_impl<std::vector<int>>() &&
+    test01_impl<std::vector<int>>({1, 2, 3, 4}) &&
+    test01_impl<std::unique_ptr<int>>(nullptr);
+}
+
+static_assert(test01());
diff --git 
a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_move/constexpr.cc
 
b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_move/constexpr.cc
new file mode 100644
index 000000000000..47403ae706dc
--- /dev/null
+++ 
b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_move/constexpr.cc
@@ -0,0 +1,51 @@
+// { dg-do compile { target c++26 } }
+
+#include <algorithm>
+#include <memory>
+#include <span>
+#include <string>
+#include <vector>
+
+template<typename T>
+constexpr
+bool
+test01_impl(std::vector<T> input)
+{
+  static_assert(std::move_constructible<T>);
+  static_assert(std::equality_comparable<T>);
+
+  const std::size_t input_size = input.size();
+  std::allocator<T> alloc;
+  T* ptr = alloc.allocate(input_size);
+
+  std::uninitialized_move(input.begin(), input.end(), ptr);
+  std::destroy(ptr, ptr + input_size);
+
+  std::uninitialized_move_n(input.begin(), input_size, ptr);
+  std::destroy_n(ptr, input_size);
+
+  std::span<T> output(ptr, ptr + input_size);
+  std::ranges::uninitialized_move(input, output);
+  std::ranges::destroy(output);
+
+  std::ranges::uninitialized_move_n(input.begin(), input_size, ptr, ptr + 
input_size);
+  std::ranges::destroy_n(ptr, input_size);
+
+  alloc.deallocate(ptr, input_size);
+  return true;
+}
+
+constexpr
+bool
+test01()
+{
+  return
+    test01_impl<char>({'a', 'b', 'c'}) &&
+    test01_impl<int>({1, 2, 3, 4}) &&
+    test01_impl<double>({1.0, 2.0, 3.0, 4.0}) &&
+    test01_impl<std::string>({"a", "b", "cc", "dddd", "eeeeeeeeeeeeeeee"}) &&
+    test01_impl<std::vector<int>>({ {0}, {0, 1}, {0, 1, 2}}) &&
+    test01_impl<std::unique_ptr<int>>(std::vector<std::unique_ptr<int>>(10));
+}
+
+static_assert(test01());
diff --git 
a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_value_construct/constexpr.cc
 
b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_value_construct/constexpr.cc
new file mode 100644
index 000000000000..55dfc59b5ef3
--- /dev/null
+++ 
b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_value_construct/constexpr.cc
@@ -0,0 +1,64 @@
+// { dg-do compile { target c++26 } }
+
+#include <algorithm>
+#include <memory>
+#include <span>
+#include <string>
+#include <vector>
+
+template<typename T>
+constexpr
+bool
+test01_impl()
+{
+  static_assert(std::default_initializable<T>);
+  static_assert(std::equality_comparable<T>);
+
+  constexpr std::size_t size = 42;
+  std::allocator<T> alloc;
+  T* ptr = alloc.allocate(size);
+
+  auto check = [&]() -> bool
+  {
+    return std::all_of(ptr, ptr + size, [](auto &&x) { return x == T(); });
+  };
+
+  std::uninitialized_value_construct(ptr, ptr + size);
+  if (!check())
+    return false;
+  std::destroy(ptr, ptr + size);
+
+  std::uninitialized_value_construct_n(ptr, size);
+  if (!check())
+    return false;
+  std::destroy_n(ptr, size);
+
+  std::span<T> storage(ptr, ptr + size);
+  std::ranges::uninitialized_value_construct(storage);
+  if (!check())
+    return false;
+  std::ranges::destroy(storage);
+
+  std::ranges::uninitialized_value_construct_n(ptr, size);
+  if (!check())
+    return false;
+  std::ranges::destroy_n(ptr, size);
+
+  alloc.deallocate(ptr, size);
+  return true;
+}
+
+constexpr
+bool
+test01()
+{
+  return
+    test01_impl<char>() &&
+    test01_impl<int>() &&
+    test01_impl<double>() &&
+    test01_impl<std::string>() &&
+    test01_impl<std::vector<int>>() &&
+    test01_impl<std::unique_ptr<int>>();
+}
+
+static_assert(test01());

Reply via email to