From 9d7581a8195e2be4d318ac253f556b0163bc4c41 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Tue, 7 Apr 2026 18:44:44 -0700 Subject: [PATCH 01/37] LWG3662 basic_string::append/assign(NTBS, pos, n) suboptimal Fixes NB RU 268 (C++26 CD). --- source/strings.tex | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/source/strings.tex b/source/strings.tex index d2c0d62791..b8619c9b4b 100644 --- a/source/strings.tex +++ b/source/strings.tex @@ -2153,6 +2153,7 @@ constexpr basic_string& append(const T& t, size_type pos, size_type n = npos); constexpr basic_string& append(const charT* s, size_type n); constexpr basic_string& append(const charT* s); + constexpr basic_string& append(const charT* s, size_type pos, size_type n); constexpr basic_string& append(size_type n, charT c); template constexpr basic_string& append(InputIterator first, InputIterator last); @@ -2173,6 +2174,7 @@ constexpr basic_string& assign(const T& t, size_type pos, size_type n = npos); constexpr basic_string& assign(const charT* s, size_type n); constexpr basic_string& assign(const charT* s); + constexpr basic_string& assign(const charT* s, size_type pos, size_type n); constexpr basic_string& assign(size_type n, charT c); template constexpr basic_string& assign(InputIterator first, InputIterator last); @@ -3353,6 +3355,18 @@ Equivalent to: \tcode{return append(s, traits::length(s));} \end{itemdescr} +\indexlibrarymember{append}{basic_string}% +\begin{itemdecl} +constexpr basic_string& append(const charT* s, size_type pos, size_type n); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\tcode{return append(basic_string_view(s).substr(pos, n));} +\end{itemdescr} + \indexlibrarymember{append}{basic_string}% \begin{itemdecl} constexpr basic_string& append(size_type n, charT c); @@ -3546,6 +3560,18 @@ Equivalent to: \tcode{return assign(s, traits::length(s));} \end{itemdescr} +\indexlibrarymember{assign}{basic_string}% +\begin{itemdecl} +constexpr basic_string& assign(const charT* s, size_type pos, size_type n); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\tcode{return assign(basic_string_view(s).substr(pos, n));} +\end{itemdescr} + \indexlibrarymember{assign}{basic_string}% \begin{itemdecl} constexpr basic_string& assign(initializer_list il); From 581d0cb3387dc43b9db79d86f181c703cf583eeb Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Tue, 7 Apr 2026 18:48:04 -0700 Subject: [PATCH 02/37] LWG3777 Common cartesian_product_view produces an invalid range if the first range is input and one of the ranges is empty --- source/iterators.tex | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/iterators.tex b/source/iterators.tex index 7d97d4395a..ed599d9725 100644 --- a/source/iterators.tex +++ b/source/iterators.tex @@ -1692,6 +1692,9 @@ \range{++i}{s} denotes a range. \item \tcode{\libconcept{assignable_from}} is either modeled or not satisfied. + +\item If \tcode{I} and \tcode{S} are the same type, then + \tcode{i == i} is \tcode{true}. \end{itemize} \end{itemdescr} From a50b69cfaa55263e5e18b1fc3de3764055eff4c1 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Tue, 7 Apr 2026 18:54:59 -0700 Subject: [PATCH 03/37] LWG3797 elements_view insufficiently constrained --- source/ranges.tex | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source/ranges.tex b/source/ranges.tex index 18bed31c3c..4edd7d9642 100644 --- a/source/ranges.tex +++ b/source/ranges.tex @@ -10237,7 +10237,10 @@ namespace std::ranges { template concept @\defexposconcept{has-tuple-element}@ = // \expos - @\exposconcept{tuple-like}@ && N < tuple_size_v; + @\exposconcept{tuple-like}@ && N < tuple_size_v && + requires(T t) { + { std::get(t) } -> @\libconcept{convertible_to}@&>; + }; template concept @\defexposconcept{returnable-element}@ = // \expos From 4fa9e5795318cc20d2217b1f182488a2be7bc9b0 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Tue, 7 Apr 2026 19:02:47 -0700 Subject: [PATCH 04/37] LWG3891 LWG 3870 breaks std::expected --- source/utilities.tex | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/utilities.tex b/source/utilities.tex index 7b5fe5d565..f3eae6ff48 100644 --- a/source/utilities.tex +++ b/source/utilities.tex @@ -8258,10 +8258,10 @@ friend constexpr bool operator==(const expected&, const unexpected&); private: - bool @\exposid{has_val}@; // \expos + bool @\exposid{has_val}@; // \expos union { - T @\exposid{val}@; // \expos - E @\exposid{unex}@; // \expos + remove_cv_t @\exposid{val}@; // \expos + E @\exposid{unex}@; // \expos }; }; } @@ -8987,7 +8987,7 @@ throw; } } else { - T tmp(std::move(@\exposid{val}@)); + remove_cv_t tmp(std::move(@\exposid{val}@)); destroy_at(addressof(@\exposid{val}@)); try { construct_at(addressof(@\exposid{unex}@), std::move(rhs.@\exposid{unex}@)); From 0b97facdb5675becd400d06a7d9b47c147079dec Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Tue, 7 Apr 2026 19:19:34 -0700 Subject: [PATCH 05/37] LWG4026 Assignment operators of std::expected should propagate triviality Fixes NB US 135-216, US 136-217 (C++26 CD). --- source/utilities.tex | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/source/utilities.tex b/source/utilities.tex index f3eae6ff48..c92ab2e45b 100644 --- a/source/utilities.tex +++ b/source/utilities.tex @@ -8736,6 +8736,18 @@ \tcode{is_nothrow_move_constructible_v || is_nothrow_move_constructible_v} is \tcode{true}. \end{itemize} + +%FIXME: Is this supposed to be part of the Remarks clause? +\pnum +This operator is trivial if: +\begin{itemize} +\item \tcode{is_trivially_copy_constructible_v} is \tcode{true}, and +\item \tcode{is_trivially_copy_assignable_v} is \tcode{true}, and +\item \tcode{is_trivially_destructible_v} is \tcode{true}, and +\item \tcode{is_trivially_copy_constructible_v} is \tcode{true}, and +\item \tcode{is_trivially_copy_assignable_v} is \tcode{true}, and +\item \tcode{is_trivially_destructible_v} is \tcode{true}. +\end{itemize} \end{itemdescr} \indexlibrarymember{operator=}{expected}% @@ -8793,6 +8805,18 @@ is_nothrow_move_assignable_v && is_nothrow_move_constructible_v && is_nothrow_move_assignable_v && is_nothrow_move_constructible_v \end{codeblock} + +%FIXME: Is this supposed to be part of the Remarks clause? +\pnum +This operator is trivial if: +\begin{itemize} +\item \tcode{is_trivially_move_constructible_v} is \tcode{true}, and +\item \tcode{is_trivially_move_assignable_v} is \tcode{true}, and +\item \tcode{is_trivially_destructible_v} is \tcode{true}, and +\item \tcode{is_trivially_move_constructible_v} is \tcode{true}, and +\item \tcode{is_trivially_move_assignable_v} is \tcode{true}, and +\item \tcode{is_trivially_destructible_v} is \tcode{true}. +\end{itemize} \end{itemdescr} \indexlibrarymember{operator=}{expected}% @@ -9940,6 +9964,14 @@ This operator is defined as deleted unless \tcode{is_copy_assignable_v} is \tcode{true} and \tcode{is_copy_constructible_v} is \tcode{true}. + +%FIXME: Is this supposed to be part of the Remarks clause? +\pnum +This operator is trivial if +\tcode{is_trivially_copy_constructible_v}, +\tcode{is_trivially_copy_assigna\-ble_v}, and +\tcode{is_trivially_destructible_v} +are all \tcode{true}. \end{itemdescr} \indexlibrarymember{operator=}{expected}% @@ -9979,6 +10011,14 @@ \remarks The exception specification is equivalent to \tcode{is_nothrow_move_constructible_v \&\& is_nothrow_move_assignable_v}. + +%FIXME: Is this supposed to be part of the Remarks clause? +\pnum +This operator is trivial if +\tcode{is_trivially_move_constructible_v}, +\tcode{is_trivially_move_assigna\-ble_v}, and +\tcode{is_trivially_destructible_v} +are all \tcode{true}. \end{itemdescr} \indexlibrarymember{operator=}{expected}% From 9555e199531d6de7a8c321075601952943d92b12 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Tue, 7 Apr 2026 19:30:29 -0700 Subject: [PATCH 06/37] LWG4122 Ill-formed operator<=> can cause hard error when instantiating std::inplace_vector --- source/containers.tex | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/source/containers.tex b/source/containers.tex index 63cf29baa1..2f29bb04fb 100644 --- a/source/containers.tex +++ b/source/containers.tex @@ -10999,8 +10999,13 @@ friend constexpr bool operator==(const inplace_vector& x, const inplace_vector& y); - friend constexpr @\exposid{synth-three-way-result}@ - operator<=>(const inplace_vector& x, const inplace_vector& y); + friend constexpr auto + operator<=>(const inplace_vector& x, const inplace_vector& y) + requires requires (const T t) { @\exposid{synth-three-way}@(t, t); } + { + return lexicographical_compare_three_way(x.begin(), x.end(), y.begin(), y.end(), + @\exposid{synth-three-way}@); + } friend constexpr void swap(inplace_vector& x, inplace_vector& y) noexcept(N == 0 || (is_nothrow_swappable_v && is_nothrow_move_constructible_v)) From d323c5ad7a00c1b3676e03eba91bad9dc0cc72f5 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Tue, 7 Apr 2026 19:59:18 -0700 Subject: [PATCH 07/37] LWG4133 awaitable-receiver's members are potentially throwing --- source/exec.tex | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/source/exec.tex b/source/exec.tex index cba1458af9..65a60cae2f 100644 --- a/source/exec.tex +++ b/source/exec.tex @@ -6714,7 +6714,11 @@ Let \tcode{rcvr} be an rvalue expression of type \exposid{awaitable-receiver}, let \tcode{crcvr} be a const lvalue that refers to \tcode{rcvr}, let \tcode{vs} be a pack of subexpressions, and -let \tcode{err} be an expression of type \tcode{Err}. Then: +let \tcode{err} be an expression of type \tcode{Err}. +Let \tcode{\placeholder{MAKE-NOEXCEPT}(expr)} +for some subexpression \tcode{expr} be expression-equivalent to +\tcode{[\&] noexcept -> decltype(auto) \{ return (expr); \}()}. +Then: \begin{itemize} \item If \tcode{\libconcept{constructible_from}<\exposid{result-type}, decltype((vs))...>} @@ -6726,19 +6730,25 @@ } catch(...) { rcvr.@\exposid{result-ptr}@->template emplace<2>(current_exception()); } -rcvr.@\exposid{continuation}@.resume(); +@\placeholder{MAKE-NOEXCEPT}@(rcvr.@\exposid{continuation}@.resume()); \end{codeblock} Otherwise, \tcode{set_value(rcvr, vs...)} is ill-formed. \item The expression \tcode{set_error(rcvr, err)} is equivalent to: \begin{codeblock} -rcvr.@\exposid{result-ptr}@->template emplace<2>(@\exposid{AS-EXCEPT-PTR}@(err)); // see \ref{exec.general} -rcvr.@\exposid{continuation}@.resume(); +try { + rcvr.@\exposid{result-ptr}@->template emplace<2>(@\exposid{AS-EXCEPT-PTR}@(err)); // see \ref{exec.general} +} catch(...) { + rcvr.@\exposid{result-ptr}@->template emplace<2>(current_exception()); +} +@\placeholder{MAKE-NOEXCEPT}@(rcvr.@\exposid{continuation}@.resume()); \end{codeblock} \item The expression \tcode{set_stopped(rcvr)} is equivalent to: \begin{codeblock} -static_cast>(rcvr.@\exposid{continuation}@.promise().unhandled_stopped()).resume(); +@\placeholder{MAKE-NOEXCEPT}@( + static_cast>( + rcvr.@\exposid{continuation}@.promise().unhandled_stopped()).resume()); \end{codeblock} \item For any expression \tcode{tag} @@ -6746,7 +6756,8 @@ for any pack of subexpressions \tcode{as}, \tcode{get_env(crcvr).query(tag, as...)} is expression-equivalent to: \begin{codeblock} -tag(get_env(as_const(crcvr.@\exposid{continuation}@.promise())), as...) +tag(get_env(as_const(@\placeholder{MAKE-NOEXCEPT}@(crcvr.@\exposid{continuation}@.promise()))), + as...) \end{codeblock} \end{itemize} From 901b485f0a81f396e3bf1263983f7782404b0c5e Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Tue, 7 Apr 2026 20:24:03 -0700 Subject: [PATCH 08/37] LWG4143 execution::set_value/set_error/set_stopped/start should always return void --- source/exec.tex | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/source/exec.tex b/source/exec.tex index 65a60cae2f..e8f9f9f54c 100644 --- a/source/exec.tex +++ b/source/exec.tex @@ -1242,6 +1242,9 @@ Otherwise, it is expression-equivalent to \tcode{\exposid{MANDATE-NOTHROW}(rcvr.set_value(vs...))}. +\mandates +If the expression above is well-formed, its type is \tcode{void}. + \rSec2[exec.set.error]{\tcode{execution::set_error}} \pnum @@ -1253,6 +1256,9 @@ Otherwise, it is expression-equivalent to \tcode{\exposid{MANDATE-NOTHROW}(rcvr.set_error(err))}. +\mandates +If the expression above is well-formed, its type is \tcode{void}. + \rSec2[exec.set.stopped]{\tcode{execution::set_stopped}} \pnum @@ -1264,6 +1270,9 @@ Otherwise, it is expression-equivalent to \tcode{\exposid{MANDATE-NOTHROW}(rcvr.set_stopped())}. +\mandates +If the expression above is well-formed, its type is \tcode{void}. + \rSec1[exec.opstate]{Operation states} \rSec2[exec.opstate.general]{General} @@ -1311,6 +1320,9 @@ Otherwise, it is expression-equivalent to \tcode{\exposid{MANDATE-NOTHROW}(op.start())}. +\mandates +If the expression above is well-formed, its type is \tcode{void}. + \pnum If \tcode{op.start()} does not start\iref{exec.async.ops} the asynchronous operation associated with the operation state \tcode{op}, From 8f66474b0f0fd43d7f82d4e79df5b41c0ebd8169 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Tue, 7 Apr 2026 21:10:10 -0700 Subject: [PATCH 09/37] LWG4151 Precondition of inplace_vector::swap --- source/containers.tex | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/source/containers.tex b/source/containers.tex index 2f29bb04fb..39e04a964d 100644 --- a/source/containers.tex +++ b/source/containers.tex @@ -11423,6 +11423,26 @@ equal to the number of elements after the erased elements. \end{itemdescr} +\indexlibrarymember{swap}{inplace_vector}% +\begin{itemdecl} +constexpr void swap(inplace_vector& x) noexcept( + N == 0 || (is_nothrow_swappable_v && is_nothrow_move_constructible_v)); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{T} meets the \oldconcept{MoveConstructible} requirements. +Let $M$ be \tcode{min(size(), x.size())}. +For each non-negative integer $n < M$, +\tcode{(*this)[$n$]} is swappable +with \tcode{x[$n$]}\iref{swappable.requirements}. + +\pnum +\effects +Exchanges the contents of \tcode{*this} and \tcode{x}. +\end{itemdescr} + \rSec3[inplace.vector.erasure]{Erasure} \indexlibrarymember{erase}{inplace_vector}% From ca72aacfb9f2fca2bc37ed38b8450ab3132c7050 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Tue, 7 Apr 2026 22:09:44 -0700 Subject: [PATCH 10/37] LWG4223 Deduction guides for maps are mishandling tuples and references --- source/containers.tex | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/source/containers.tex b/source/containers.tex index 39e04a964d..91032de5d8 100644 --- a/source/containers.tex +++ b/source/containers.tex @@ -11497,24 +11497,25 @@ template using @\placeholder{iter-value-type}@ = iterator_traits::value_type; // \expos template - using @\placeholder{iter-key-type}@ = remove_const_t< + using @\placeholder{iter-key-type}@ = remove_cvref_t< tuple_element_t<0, @\exposid{iter-value-type}@>>; // \expos template - using @\placeholder{iter-mapped-type}@ = - tuple_element_t<1, @\exposid{iter-value-type}@>; // \expos + using @\placeholder{iter-mapped-type}@ = remove_cvref_t< + tuple_element_t<1, @\exposid{iter-value-type}@>>; // \expos template using @\placeholder{iter-to-alloc-type}@ = pair< - const tuple_element_t<0, @\exposid{iter-value-type}@>, - tuple_element_t<1, @\exposid{iter-value-type}@>>; // \expos + const @\exposid{iter-key-type}@, + @\exposid{iter-mapped-type}@>; // \expos template using @\exposid{range-key-type}@ = - remove_const_t::first_type>; // \expos + remove_cvref_t>>; // \expos template - using @\exposid{range-mapped-type}@ = ranges::range_value_t::second_type; // \expos + using @\exposid{range-mapped-type}@ = + remove_cvref_t>>; // \expos template using @\exposid{range-to-alloc-type}@ = - pair::first_type, - typename ranges::range_value_t::second_type>; // \expos + pair, + @\exposid{range-mapped-type}@>; // \expos \end{codeblock} \rSec2[associative.map.syn]{Header \tcode{} synopsis} From 0514f2fc5f9efce32720534fdbf1b8302c85f132 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Tue, 7 Apr 2026 22:46:32 -0700 Subject: [PATCH 11/37] LWG4314 Missing move in mdspan layout mapping::operator() --- source/containers.tex | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/source/containers.tex b/source/containers.tex index 91032de5d8..1cc81efa3e 100644 --- a/source/containers.tex +++ b/source/containers.tex @@ -21512,7 +21512,7 @@ If \tcode{remove_cvref_t} is an integral type other than \tcode{bool}, then equivalent to \tcode{return i;}, \item -otherwise, equivalent to \tcode{return static_cast(i);}. +otherwise, equivalent to \tcode{return static_cast(std::forward(\brk{}i));}. \end{itemize} \begin{note} This function will always return an integral type other than \tcode{bool}. @@ -22459,7 +22459,7 @@ is \tcode{true}. Equivalent to: \begin{codeblock} -return ((static_cast(i) * stride(P)) + ... + 0); +return ((static_cast(std::move(i)) * stride(P)) + ... + 0); \end{codeblock} \end{itemdescr} @@ -22792,7 +22792,7 @@ \end{codeblock} is \tcode{true}. Equivalent to: \begin{codeblock} -return ((static_cast(i) * stride(P)) + ... + 0); +return ((static_cast(std::move(i)) * stride(P)) + ... + 0); \end{codeblock} \end{itemdescr} @@ -23156,7 +23156,7 @@ is \tcode{true}. Equivalent to: \begin{codeblock} -return ((static_cast(i) * stride(P)) + ... + 0); +return ((static_cast(std::move(i)) * stride(P)) + ... + 0); \end{codeblock} \end{itemdescr} @@ -23471,10 +23471,14 @@ \indexlibraryctor{layout_left_padded::mapping}% \begin{itemdecl} template -constexpr mapping(const extents_type& ext, OtherIndexType pad); +constexpr mapping(const extents_type& ext, OtherIndexType padding); \end{itemdecl} \begin{itemdescr} +\pnum +Let \tcode{pad} be +\tcode{extents_type::\exposid{index-cast}(std::move(padding))}. + \pnum \constraints \begin{itemize} @@ -23490,7 +23494,7 @@ \item \tcode{pad} is representable as a value of type \tcode{index_type}. \item -\tcode{extents_type::\exposid{index-cast}(pad)} is greater than zero. +\tcode{pad} is greater than zero. \item If \exposid{rank_} is greater than one, then \tcode{\exposid{LEAST-MULTIPLE-AT-LEAST}(pad, ext.extent(0))} @@ -23504,7 +23508,7 @@ is representable as a value of type \tcode{index_type}. \item If \tcode{padding_value} is not equal to \tcode{dynamic_extent}, -\tcode{padding_value} equals \tcode{extents_type::\exposid{in\-dex-cast}(pad)}. +\tcode{padding_value} equals \tcode{pad}. \end{itemize} \pnum @@ -23781,7 +23785,7 @@ \pnum \returns -\tcode{((static_cast(idxs) * stride(P_rank)) + ... + 0)}. +\tcode{((static_cast(std::move(idxs)) * stride(P_rank)) + ... + 0)}. \end{itemdescr} \begin{itemdecl} @@ -24108,10 +24112,14 @@ \indexlibraryctor{layout_right_padded::mapping}% \begin{itemdecl} template -constexpr mapping(const extents_type& ext, OtherIndexType pad); +constexpr mapping(const extents_type& ext, OtherIndexType padding); \end{itemdecl} \begin{itemdescr} +\pnum +Let \tcode{pad} be +\tcode{extents_type::\exposid{index-cast}(std::move(padding))}. + \pnum \constraints \begin{itemize} @@ -24127,7 +24135,7 @@ \item \tcode{pad} is representable as a value of type \tcode{index_type}. \item -\tcode{extents_type::\exposid{index-cast}(pad)} is greater than zero. +\tcode{pad} is greater than zero. \item If \exposid{rank_} is greater than one, then \tcode{\exposid{LEAST-MULTIPLE-AT-LEAST}(pad, ext.extent(\exposid{rank_} - 1))} @@ -24141,7 +24149,7 @@ is representable as a value of type \tcode{index_type}. \item If \tcode{padding_value} is not equal to \tcode{dynamic_extent}, -\tcode{padding_value} equals \tcode{extents_type::\linebreak \exposid{index-cast}(pad)}. +\tcode{padding_value} equals \tcode{pad}. \end{itemize} \pnum @@ -24416,7 +24424,7 @@ \pnum \returns -\tcode{((static_cast(idxs) * stride(P_rank)) + ... + 0)}. +\tcode{((static_cast(std::move(idxs)) * stride(P_rank)) + ... + 0)}. \end{itemdescr} \indexlibrarymember{layout_right_padded::mapping}{is_always_exhaustive}% From 9ad14eb9d3f0fd75586e0d5499f4a87987200bdd Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Tue, 7 Apr 2026 22:51:48 -0700 Subject: [PATCH 12/37] LWG4325 std::indirect's operator== still does not support incomplete types --- source/memory.tex | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source/memory.tex b/source/memory.tex index eb7c889a51..5b1e26c961 100644 --- a/source/memory.tex +++ b/source/memory.tex @@ -6566,7 +6566,7 @@ \begin{itemdecl} template constexpr bool operator==(const indirect& lhs, const indirect& rhs) - noexcept(noexcept(*lhs == *rhs)); + noexcept(noexcept(bool(*lhs == *rhs))); \end{itemdecl} \begin{itemdescr} @@ -6605,7 +6605,8 @@ %FIXME: "friend" included on declaration in synopsis but not here. \begin{itemdecl} template - constexpr bool operator==(const indirect& lhs, const U& rhs) noexcept(noexcept(*lhs == rhs)); + constexpr bool operator==(const indirect& lhs, const U& rhs) + noexcept(noexcept(bool(*lhs == rhs))); \end{itemdecl} \begin{itemdescr} From 1be5f6e70a0aa0db02e2023b2da019ab698d49de Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Tue, 7 Apr 2026 23:39:42 -0700 Subject: [PATCH 13/37] LWG4339 task's coroutine frame may be released late Fixes NB US 242-372 (C++26 CD). --- source/exec.tex | 43 ++++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/source/exec.tex b/source/exec.tex index e8f9f9f54c..a3b327d8f2 100644 --- a/source/exec.tex +++ b/source/exec.tex @@ -7404,6 +7404,8 @@ remove_cvref_t @\exposidnc{rcvr}@; // \expos @\exposidnc{own-env-t}@ @\exposidnc{own-env}@; // \expos Environment @\exposidnc{environment}@; // \expos + optional @\exposidnc{result}@; // \expos; present only if \tcode{is_void_v} is \tcode{false} + exception_ptr @\exposidnc{error}@; // \expos }; } \end{codeblock} @@ -7532,8 +7534,6 @@ allocator_type @\exposidnc{alloc}@; // \expos stop_source_type @\exposidnc{source}@; // \expos stop_token_type @\exposidnc{token}@; // \expos - optional @\exposidnc{result}@; // \expos; present only if \tcode{is_void_v} is \tcode{false} - @\exposidnc{error-variant}@ @\exposidnc{errors}@; // \expos }; } \end{codeblock} @@ -7550,13 +7550,6 @@ during evaluation of \tcode{task::\exposid{state}::start} for some receiver \tcode{Rcvr}. -\pnum -\exposid{error-variant} is a \tcode{variant...>}, with duplicate types removed, where \tcode{E...} -are the parameter types of the template arguments of the specialization of -\tcode{execution::completion_signatures} denoted by -\tcode{error_types}. - \indexlibraryctor{task::promise_type}% \begin{itemdecl} template @@ -7596,17 +7589,19 @@ \returns An awaitable object of unspecified type\iref{expr.await} whose member functions arrange for the completion of the asynchronous -operation associated with \tcode{\exposid{STATE}(*this)} by invoking: +operation associated with \tcode{\exposid{STATE}(*this)}. +Let \tcode{st} be a reference to \tcode{\exposid{STATE}(*this)}. +The asynchronous completion first destroys the coroutine frame +using \tcode{st.\exposid{handle}.destroy()} and then invokes: \begin{itemize} \item -\tcode{set_error(std::move(\exposid{RCVR}(*this)), std::move(e))} -if \tcode{\exposid{errors}.index()} is greater than zero and -\tcode{e} is the value held by \exposid{errors}, otherwise +\tcode{set_error(std::move(st.\exposid{rcvr}), std::move(st.\exposid{error}))} +if \tcode{bool(st.\exposid{error})} is \tcode{true}, otherwise \item -\tcode{set_value(std::move(\exposid{RCVR}(*this)))} if \tcode{is_void} is \tcode{true}, +\tcode{set_value(std::move(st.\exposid{rcvr}))} if \tcode{is_void_v} is \tcode{true}, and otherwise \item - \tcode{set_value(std::move(\exposid{RCVR}(*this)), std::move(*\exposid{result}))}. + \tcode{set_value(std::move(st.\exposid{rcvr}), *std::move(st.\exposid{result}))}. \end{itemize} \end{itemdescr} @@ -7627,7 +7622,12 @@ An awaitable object of unspecified type\iref{expr.await} whose member functions arrange for the calling coroutine to be suspended and then completes the asynchronous operation associated with -\tcode{\exposid{STATE}(*this)} by invoking \tcode{set_error(std::move(\exposid{RCVR}(*this)), +\tcode{\exposid{STATE}(*this)}. +Let \tcode{st} be a reference to \tcode{\exposid{STATE}(*this)}. +Then the asynchronous operation completes by first +destroying the coroutine frame using \tcode{st.\exposid{handle}.destroy()} +and then invoking +\tcode{set_error(std::move(st.\exposid{rcvr}), \placeholder{Cerr}(std::move(err.error)))}. \end{itemdescr} @@ -7668,7 +7668,8 @@ \effects If the signature \tcode{set_error_t(exception_ptr)} is not an element of \tcode{error_types}, calls \tcode{terminate()}\iref{except.terminate}. -Otherwise, stores \tcode{current_exception()} into \exposid{errors}. +Otherwise, stores \tcode{current_exception()} into +\tcode{\exposid{STATE}(*this).\exposid{error}}. \end{itemdescr} \indexlibrarymember{unhandled_stopped}{task::promise_type}% @@ -7678,8 +7679,12 @@ \begin{itemdescr} \pnum \effects -Completes the asynchronous operation associated with \tcode{\exposid{STATE}(*this)} -by invoking \tcode{set_stopped(std::move(\exposid{RCVR}(*this)))}. +Completes the asynchronous operation associated with \tcode{\exposid{STATE}(*this)}. +Let \tcode{st} be a reference to \tcode{\exposid{STATE}(*this)}. +The asynchronous operation is completed by first +destroying the coroutine frame +using \tcode{st.\exposid{handle}.destroy()} and then +invoking \tcode{set_stopped(std::move(st.\exposid{rcvr}))}. \end{itemdescr} \begin{itemdescr} \pnum From c4ccbb252f9f3f7725fa8bbc70a4891a4878afff Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Wed, 8 Apr 2026 01:15:43 -0700 Subject: [PATCH 14/37] LWG4347 task's stop source is always created Fixes NB US 257-382 (C++26 CD). [task.state]p5 Didn't insert a new paragraph (text belongs with the \effects clause). --- source/exec.tex | 46 ++++++++++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/source/exec.tex b/source/exec.tex index a3b327d8f2..c9fe0fd363 100644 --- a/source/exec.tex +++ b/source/exec.tex @@ -7398,10 +7398,13 @@ void start() & noexcept; + stop_token_type @\exposidnc{get-stop-token}@(); // \expos + private: using @\exposidnc{own-env-t}@ = @\seebelownc@; // \expos coroutine_handle @\exposidnc{handle}@; // \expos remove_cvref_t @\exposidnc{rcvr}@; // \expos + optional @\exposidnc{source}@; // \expos @\exposidnc{own-env-t}@ @\exposidnc{own-env}@; // \expos Environment @\exposidnc{environment}@; // \expos optional @\exposidnc{result}@; // \expos; present only if \tcode{is_void_v} is \tcode{false} @@ -7471,24 +7474,32 @@ if that expression is valid and \tcode{scheduler_type()} otherwise. If neither of these expressions is valid, the program is ill-formed. \end{itemize} -Let \tcode{\placeholder{st}} be \tcode{get_stop_token(get_env(\exposid{rcvr}))}. -Initializes \tcode{\placeholder{prom}.\exposid{token}} and -\tcode{\placeholder{prom}.\exposid{source}} such that +After that invokes \tcode{\exposid{handle}.resume()}. +\end{itemdescr} + +\indexlibrarymember{\exposid{get-stop-token}}{task::\exposid{state}}% +\begin{itemdecl} +stop_token_type @\exposidnc{get-stop-token}@(); // \expos +\end{itemdecl} +\begin{itemdescr} +\pnum +\effects +If +\tcode{\libconcept{same_as}().get_token()), decltype(get_\linebreak{}stop_token(get_env(\exposid{rcvr})))>} +is \tcode{true} +returns \tcode{get_stop_token(get_env(\exposid{rcvr}))}. +Otherwise, if \tcode{\exposid{source}.has_value()} is \tcode{false}, +initializes the contained value of \exposid{source} such that \begin{itemize} \item -\tcode{\placeholder{prom}.\exposid{token}.stop_requested()} returns -\tcode{\placeholder{st}.stop_requested()}; -\item -\tcode{\placeholder{prom}.\exposid{token}.stop_possible()} returns -\tcode{\placeholder{st}.stop_possible()}; and +\tcode{\exposid{source}->stop_requested()} returns +\tcode{get_stop_token(get_env(\exposid{rcvr}))->stop_requested()};\linebreak +and \item -for types \tcode{Fn} and \tcode{Init} such that both -\tcode{\libconcept{invocable}} and -\tcode{\libconcept{constructible_from}} are modeled, -\tcode{stop_token_type::callback_type} models -\tcode{\exposconcept{stoppable-callback-for}}. +\tcode{\exposid{source}->stop_possible()} returns +\tcode{get_stop_token(get_env(\exposid{rcvr}))->stop_possible()}. \end{itemize} -After that invokes \tcode{\exposid{handle}.resume()}. +Finally, returns \tcode{\exposid{source}->get_token()}. \end{itemdescr} \rSec3[task.promise]{Class \tcode{task::promise_type}} @@ -7532,8 +7543,6 @@ using @\exposidnc{error-variant}@ = @\seebelownc@; // \expos allocator_type @\exposidnc{alloc}@; // \expos - stop_source_type @\exposidnc{source}@; // \expos - stop_token_type @\exposidnc{token}@; // \expos }; } \end{codeblock} @@ -7724,10 +7733,11 @@ \begin{itemize} \item \tcode{env.query(get_scheduler)} returns \tcode{scheduler_type(\exposid{SCHED}(*this))}. \item \tcode{env.query(get_allocator)} returns \exposid{alloc}. -\item \tcode{env.query(get_stop_token)} returns \exposid{token}. +\item \tcode{env.query(get_stop_token)} returns +\tcode{\exposid{STATE}(*this).\exposid{get-stop-token}()}. \item For any other query \tcode{q} and arguments \tcode{a...} a call to \tcode{env.query(q, a...)} returns -\tcode{\exposid{STATE}(*this)}. \tcode{environment.query(q, a...)} if this expression +\tcode{\exposid{STATE}(*this)}. \tcode{\exposid{environment}.query(q, a...)} if this expression is well-formed and \tcode{forwarding_query(q)} is well-formed and is \tcode{true}. Otherwise \tcode{env.query(q, a...)} is ill-formed. \end{itemize} From e85c4b0273e0e6f96f3d34e2b646d3a1fd33a54b Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Wed, 8 Apr 2026 01:37:15 -0700 Subject: [PATCH 15/37] LWG4354 Reconsider weakly_parallel as the default forward_progress_guarantee --- source/exec.tex | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/source/exec.tex b/source/exec.tex index c9fe0fd363..0775b24a47 100644 --- a/source/exec.tex +++ b/source/exec.tex @@ -1007,16 +1007,12 @@ \tcode{get_forward_progress_guarantee} is ill-formed. Otherwise, \tcode{get_forward_progress_guarantee(sch)} is expression-equivalent to: -\begin{itemize} -\item -\tcode{\exposid{MANDATE-NOTHROW}(\exposid{AS-CONST}(sch).query(get_forward_progress_guarantee))}, -if that expression is well-formed. +\begin{codeblock} +@\exposid{MANDATE-NOTHROW}@(@\exposid{AS-CONST}@(sch).query(get_forward_progress_guarantee)) +\end{codeblock} \mandates The type of the expression above is \tcode{forward_progress_guarantee}. -\item -Otherwise, \tcode{forward_progress_guarantee::weakly_parallel}. -\end{itemize} \pnum If \tcode{get_forward_progress_guarantee(sch)} for some scheduler \tcode{sch} @@ -1111,6 +1107,7 @@ @\exposconcept{queryable}@ && requires(Sch&& sch) { { schedule(std::forward(sch)) } -> @\libconcept{sender}@; + { get_forward_progress_guarantee(sch) } -> @\libconcept{same_as}@; { auto(get_completion_scheduler( get_env(schedule(std::forward(sch))))) } -> @\libconcept{same_as}@>; From c8b37c1d61e90ab8d2e11eda42ef3f7abf19ca57 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Wed, 8 Apr 2026 16:41:27 -0700 Subject: [PATCH 16/37] LWG4361 awaitable-receiver::set_value should use Mandates instead of constraints --- source/exec.tex | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/source/exec.tex b/source/exec.tex index 0775b24a47..153651578f 100644 --- a/source/exec.tex +++ b/source/exec.tex @@ -1805,19 +1805,16 @@ static constexpr const auto& @\exposidnc{complete}@ = @\exposidnc{impls-for}@<@\exposidnc{tag-t}@>::@\exposidnc{complete}@; // \expos template - requires @\exposconcept{callable}@ void set_value(Args&&... args) && noexcept { @\exposid{complete}@(Index(), @\exposidnc{op}@->@\exposid{state}@, @\exposidnc{op}@->@\exposid{rcvr}@, set_value_t(), std::forward(args)...); } template - requires @\exposconcept{callable}@ void set_error(Error&& err) && noexcept { @\exposid{complete}@(Index(), @\exposidnc{op}@->@\exposid{state}@, @\exposidnc{op}@->@\exposid{rcvr}@, set_error_t(), std::forward(err)); } void set_stopped() && noexcept - requires @\exposconcept{callable}@ { @\exposid{complete}@(Index(), @\exposidnc{op}@->@\exposid{state}@, @\exposidnc{op}@->@\exposid{rcvr}@, set_stopped_t()); } @@ -6730,9 +6727,7 @@ Then: \begin{itemize} \item -If \tcode{\libconcept{constructible_from}<\exposid{result-type}, decltype((vs))...>} -is satisfied, -the expression \tcode{set_value(\newline rcvr, vs...)} is equivalent to: +The expression \tcode{set_value(rcvr, vs...)} is equivalent to: \begin{codeblock} try { rcvr.@\exposid{result-ptr}@->template emplace<1>(vs...); @@ -6741,7 +6736,10 @@ } @\placeholder{MAKE-NOEXCEPT}@(rcvr.@\exposid{continuation}@.resume()); \end{codeblock} -Otherwise, \tcode{set_value(rcvr, vs...)} is ill-formed. + +\mandates +\tcode{\libconcept{constructible_from}<\exposid{result-type}, decltype((vs))...>} +is satisfied. \item The expression \tcode{set_error(rcvr, err)} is equivalent to: \begin{codeblock} From 6fe0756c23e4e29debeb2d6456ca8e4500f2950a Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Wed, 8 Apr 2026 17:34:00 -0700 Subject: [PATCH 17/37] LWG4379 hive::reserve() needs Throws: element adjusted to match block min/max considerations Fixes NB US 142-236 (C++26 CD). --- source/containers.tex | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/containers.tex b/source/containers.tex index 1cc81efa3e..55aae3849a 100644 --- a/source/containers.tex +++ b/source/containers.tex @@ -8478,7 +8478,9 @@ \pnum \throws -\tcode{length_error} if \tcode{n > max_size()}, +\tcode{length_error} if +satisfying the postcondition +would cause \tcode{capacity()} to exceed \tcode{max_size()}, as well as any exceptions thrown by the allocator. \pnum From 1743833a77b88b6f9966e7e0ad4674de98f46364 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Wed, 8 Apr 2026 18:24:17 -0700 Subject: [PATCH 18/37] LWG4476 run_loop should not have a set_error completion --- source/exec.tex | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/source/exec.tex b/source/exec.tex index 153651578f..056fb0c09d 100644 --- a/source/exec.tex +++ b/source/exec.tex @@ -6392,7 +6392,7 @@ class @\exposid{run-loop-scheduler}@; // \expos class @\exposid{run-loop-sender}@; // \expos struct @\exposid{run-loop-opstate-base}@ { // \expos - virtual void @\exposid{execute}@() = 0; // \expos + virtual void @\exposid{execute}@() noexcept = 0; // \expos run_loop* @\exposid{loop}@; // \expos @\exposid{run-loop-opstate-base}@* @\exposid{next}@; // \expos }; @@ -6400,8 +6400,8 @@ using @\exposid{run-loop-opstate}@ = @\unspec@; // \expos // \ref{exec.run.loop.members}, member functions - @\exposid{run-loop-opstate-base}@* @\exposid{pop-front}@(); // \expos - void @\exposid{push-back}@(@\exposid{run-loop-opstate-base}@*); // \expos + @\exposid{run-loop-opstate-base}@* @\exposid{pop-front}@() noexcept; // \expos + void @\exposid{push-back}@(@\exposid{run-loop-opstate-base}@*) noexcept; // \expos public: // \ref{exec.run.loop.ctor}, constructor and destructor @@ -6410,9 +6410,9 @@ ~run_loop(); // \ref{exec.run.loop.members}, member functions - @\exposid{run-loop-scheduler}@ get_scheduler(); - void run(); - void finish(); + @\exposid{run-loop-scheduler}@ get_scheduler() noexcept; + void run() noexcept; + void finish() noexcept; }; } \end{codeblock} @@ -6512,11 +6512,7 @@ \item The expression \tcode{start($o$)} is equivalent to: \begin{codeblock} -try { - @$o$@.@\exposid{loop}@->@\exposid{push-back}@(addressof(@$o$@)); -} catch(...) { - set_error(std::move(@\exposid{REC}@(@$o$@)), current_exception()); -} +@$o$@.@\exposid{loop}@->@\exposid{push-back}@(addressof(@$o$@)); \end{codeblock} \end{itemize} @@ -6551,7 +6547,7 @@ \rSec3[exec.run.loop.members]{Member functions} \begin{itemdecl} -@\exposid{run-loop-opstate-base}@* @\exposid{pop-front}@(); +@\exposid{run-loop-opstate-base}@* @\exposid{pop-front}@() noexcept; \end{itemdecl} \begin{itemdescr} @@ -6572,7 +6568,7 @@ \end{itemdescr} \begin{itemdecl} -void @\exposid{push-back}@(@\exposid{run-loop-opstate-base}@* item); +void @\exposid{push-back}@(@\exposid{run-loop-opstate-base}@* item) noexcept; \end{itemdecl} \begin{itemdescr} @@ -6589,7 +6585,7 @@ \indexlibrarymember{get_scheduler}{run_loop}% \begin{itemdecl} -@\exposid{run-loop-scheduler}@ get_scheduler(); +@\exposid{run-loop-scheduler}@ get_scheduler() noexcept; \end{itemdecl} \begin{itemdescr} @@ -6601,7 +6597,7 @@ \indexlibrarymember{run}{run_loop}% \begin{itemdecl} -void run(); +void run() noexcept; \end{itemdecl} \begin{itemdescr} @@ -6629,7 +6625,7 @@ \indexlibrarymember{finish}{run_loop}% \begin{itemdecl} -void finish(); +void finish() noexcept; \end{itemdecl} \begin{itemdescr} From 073a3ed00244ce8c93a92f98df3159c3625e1f50 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Wed, 8 Apr 2026 18:37:11 -0700 Subject: [PATCH 19/37] LWG4478 meta::has_identifier is not specified for annotations --- source/meta.tex | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/meta.tex b/source/meta.tex index b2a168331b..6486f625ac 100644 --- a/source/meta.tex +++ b/source/meta.tex @@ -3905,10 +3905,12 @@ Otherwise, if \tcode{r} represents a direct base class relationship, then \tcode{has_identifier(type_of(r))}. \item - Otherwise, \tcode{r} represents a data member description + Otherwise, if \tcode{r} represents a data member description $(T, N, A, W, \mathit{NUA})$\iref{class.mem.general}; \tcode{true} if $N$ is not $\bot$. Otherwise, \tcode{false}. +\item + Otherwise, \tcode{false}. \end{itemize} \end{itemdescr} From c2be2beb25eb55a94c192dae6273c207131166c9 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Wed, 8 Apr 2026 19:58:12 -0700 Subject: [PATCH 20/37] LWG4485 Move specification for task::stop_token_type Fixes NB US 249-379 (C++26 CD). --- source/exec.tex | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source/exec.tex b/source/exec.tex index 056fb0c09d..43eea67914 100644 --- a/source/exec.tex +++ b/source/exec.tex @@ -7298,8 +7298,9 @@ \tcode{set_error_t(E)} for some type \tcode{E}. \pnum -\tcode{allocator_type} shall meet the \oldconcept{Allocator} -requirements. +\tcode{allocator_type} shall meet the \oldconcept{Allocator} requirements, +\tcode{scheduler_type} shall model \libconcept{scheduler}, and +\tcode{stop_source_type} shall model \exposconcept{stoppable-source}. \rSec3[task.members]{\tcode{task} members} From 140c4a06f751493a84a1e59cfce5ba9da399ebb7 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Wed, 8 Apr 2026 20:07:06 -0700 Subject: [PATCH 21/37] LWG4497 std::nullopt_t should be comparable --- source/utilities.tex | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/source/utilities.tex b/source/utilities.tex index c92ab2e45b..ef56bc81b8 100644 --- a/source/utilities.tex +++ b/source/utilities.tex @@ -5071,7 +5071,11 @@ this indicates that an optional object not containing a value shall be constructed. \pnum -Type \tcode{nullopt_t} shall not have a default constructor or an initializer-list constructor, and shall not be an aggregate. +Type \tcode{nullopt_t} does not have +a default constructor or an initializer-list constructor, and +is not an aggregate. +\tcode{nullopt_t} models \libconcept{copyable} and +\tcode{\libconcept{three_way_comparable}}. \rSec2[optional.bad.access]{Class \tcode{bad_optional_access}} From 0922696891495430f5240d17638814c643dce14d Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Wed, 8 Apr 2026 20:13:03 -0700 Subject: [PATCH 22/37] LWG4504 Wording problem in {simple_}counting_scope --- source/exec.tex | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/source/exec.tex b/source/exec.tex index 43eea67914..11e56dad46 100644 --- a/source/exec.tex +++ b/source/exec.tex @@ -8296,12 +8296,11 @@ \begin{itemdescr} \pnum \effects -If \exposid{state} is +If \tcode{count} is zero, then +changes \exposid{state} to \exposid{joined} and returns \tcode{true}. +Otherwise, if \exposid{state} is \begin{itemize} \item -\exposid{unused}, \exposid{unused-and-closed}, or \exposid{joined}, then -changes \exposid{state} to \exposid{joined} and returns \tcode{true}; -\item \exposid{open} or \exposid{open-and-joining}, then changes \exposid{state} to \exposid{open-and-joining}, registers \tcode{st} with \tcode{*this} and returns \tcode{false}; From 415d2accda703c3cc5769dd33172be45059760e2 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Wed, 8 Apr 2026 20:42:22 -0700 Subject: [PATCH 23/37] LWG4506 source_location is explicitly unspecified if is constexpr or not --- source/support.tex | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/source/support.tex b/source/support.tex index ce4a1c9271..4f8c4bbad2 100644 --- a/source/support.tex +++ b/source/support.tex @@ -3625,6 +3625,9 @@ static consteval source_location current() noexcept; constexpr source_location() noexcept; + constexpr source_location(const source_location&) noexcept = default; + constexpr source_location& operator=(const source_location&) noexcept = default; + // source location field access constexpr uint_least32_t line() const noexcept; constexpr uint_least32_t column() const noexcept; @@ -3641,25 +3644,14 @@ \end{codeblock} \pnum -The type \tcode{source_location} meets the -\oldconcept{DefaultConstructible}, -\oldconcept{CopyConstructible}, -\oldconcept{Copy\-Assignable}, -\oldconcept{Swappable}, and -\oldconcept{Destructible} -requirements\iref{utility.arg.requirements,swappable.requirements}. -All of the following conditions are \tcode{true}: -\begin{itemize} -\item \tcode{is_nothrow_move_constructible_v} -\item \tcode{is_nothrow_move_assignable_v} -\item \tcode{is_nothrow_swappable_v} -\end{itemize} +The type \tcode{source_location} models \libconcept{semiregular}. +\tcode{is_nothrow_swappable_v} is \tcode{true}. \begin{note} The intent of \tcode{source_location} is to have a small size and efficient copying. It is unspecified whether the copy/move constructors and the copy/move assignment operators -are trivial and/or constexpr. +are trivial. \end{note} \pnum From bc841ac4c4a4b5d445f710d6eb331e4a261ffe6e Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Wed, 8 Apr 2026 22:53:41 -0700 Subject: [PATCH 24/37] LWG4532 Imprecise std::polymorphic wording seems to imply slicing --- source/memory.tex | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/source/memory.tex b/source/memory.tex index 5b1e26c961..758104f9a4 100644 --- a/source/memory.tex +++ b/source/memory.tex @@ -6930,8 +6930,9 @@ considering that owned object as an rvalue. Otherwise, if \tcode{\exposid{alloc} != other.\exposid{alloc}} is \tcode{true}, -constructs an object of type \tcode{polymorphic}, -considering the owned object in \tcode{other} as an rvalue, +constructs an owned object of type \tcode{U}, +where \tcode{U} is the type of the owned object in \tcode{other}, +with the owned object in \tcode{other} as an rvalue, using the allocator \exposid{alloc}. \end{itemdescr} @@ -7128,7 +7129,10 @@ \pnum \effects If \tcode{*this} is not valueless, -destroys the owned object using \tcode{allocator_traits::de\-stroy} and +calls \tcode{allocator_traits::destroy(p)}, +where \tcode{p} is a pointer of type \tcode{U*} to +the owned object and +\tcode{U} is the type of the owned object; then the storage is deallocated. \end{itemdescr} @@ -7160,7 +7164,9 @@ \item If \tcode{other} is not valueless, -a new owned object is constructed in \tcode{*this} using +a new owned object of type \tcode{U}, +where \tcode{U} is the type of the owned object in \tcode{other}, +is constructed in \tcode{*this} using \tcode{allocator_traits::construct} with the owned object from \tcode{other} as the argument, using either the allocator in \tcode{*this} or @@ -7226,7 +7232,9 @@ \item Otherwise, -constructs a new owned object with the owned object of +constructs a new owned object of type \tcode{U}, +where \tcode{U} is the type of the owned object in \tcode{other}, +with the owned object of \tcode{other} as the argument as an rvalue, using the allocator in \tcode{*this}. From 8336444cd900c6fff17b7b9cf6bc2fa4d3b6e2e6 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Wed, 8 Apr 2026 23:54:15 -0700 Subject: [PATCH 25/37] LWG4533 not_fn is unimplementable --- source/utilities.tex | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/source/utilities.tex b/source/utilities.tex index ef56bc81b8..0d52de611a 100644 --- a/source/utilities.tex +++ b/source/utilities.tex @@ -11792,19 +11792,20 @@ A \defnadj{callable}{object} is an object of a callable type. \pnum -A \defnx{call wrapper type}{call wrapper!type} is a type that holds a callable object -and supports a call operation that forwards to that object. +A \defnx{call wrapper type}{call wrapper!type} is a type that holds +a \defnadj{target}{object}, +which is either +a callable object or +an object representing a callable object, +and supports a call operation that forwards to that callable object. \pnum A \defn{call wrapper} is an object of a call wrapper type. -\pnum -A \defn{target object} is the callable object held by a call wrapper. - \pnum A call wrapper type may additionally hold a sequence of objects and references -that may be passed as arguments to the target object. +that may be passed as arguments to the callable object. These entities are collectively referred to as \defnx{bound argument entities}{bound argument entity}. @@ -13502,9 +13503,9 @@ \pnum \returns -A perfect forwarding call wrapper\iref{func.require} \tcode{g} that -does not have state entities, and -has the call pattern \tcode{!invoke(f, call_args...)}. +A perfect forwarding call wrapper\iref{func.require} \tcode{g} +whose target object is a copy of \tcode{cw}, and +whose call pattern is \tcode{!invoke(f, call_args...)}. \end{itemdescr} \rSec2[func.bind.partial]{Function templates \tcode{bind_front} and \tcode{bind_back}} @@ -13624,8 +13625,9 @@ \pnum \returns -A perfect forwarding call wrapper\iref{func.require} \tcode{g} that -does not have a target object, and has the call pattern: +A perfect forwarding call wrapper\iref{func.require} \tcode{g} +whose target object is a copy of \tcode{cw}, and +whose call pattern is: \begin{itemize} \item \tcode{invoke(f, bound_args..., call_args...)} From b36dfac3ff58e09caa819c048ac4da5e7be4cdec Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Thu, 9 Apr 2026 00:09:41 -0700 Subject: [PATCH 26/37] LWG4537 Improve define_static_array --- source/meta.tex | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/source/meta.tex b/source/meta.tex index 6486f625ac..aca94502c9 100644 --- a/source/meta.tex +++ b/source/meta.tex @@ -2932,7 +2932,7 @@ template consteval const ranges::range_value_t* define_static_string(R&& r); template - consteval span> define_static_array(R&& r); + consteval span, \seebelow> define_static_array(R&& r); template consteval const remove_cvref_t* define_static_object(T&& r); } @@ -3514,7 +3514,7 @@ \indexlibraryglobal{define_static_array}% \begin{itemdecl} template - consteval span> define_static_array(R&& r); + consteval span, \seebelow> define_static_array(R&& r); \end{itemdecl} \begin{itemdescr} @@ -3525,10 +3525,18 @@ using T = ranges::range_value_t; meta::info array = meta::reflect_constant_array(r); if (meta::is_array_type(meta::type_of(array))) { - return span(meta::extract(array), meta::extent(meta::type_of(array))); + return span(meta::extract(array), + meta::extent(meta::type_of(array))); } else { - return span(); + return span(static_cast(nullptr), 0); } + +\pnum +\remarks +The second template argument of the returned \tcode{span} type +is \tcode{static_cast(ranges::size(r))} +if \tcode{ranges::size(r)} is a constant expression, and +\tcode{dynamic_extent} otherwise. \end{codeblock} \end{itemdescr} From 4ae4a80f95894b775802ffea1561efb8fe86d6e4 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Thu, 9 Apr 2026 03:36:06 -0700 Subject: [PATCH 27/37] LWG4540 future-senders returned from spawn_future do not forward stop requests to spawned work [exec.spawn.future] "receiver" in struct "future-operation" renamed to "receiverx" due to concept of same name. --- source/exec.tex | 166 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 158 insertions(+), 8 deletions(-) diff --git a/source/exec.tex b/source/exec.tex index 11e56dad46..91ba65006f 100644 --- a/source/exec.tex +++ b/source/exec.tex @@ -5313,6 +5313,18 @@ are not satisfied, the expression \tcode{spawn_future(sndr, token, env)} is ill-formed. +\pnum +Let \exposid{try-cancelable} be the exposition-only class: + +\indexlibraryglobal{execution::\exposid{try-cancelable}}% +\begin{codeblock} +namespace std::execution { + struct @\exposid{try-cancelable}@ { // \expos + virtual void @\exposid{try-cancel}@() noexcept = 0; // \expos + }; +} +\end{codeblock} + \pnum Let \exposid{spawn-future-state-base} be the exposition-only class template: @@ -5323,7 +5335,8 @@ struct @\exposid{spawn-future-state-base}@; // \expos template - struct @\exposid{spawn-future-state-base}@> { // \expos + struct @\exposid{spawn-future-state-base}@> // \expos + : @\exposid{try-cancelable}@ { using @\exposid{variant-t}@ = @\seebelow@; // \expos @\exposid{variant-t}@ @\exposid{result}@; // \expos virtual void @\exposid{complete}@() noexcept = 0; // \expos @@ -5449,6 +5462,11 @@ void @\exposidnc{complete}@() noexcept override; // \expos void @\exposidnc{consume}@(@\libconcept{receiver}@ auto& rcvr) noexcept; // \expos void @\exposidnc{abandon}@() noexcept; // \expos + void @\exposidnc{try-cancel}@() noexcept override { // \expos + @\exposid{ssource}@.request_stop(); + @\exposid{try-set-stopped}@(); + } + void @\exposidnc{try-set-stopped}@() noexcept; // \expos private: using @\exposidnc{assoc-t}@ = // \expos @@ -5470,7 +5488,7 @@ \pnum For purposes of determining the existence of a data race, -\exposid{complete}, \exposid{consume}, and \exposid{abandon} +\exposid{complete}, \exposid{consume}, \exposid{try-set-stopped}, and \exposid{abandon} behave as atomic operations\iref{intro.multithread}. These operations on a single object of a type that is a specialization of \exposid{spawn-future-state} @@ -5487,13 +5505,18 @@ \begin{itemize} \item No effects if this invocation of \exposid{complete} happens before -an invocation of \exposid{consume} or \exposid{abandon} on \tcode{*this}; +an invocation of +\exposid{consume}, \exposid{try-set-\linebreak{}stopped}, or \exposid{abandon} +on \tcode{*this}; \item otherwise, if an invocation of \exposid{consume} on \tcode{*this} happens before -this invocation of \exposid{complete} then +this invocation of \exposid{complete} and +no invocation of \exposid{try-set-stopped} on \tcode{*this} happened before +this invocation of \tcode{complete} then there is a receiver, \tcode{rcvr}, registered and -that receiver is completed as if by \tcode{\exposid{consume}(rcvr)}; +that receiver is deregistered and completed +as if by \tcode{\exposid{consume}(rcvr)}; \item otherwise, \exposid{destroy} is invoked. @@ -5511,10 +5534,20 @@ \begin{itemize} \item If this invocation of \exposid{consume} happens before -an invocation of \exposid{complete} on \tcode{*this} then +an invocation of \exposid{complete} on \tcode{*this} and +no invocation of \exposid{try-set-stopped} on \tcode{*this} happened before +this invocation of \exposid{consume} then \tcode{rcvr} is registered to be completed when \exposid{complete} is subsequently invoked on \tcode{*this}; +\item +otherwise, +if this invocation of \exposid{consume} happens after +an invocation of \exposid{try-set-stopped} on \tcode{*this} and +no invocation of \exposid{complete} on \tcode{*this} happened before +this invocation of \exposid{consume} then +\tcode{rcvr} is completed as if by \tcode{set_stopped(std::move(rcvr))}; + \item otherwise, \tcode{rcvr} is completed as if by: @@ -5527,10 +5560,34 @@ }, std::move(tuple)); } }); +destroy(); \end{codeblock} \end{itemize} \end{itemdescr} +\indexlibrarymember{\exposid{try-set-stopped}}{execution::\exposid{spawn-future-state}}% +\begin{itemdecl} +void @\exposid{try-set-stopped}@() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +\begin{itemize} +\item +If an invocation of \exposid{consume} on \tcode{*this} happens before +this invocation of \exposid{try-set-stopped} and +no invocation of \exposid{complete} on \tcode{*this} happened before +this invocation of \exposid{try-set-stopped} then +there is a receiver, \tcode{rcvr}, registered and +that receiver is deregistered and completed as if by +\tcode{set_stopped(std::move(rcvr)), \exposid{destroy}()}; + +\item +otherwise, no effects. +\end{itemize} +\end{itemdescr} + \indexlibrarymember{\exposid{abandon}}{execution::\exposid{spawn-future-state}}% \begin{itemdecl} void @\exposid{abandon}@() noexcept; @@ -5573,6 +5630,87 @@ \end{codeblock} \end{itemdescr} +\pnum +Let \exposid{future-operation} be the exposition-only class template: + +\begin{codeblock} +namespace std::execution { + template + struct @\exposid{future-operation}@ { // \expos + struct @\exposid{callback}@ { // \expos + @\exposid{try-cancelable}@* @\exposid{state}@; // \expos + + void operator()() noexcept { + @\exposid{state}@->@\exposid{try-cancel}@(); + }; + }; + + using @\exposid{stop-token-t}@ = // \expos + stop_token_of_t>; + + using @\exposid{stop-callback-t}@ = // \expos + stop_callback_for_t<@\exposid{stop-token-t}@, @\exposid{callback}@>; + + struct @\exposid{receiverx}@ { // \expos + using receiver_concept = receiver_t; + @\exposid{future-operation}@* @\exposid{op}@; // \expos + + template + void set_value(T&&... ts) && noexcept { + @\exposid{op}@->@\exposid{set-complete}@(std::forward(ts)...); + } + + template + void set_error(E&& e) && noexcept { + @\exposid{op}@->@\exposid{set-complete}@(std::forward(e)); + } + + void set_stopped() && noexcept { + @\exposid{op}@->@\exposid{set-complete}@(); + } + + env_of_t get_env() const noexcept { + return execution::get_env(@\exposid{op}@->@\exposid{rcvr}@); + } + }; + + Rcvr @\exposid{rcvr}@; // \expos + StatePtr @\exposid{state}@; // \expos + @\exposid{receiverx}@ @\exposid{inner}@; // \expos + optional<@\exposid{stop-callback-t}@> @\exposid{stopCallback}@; // \expos + + + @\exposid{future-operation}@(StatePtr state, Rcvr rcvr) noexcept // \expos + : @\exposid{rcvr}@(std::move(rcvr)), @\exposid{state}@(std::move(state)), @\exposid{inner}@(this) + {} + + @\exposid{future-operation}@(@\exposid{future-operation}@&&) = delete; + + void @\exposid{run}@() & noexcept { // \expos + constexpr bool nothrow = + is_nothrow_constructible_v<@\exposid{stop-callback-t}@, @\exposid{stop-token-t}@, @\exposid{callback}@>; + try { + @\exposid{stopCallback}@.emplace(get_stop_token(@\exposid{rcvr}@), @\exposid{callback}@(@\exposid{state}@.get())); + } + catch (...) { + if constexpr (!nothrow) { + set_error(std::move(@\exposid{rcvr}@), current_exception()); + return; + } + } + + @\exposid{state}@.release()->@\exposid{consume}@(@\exposid{innex}@); + } + + template + void @\exposid{set-complete}@(T&&... ts) noexcept { // \expos + @\exposid{stopCallback}@.reset(); + CPO{}(std::move(@\exposid{rcvr}@), std::forward(ts)...); + } + }; +} +\end{codeblock} + \pnum The exposition-only class template \exposid{impls-for}\iref{exec.snd.expos} is specialized for \tcode{spawn_future_t} as follows: @@ -5583,6 +5721,7 @@ template<> struct @\exposid{impls-for}@ : @\exposid{default-impls}@ { static constexpr auto @\exposid{start}@ = @\seebelow@; // \expos + static constexpr auto @\exposid{get-state}@ = @\seebelow@; // \expos }; } \end{codeblock} @@ -5591,8 +5730,19 @@ The member \tcode{\exposid{impls-for}::\exposid{start}} is initialized with a callable object equivalent to the following lambda: \begin{codeblock} -[](auto& state, auto& rcvr) noexcept -> void { - state->@\exposid{consume}@(rcvr); +[](auto& state, auto&) noexcept -> void { + state.@\exposid{run}@(); +} +\end{codeblock} + +\pnum +The member \tcode{\exposid{impls-for}::\exposid{get-state}} +is initialized with a callable object equivalent to the following lambda: +\begin{codeblock} +[](Sndr sndr, Rcvr& rcvr) noexcept { + auto& [_, data] = sndr; + using state_ptr = remove_cvref_t; + return @\exposid{future-operation}@(std::move(data), std::move(rcvr)); } \end{codeblock} From 5a6ac9cb8306454eb41f309e4f4271c386eef804 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Thu, 9 Apr 2026 04:20:06 -0700 Subject: [PATCH 28/37] LWG4544 Parallel overload of ranges::set_difference should return in_in_out_result --- source/algorithms.tex | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/source/algorithms.tex b/source/algorithms.tex index 0c5d2b5cb6..6424f4e38a 100644 --- a/source/algorithms.tex +++ b/source/algorithms.tex @@ -3633,6 +3633,8 @@ namespace ranges { template using @\libglobal{set_difference_result}@ = in_out_result; + template + using @\libglobal{set_difference_truncated_result}@ = in_in_out_result; template<@\libconcept{input_iterator}@ I1, @\libconcept{sentinel_for}@ S1, @\libconcept{input_iterator}@ I2, @\libconcept{sentinel_for}@ S2, @\libconcept{weakly_incrementable}@ O, class Comp = ranges::less, @@ -3653,7 +3655,7 @@ @\libconcept{random_access_iterator}@ O, @\libconcept{sized_sentinel_for}@ OutS, class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity> requires @\libconcept{mergeable}@ - set_difference_result + set_difference_truncated_result set_difference(Ep&& exec, I1 first1, S1 last1, I2 first2, S2 last2, O result, OutS result_last, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); // freestanding-deleted @@ -3661,7 +3663,8 @@ @\exposconcept{sized-random-access-range}@ OutR, class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity> requires @\libconcept{mergeable}@, iterator_t, iterator_t, Comp, Proj1, Proj2> - set_difference_result, borrowed_iterator_t> + set_difference_truncated_result, borrowed_iterator_t, + borrowed_iterator_t> set_difference(Ep&& exec, R1&& r1, R2&& r2, OutR&& result_r, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); // freestanding-deleted } @@ -10669,7 +10672,7 @@ @\libconcept{random_access_iterator}@ O, @\libconcept{sized_sentinel_for}@ OutS, class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity> requires @\libconcept{mergeable}@ - ranges::set_difference_result + ranges::set_difference_truncated_result ranges::set_difference(Ep&& exec, I1 first1, S1 last1, I2 first2, S2 last2, O result, OutS result_last, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); @@ -10677,7 +10680,8 @@ @\exposconcept{sized-random-access-range}@ OutR, class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity> requires @\libconcept{mergeable}@, iterator_t, iterator_t, Comp, Proj1, Proj2> - ranges::set_difference_result, borrowed_iterator_t> + ranges::set_difference_truncated_result, borrowed_iterator_t, + borrowed_iterator_t> ranges::set_difference(Ep&& exec, R1&& r1, R2&& r2, OutR&& result_r, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); \end{itemdecl} @@ -10716,6 +10720,13 @@ that are equivalent to them, the last $\max(m - n, 0)$ elements from \range{first1}{last1} are included in the sorted difference, in order. +Of those equivalent elements, +the first $\min(m, n)$ elements in both ranges +\indextext{element!skipped}% +are considered \defn{skipped}. +An element from the second range is also considered skipped +if it compares less than the $\min(N + 1, M)^\text{th}$ element +of the sorted difference. Copies the first $N$ elements of the sorted difference to the range \range{result}{result + $N$}. @@ -10727,14 +10738,19 @@ for the overloads in namespace \tcode{std}. \item \tcode{\{last1, result + $N$\}} - for the overloads in namespace \tcode{ranges}, - if $N$ is equal to $M$. + for the non-parallel overloads in namespace \tcode{ranges}. \item - Otherwise, \tcode{\{j1, result_last\}} - for the overloads in namespace \tcode{ranges}, - where the iterator \tcode{j1} - points to the position of the element in \range{first1}{last1} - corresponding to the $(N + 1)^\text{th}$ element of the sorted difference. + For the parallel algorithm overloads in namespace \tcode{ranges}: + \begin{itemize} + \item + \tcode{\{last1, first2 + $B$, result + $N$\}}, + if $N$ is equal to $M$, + where $B$ is the number of skipped elements in \range{first2}{last2}. + \item + Otherwise, \tcode{\{first1 + $A$, first2 + $B$, result_last\}}, + where $A$ and $B$ are the numbers of copied or skipped elements + in \range{first1}{last1} and \range{first2}{last2}, respectively. + \end{itemize} \end{itemize} \pnum From 171ed2c75837e0ac6807e0533d3bf084bdc54fc9 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Thu, 9 Apr 2026 04:32:53 -0700 Subject: [PATCH 29/37] LWG4548 Parallel ranges::set_intersection should not do unnecessary work [set.intersection] Turned "skipped" into an indexed definition to match that of LWG4544. --- source/algorithms.tex | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/source/algorithms.tex b/source/algorithms.tex index 6424f4e38a..2c7c2223c3 100644 --- a/source/algorithms.tex +++ b/source/algorithms.tex @@ -10587,9 +10587,10 @@ If, of those elements, $k$ elements from the first range are copied to the output range, then the first $k$ elements from the second range -are considered \term{skipped}. -If $N < M$, a non-copied element is also considered skipped -if it compares less than the $(N + 1)^\text{th}$ element +\indextext{element!skipped}% +are considered \defn{skipped}. +A non-copied element is also considered skipped +if it compares less than the $\min(M, N + 1)^\text{th}$ element of the sorted intersection. Copies the first $N$ elements of the sorted intersection to the range \range{result}{result + $N$}. @@ -10602,11 +10603,10 @@ for the overloads in namespace \tcode{std}. \item \tcode{\{last1, last2, result + $N$\}} - for the overloads in namespace \tcode{ranges}, - if $N$ is equal to $M$. + for the non-parallel algorithm overloads in namespace \tcode{ranges}. \item - Otherwise, \tcode{\{first1 + $A$, first2 + $B$, result_last\}} - for the overloads in namespace \tcode{ranges}, + Otherwise, \tcode{\{first1 + $A$, first2 + $B$, result + $N$\}} + for the parallel algorithm overloads in namespace \tcode{ranges}, where $A$ and $B$ are the numbers of copied or skipped elements in \range{first1}{last1} and \range{first2}{last2}, respectively. \end{itemize} From c4ad4afdab2372ae035ad9c23d81c2e5e33f2fdd Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Thu, 9 Apr 2026 04:37:36 -0700 Subject: [PATCH 30/37] LWG4549 vprint_nonunicode_buffered ignores its stream parameter --- source/iostreams.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/iostreams.tex b/source/iostreams.tex index a430c8dc69..7613d622b2 100644 --- a/source/iostreams.tex +++ b/source/iostreams.tex @@ -7927,7 +7927,7 @@ Equivalent to: \begin{codeblock} string out = vformat(fmt, args); -vprint_nonunicode("{}", make_format_args(out)); +vprint_nonunicode(stream, "{}", make_format_args(out)); \end{codeblock} \end{itemdescr} From a1901ce3185e8ee9672874a0d3381e3575d4e954 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Thu, 9 Apr 2026 04:41:11 -0700 Subject: [PATCH 31/37] LWG4550 Need new feature test macros for and Fixes NB GB 07, GB 11 (C++26 CD). --- source/support.tex | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/support.tex b/source/support.tex index 4f8c4bbad2..af21337ef8 100644 --- a/source/support.tex +++ b/source/support.tex @@ -848,6 +848,8 @@ #define @\defnlibxname{cpp_lib_start_lifetime_as}@ 202207L // freestanding, also in \libheader{memory} #define @\defnlibxname{cpp_lib_starts_ends_with}@ 201711L // also in \libheader{string}, \libheader{string_view} #define @\defnlibxname{cpp_lib_stdatomic_h}@ 202011L // also in \libheader{stdatomic.h} +#define @\defnlibxname{cpp_lib_stdbit_h}@ 202603L // also in \libheader{stdbit.h} +#define @\defnlibxname{cpp_lib_stdckdint_h}@ 202603L // also in \libheader{stdckdint.h} #define @\defnlibxname{cpp_lib_string_contains}@ 202011L // also in \libheader{string}, \libheader{string_view} #define @\defnlibxname{cpp_lib_string_resize_and_overwrite}@ 202110L // also in \libheader{string} #define @\defnlibxname{cpp_lib_string_subview}@ 202506L // also in \libheader{string}, \libheader{string_view} From b08f0d6f96fae0488c9ac26c8dd8562553756616 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Thu, 9 Apr 2026 04:55:57 -0700 Subject: [PATCH 32/37] LWG4552 compare_exchange_weak writes a value on spurious failure, not memory contents --- source/threads.tex | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/source/threads.tex b/source/threads.tex index 5762bd5817..7d67eed288 100644 --- a/source/threads.tex +++ b/source/threads.tex @@ -3525,11 +3525,11 @@ \pnum \remarks A weak compare-and-exchange operation may fail spuriously. -That is, even when the contents of memory referred to -by \tcode{expected} and \tcode{ptr} are equal, +That is, even when the value representations referred to +by \tcode{expected} and \tcode{ptr} compare equal, it may return \tcode{false} and -store back to \tcode{expected} the same memory contents -that were originally there. +store back to \tcode{expected} +the same value representation that was originally there. \begin{note} This spurious failure enables implementation of compare-and-exchange on a broader class of machines, e.g., load-locked store-conditional machines. @@ -4805,7 +4805,7 @@ pointed to by \keyword{this} during the atomic comparison. If the operation returns \tcode{true}, these operations are atomic read-modify-write -operations\iref{intro.multithread} on the memory +operations\iref{intro.races} on the memory pointed to by \keyword{this}. Otherwise, these operations are atomic load operations on that memory. @@ -4849,6 +4849,7 @@ \end{example} \pnum +\recommended Implementations should ensure that weak compare-and-exchange operations do not consistently return \tcode{false} unless either the atomic object has value different from \tcode{expected} or there are concurrent modifications to the @@ -4857,9 +4858,11 @@ \pnum \remarks A weak compare-and-exchange operation may fail spuriously. That is, even when -the contents of memory referred to by \tcode{expected} and \keyword{this} are -equal, it may return \tcode{false} and store back to \tcode{expected} the same memory -contents that were originally there. +the value representations referred to by \tcode{expected} and \keyword{this} +compare equal, +it may return \tcode{false} and +store back to \tcode{expected} +the same value representation that was originally there. \begin{note} This spurious failure enables implementation of compare-and-exchange on a broader class of From c4e0c926afac068fcb5bead895e4091babcd5ad0 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Thu, 9 Apr 2026 05:02:48 -0700 Subject: [PATCH 33/37] LWG4553 Wording for FR-025-246 25.7.18.2 Add a reserve_hint function to concat_view Fixes NB FR 025-246 (C++26 CD). --- source/ranges.tex | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/source/ranges.tex b/source/ranges.tex index 4edd7d9642..61cc34d210 100644 --- a/source/ranges.tex +++ b/source/ranges.tex @@ -8791,6 +8791,8 @@ constexpr auto size() requires (@\libconcept{sized_range}@ && ...); constexpr auto size() const requires (@\libconcept{sized_range}@ && ...); + constexpr auto reserve_hint() requires (@\libconcept{approximately_sized_range}@ && ...); + constexpr auto reserve_hint() const requires (@\libconcept{approximately_sized_range}@ && ...); }; template @@ -8963,6 +8965,26 @@ \end{codeblock} \end{itemdescr} +\indexlibrarymember{reserve_hint}{concat_view}% +\begin{itemdecl} +constexpr auto reserve_hint() requires (@\libconcept{approximately_sized_range}@ && ...); +constexpr auto reserve_hint() const requires (@\libconcept{approximately_sized_range}@ && ...); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +return apply( + [](auto... sizes) { + using CT = @\exposid{make-unsigned-like-t}@>; + return (CT(sizes) + ...); + }, + @\exposid{tuple-transform}@(ranges::reserve_hint, @\exposid{views_}@)); +\end{codeblock} +\end{itemdescr} + \rSec3[range.concat.iterator]{Class \tcode{concat_view::\exposid{iterator}}} \indexlibrarymember{iterator}{concat_view}% From 79358bcb9da9359d8a5ff160057d9779781f5a03 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Thu, 9 Apr 2026 06:02:55 -0700 Subject: [PATCH 34/37] LWG4554 Remove undefined behaviour from hive for invalid limits Fixes NB US 139-232 (C++26 CD). --- source/containers.tex | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/source/containers.tex b/source/containers.tex index 55aae3849a..82c17c23da 100644 --- a/source/containers.tex +++ b/source/containers.tex @@ -7980,9 +7980,15 @@ The maximum hard limit shall be no larger than \tcode{std::allocator_traits::max_size()}. \item -If user-specified limits are not within hard limits, or +If user-specified limits passed to +a \tcode{hive} constructor or \tcode{reshape} +are not within hard limits, or if the specified minimum limit is greater than the specified maximum limit, -the behavior is undefined. +the behavior is erroneous and the effects are +\impldef{effects of invalid \tcode{hive} limits}. +\begin{tailnote} +This condition can be checked using \tcode{is_within_hard_limits}. +\end{tailnote} \item An element block is said to be \defnx{within the bounds}{element block!bounds} of a pair of minimum/maximum limits @@ -8089,6 +8095,7 @@ constexpr hive_limits block_capacity_limits() const noexcept; static constexpr hive_limits block_capacity_default_limits() noexcept; static constexpr hive_limits block_capacity_hard_limits() noexcept; + static constexpr bool is_within_hard_limits(hive_limits) noexcept; void reshape(hive_limits block_limits); // \ref{hive.modifiers}, modifiers @@ -8606,6 +8613,20 @@ Constant. \end{itemdescr} +\indexlibrarymember{is_within_hard_limits}{hive}% +\begin{itemdecl} +static constexpr bool is_within_hard_limits(hive_limits lim) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{hl} be \tcode{block_capacity_hard_limits()}. + +\pnum +\returns +\tcode{hl.min <= lim.min \&\& lim.min <= lim.max \&\& lim.max <= hl.max}. +\end{itemdescr} + \indexlibrarymember{reshape}{hive}% \begin{itemdecl} void reshape(hive_limits block_limits); From 77389753a93b0f51c267ddf16328bf827f4b30eb Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Thu, 9 Apr 2026 06:10:00 -0700 Subject: [PATCH 35/37] LWG4555 Remove is_consteval_only Fixes NB US 81-149 (C++26 CD). --- source/meta.tex | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/source/meta.tex b/source/meta.tex index aca94502c9..6285cc7063 100644 --- a/source/meta.tex +++ b/source/meta.tex @@ -257,7 +257,6 @@ template struct is_abstract; template struct is_final; template struct is_aggregate; - template struct is_consteval_only; template struct is_signed; template struct is_unsigned; @@ -510,8 +509,6 @@ constexpr bool @\libglobal{is_final_v}@ = is_final::value; template constexpr bool @\libglobal{is_aggregate_v}@ = is_aggregate::value; - template - constexpr bool @\libglobal{is_consteval_only_v}@ = is_consteval_only::value; template constexpr bool @\libglobal{is_signed_v}@ = is_signed::value; template @@ -1197,12 +1194,6 @@ \tcode{T} is an aggregate type\iref{dcl.init.aggr} & \tcode{T} shall be an array type, a complete type, or \cv~\keyword{void}. \\ \rowsep -\indexlibraryglobal{is_consteval_only}% -\tcode{template}\br - \tcode{struct is_consteval_only;} & - \tcode{T} is consteval-only\iref{basic.types.general} & - \tcode{remove_all_extents_t} shall be a complete type or \cv~\keyword{void}. \\ \rowsep - \indexlibrary{\idxcode{is_signed}!class}% \tcode{template}\br \tcode{struct is_signed;} & @@ -3160,7 +3151,6 @@ consteval bool is_abstract_type(info type); consteval bool is_final_type(info type); consteval bool is_aggregate_type(info type); - consteval bool is_consteval_only_type(info type); consteval bool is_signed_type(info type); consteval bool is_unsigned_type(info type); consteval bool is_bounded_array_type(info type); @@ -6853,7 +6843,6 @@ consteval bool @\libglobal{is_abstract_type}@(info type); consteval bool @\libglobal{is_final_type}@(info type); consteval bool @\libglobal{is_aggregate_type}@(info type); -consteval bool @\libglobal{is_consteval_only_type}@(info type); consteval bool @\libglobal{is_signed_type}@(info type); consteval bool @\libglobal{is_unsigned_type}@(info type); consteval bool @\libglobal{is_bounded_array_type}@(info type); From 1e44b039378c4243fcd162789c572c39d86b6066 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Thu, 9 Apr 2026 06:16:26 -0700 Subject: [PATCH 36/37] LWG4556 Unclear properties of reflection strings --- source/meta.tex | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/source/meta.tex b/source/meta.tex index 6285cc7063..b6f5ccfbcc 100644 --- a/source/meta.tex +++ b/source/meta.tex @@ -3317,8 +3317,17 @@ \pnum Any function in namespace \tcode{std::meta} whose return type is \tcode{string_view} or \tcode{u8string_view} +%FIXME: V should not be \exposid since it's not a declared \expos varible, +%use math font or \placeholder instead. returns an object \exposid{V} such that \tcode{\exposid{V}.data()[\exposid{V}.size()]} equals \tcode{'\textbackslash 0'}. +Each element of the range +\tcode{\exposid{V}.data() +} \range{0}{\exposid{V}.size()} +is a potentially non-unique object with static storage duration that +is usable in constant expressions\iref{intro.object, expr.const}; +a pointer to such an element is not suitable for use as +a template argument for a constant template parameter of +pointer type\iref{temp.arg.nontype}. \begin{example} \begin{codeblock} struct C { }; From b87b2ae8f175da2b17620a1d15e5b46af2deac37 Mon Sep 17 00:00:00 2001 From: Dawn Perchik Date: Thu, 9 Apr 2026 06:44:20 -0700 Subject: [PATCH 37/37] LWG4557 Remove constexpr from owner_less and owner_before Fixes NB US 75-138 (C++26 CD). --- source/memory.tex | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/source/memory.tex b/source/memory.tex index 758104f9a4..d8327daa70 100644 --- a/source/memory.tex +++ b/source/memory.tex @@ -3468,9 +3468,9 @@ constexpr long use_count() const noexcept; constexpr explicit operator bool() const noexcept; template - constexpr bool owner_before(const shared_ptr& b) const noexcept; + bool owner_before(const shared_ptr& b) const noexcept; template - constexpr bool owner_before(const weak_ptr& b) const noexcept; + bool owner_before(const weak_ptr& b) const noexcept; size_t owner_hash() const noexcept; template constexpr bool owner_equal(const shared_ptr& b) const noexcept; @@ -4076,8 +4076,8 @@ \indexlibrarymember{owner_before}{shared_ptr}% \begin{itemdecl} -template constexpr bool owner_before(const shared_ptr& b) const noexcept; -template constexpr bool owner_before(const weak_ptr& b) const noexcept; +template bool owner_before(const shared_ptr& b) const noexcept; +template bool owner_before(const weak_ptr& b) const noexcept; \end{itemdecl} \begin{itemdescr} @@ -4793,9 +4793,9 @@ constexpr bool expired() const noexcept; constexpr shared_ptr lock() const noexcept; template - constexpr bool owner_before(const shared_ptr& b) const noexcept; + bool owner_before(const shared_ptr& b) const noexcept; template - constexpr bool owner_before(const weak_ptr& b) const noexcept; + bool owner_before(const weak_ptr& b) const noexcept; size_t owner_hash() const noexcept; template constexpr bool owner_equal(const shared_ptr& b) const noexcept; @@ -4992,8 +4992,8 @@ \indexlibrarymember{owner_before}{weak_ptr}% \begin{itemdecl} -template constexpr bool owner_before(const shared_ptr& b) const noexcept; -template constexpr bool owner_before(const weak_ptr& b) const noexcept; +template bool owner_before(const shared_ptr& b) const noexcept; +template bool owner_before(const weak_ptr& b) const noexcept; \end{itemdecl} \begin{itemdescr} @@ -5067,26 +5067,26 @@ template struct owner_less; template struct owner_less> { - constexpr bool operator()(const shared_ptr&, const shared_ptr&) const noexcept; - constexpr bool operator()(const shared_ptr&, const weak_ptr&) const noexcept; - constexpr bool operator()(const weak_ptr&, const shared_ptr&) const noexcept; + bool operator()(const shared_ptr&, const shared_ptr&) const noexcept; + bool operator()(const shared_ptr&, const weak_ptr&) const noexcept; + bool operator()(const weak_ptr&, const shared_ptr&) const noexcept; }; template struct owner_less> { - constexpr bool operator()(const weak_ptr&, const weak_ptr&) const noexcept; - constexpr bool operator()(const shared_ptr&, const weak_ptr&) const noexcept; - constexpr bool operator()(const weak_ptr&, const shared_ptr&) const noexcept; + bool operator()(const weak_ptr&, const weak_ptr&) const noexcept; + bool operator()(const shared_ptr&, const weak_ptr&) const noexcept; + bool operator()(const weak_ptr&, const shared_ptr&) const noexcept; }; template<> struct owner_less { template - constexpr bool operator()(const shared_ptr&, const shared_ptr&) const noexcept; + bool operator()(const shared_ptr&, const shared_ptr&) const noexcept; template - constexpr bool operator()(const shared_ptr&, const weak_ptr&) const noexcept; + bool operator()(const shared_ptr&, const weak_ptr&) const noexcept; template - constexpr bool operator()(const weak_ptr&, const shared_ptr&) const noexcept; + bool operator()(const weak_ptr&, const shared_ptr&) const noexcept; template - constexpr bool operator()(const weak_ptr&, const weak_ptr&) const noexcept; + bool operator()(const weak_ptr&, const weak_ptr&) const noexcept; using is_transparent = @\unspec@; };