Hello, Thanks for the review!
On 20/02/2025 17:22, Patrick Palka wrote:
On Sun, 16 Feb 2025, Giuseppe D'Angelo wrote:Hello, the attached patch implements the C++26 papers that add `constexpr` to the specialized memory algorithms (the uninitialized_* family). Tested on x86-64 Linux. Thank you, -- Giuseppe D'AngeloSubject: [PATCH] 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. I've introduced a helper macro to conditionally expand to `constexpr` only in C++26 and above modes. The internal helper guard class for range algorithms instead can be marked unconditionally. uninitialized_fill is the only algorithm where I had to add a branch to a constexpr-friendly version (already existing).Seems the patch also adds code to uninitialized_copy and uninitialized_fill_n?
Whops, sorry, didn't spot them when I reviewed the diff. You're right.
template<typename _T1> +#if __cpp_constexpr >= 202406L // >= C++26 + _GLIBCXX26_CONSTEXPR +#endifMaybe we can get away with unconditionally declaring this _GLIBCXX26_CONSTEXPR? If the compiler doesn't support constexpr placement new then the 'constexpr' would be silently dropped at instantiation time. This would be in line with C++23 P2448R2 which made it no longer IFNDR to declare a constexpr function template for which no specialization is actually constexpr.
It's fundamentally a judgement / compatibility call. The patch adding the _GLIBCXX26_CONSTEXPR macro is pending here https://gcc.gnu.org/pipermail/libstdc++/2025-January/060265.html and checks for __cplusplus >= 202400L.According to cppreference only Clang >= 19 fully implements P2448R2, but Clang 17 and 18 already advertise C++26 compatibility under __cplusplus set to 202400.
On the other hand the ad-hoc _GLIBCXX26_CONSTEXPR_RAW_MEMORY_ALGORITHMS has a more stringent version check (uses the feature-testing macro, which in turn checks for the right value of __cpp_constexpr).
Is switching to _GLIBCXX26_CONSTEXPR going to create compatibility problems? If not, I'll do the change.
+ namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -226,6 +232,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * Like std::copy, but does not require an initialized output range. */ template<typename _InputIterator, typename _ForwardIterator> + _GLIBCXX26_CONSTEXPR_RAW_MEMORY_ALGORITHMS inline _ForwardIterator uninitialized_copy(_InputIterator __first, _InputIterator __last, _ForwardIterator __result) @@ -256,6 +263,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using _Src = decltype(std::__niter_base(__first)); using _ValT = typename iterator_traits<_ForwardIterator>::value_type;++ if (__is_constant_evaluated())We typically call __is_constant_evaluated fully qualified (though I don't remember why since it's not eligible for ADL?)
Ack, will fix.
+ return std::__do_uninit_copy(__first, __last, __result);I guess we could instead guard the memcpy code path preceding the existing call to __do_uninit_copy with !std::__is_constant_evaluated(), rather than adding this new call. But that doesn't seem significantly cleaner and I'm personally OK with your approach :) Same for uninitialized_fill and uninitialized_fill_n
I'm wagering this is the simplest implementation strategy for most constexpr-ified algorithms -- first thing, check if we're called during constant evaluation, if so dispatch to a constexpr-friendly implementation.
Thank you, -- Giuseppe D'Angelo
smime.p7s
Description: S/MIME Cryptographic Signature