From cc244eb123329829a38a92cecd7fcd92ce37baac Mon Sep 17 00:00:00 2001 From: Matthias Kretz Date: Tue, 21 Oct 2025 14:43:05 +0200 Subject: [PATCH] LWG4420 [simd] conversions (constructor, load, stores, gather, and scatter) are incorrectly constrained for types Also fixes LWG4393, NB DE-288 (C++26 CD), NB DE-285 (C++26 CD). --- source/numerics.tex | 121 ++++++++++++++++++++++++++------------------ 1 file changed, 71 insertions(+), 50 deletions(-) diff --git a/source/numerics.tex b/source/numerics.tex index 9fedf97488..00752e6276 100644 --- a/source/numerics.tex +++ b/source/numerics.tex @@ -16232,6 +16232,12 @@ bool_constant::value && bool_constant(T()) == T::value>::value; +template + concept @\defexposconceptnc{explicitly-convertible-to}@ = // \expos + requires { + static_cast(declval()); + }; + template using @\exposidnc{deduced-vec-t} = \seebelownc@; // \expos template using @\exposidnc{make-compatible-simd-t} = \seebelownc@; // \expos @@ -16576,54 +16582,46 @@ flags f = {}); template - requires ranges::@\libconcept{sized_range}@ && @\libconcept{indirectly_writable}@, T> + requires ranges::@\libconcept{sized_range}@ constexpr void unchecked_store(const basic_vec& v, R&& r, flags f = {}); template - requires ranges::@\libconcept{sized_range}@ && @\libconcept{indirectly_writable}@, T> + requires ranges::@\libconcept{sized_range}@ constexpr void unchecked_store(const basic_vec& v, R&& r, const typename basic_vec::mask_type& mask, flags f = {}); template - requires @\libconcept{indirectly_writable}@ constexpr void unchecked_store(const basic_vec& v, I first, iter_difference_t n, flags f = {}); template - requires @\libconcept{indirectly_writable}@ constexpr void unchecked_store(const basic_vec& v, I first, iter_difference_t n, const typename basic_vec::mask_type& mask, flags f = {}); template S, class... Flags> - requires @\libconcept{indirectly_writable}@ constexpr void unchecked_store(const basic_vec& v, I first, S last, flags f = {}); template S, class... Flags> - requires @\libconcept{indirectly_writable}@ constexpr void unchecked_store(const basic_vec& v, I first, S last, const typename basic_vec::mask_type& mask, flags f = {}); template - requires ranges::@\libconcept{sized_range}@ && @\libconcept{indirectly_writable}@, T> + requires ranges::@\libconcept{sized_range}@ constexpr void partial_store(const basic_vec& v, R&& r, flags f = {}); template - requires ranges::@\libconcept{sized_range}@ && @\libconcept{indirectly_writable}@, T> + requires ranges::@\libconcept{sized_range}@ constexpr void partial_store(const basic_vec& v, R&& r, const typename basic_vec::mask_type& mask, flags f = {}); template - requires @\libconcept{indirectly_writable}@ constexpr void partial_store( const basic_vec& v, I first, iter_difference_t n, flags f = {}); template - requires @\libconcept{indirectly_writable}@ constexpr void partial_store( const basic_vec& v, I first, iter_difference_t n, const typename basic_vec::mask_type& mask, flags f = {}); template S, class... Flags> - requires @\libconcept{indirectly_writable}@ constexpr void partial_store(const basic_vec& v, I first, S last, flags f = {}); template S, class... Flags> - requires @\libconcept{indirectly_writable}@ constexpr void partial_store(const basic_vec& v, I first, S last, const typename basic_vec::mask_type& mask, flags f = {}); @@ -17713,7 +17711,7 @@ \pnum \constraints -\tcode{value_type} satisfies \tcode{\libconcept{constructible_from}}. +\tcode{U} satisfies \tcode{\exposconcept{explicitly-convertible-to}}. \pnum \effects @@ -17722,10 +17720,11 @@ \pnum \remarks -The expression inside \tcode{explicit} evaluates to \tcode{false} if and only if -\tcode{U} satisfies \tcode{\libconcept{convertible_to}}, and either +The expression inside \tcode{explicit} evaluates to \tcode{false} if and only +if either \begin{itemize} \item + \tcode{U} satisfies \tcode{\libconcept{convertible_to}} and \tcode{From} is not an arithmetic type and does not satisfy \exposconcept{constexpr-wrapper-like}, \item @@ -17747,7 +17746,12 @@ \begin{itemdescr} \pnum \constraints -\tcode{\exposid{simd-size-v} == size()} is \tcode{true}. +\begin{itemize} + \item + \tcode{\exposid{simd-size-v} == size()} is \tcode{true}, and + \item + \tcode{U} satisfies \tcode{\exposconcept{explicitly-convertible-to}}. +\end{itemize} \pnum \effects @@ -17819,20 +17823,17 @@ \begin{itemize} \item \tcode{R} models \tcode{ranges::\libconcept{contiguous_range}} and \tcode{ranges::\libconcept{sized_range}}, -\item \tcode{ranges::size(r)} is a constant expression, and -\item \tcode{ranges::size(r)} is equal to \tcode{size()}. +\item \tcode{ranges::size(r)} is a constant expression, +\item \tcode{ranges::size(r)} is equal to \tcode{size()}, and +\item \tcode{ranges::range_value_t} is a vectorizable type and satisfies + \tcode{\exposconcept{explicitly-convertible-to}}. \end{itemize} \pnum \mandates -\begin{itemize} - \item - \tcode{ranges::range_value_t} is a vectorizable type, and - \item - if the template parameter pack \tcode{Flags} does not contain - \tcode{\exposid{convert-flag}}, then the conversion from - \tcode{ranges::range_value_t} to \tcode{value_type} is value-preserving. -\end{itemize} +If the template parameter pack \tcode{Flags} does not contain +\tcode{\exposid{convert-flag}}, then the conversion from +\tcode{ranges::range_value_t} to \tcode{value_type} is value-preserving. \pnum \expects @@ -18575,7 +18576,8 @@ \mandates \begin{itemize} \item - \tcode{ranges::range_value_t} is a vectorizable type, + \tcode{ranges::range_value_t} is a vectorizable type and satisfies + \tcode{\exposconcept{explicitly-convertible-to}}, \item \tcode{same_as, V>} is \tcode{true}, \item @@ -18622,26 +18624,22 @@ \indexlibrarymember{unchecked_store}{simd} \begin{itemdecl} template - requires ranges::@\libconcept{sized_range}@ && @\libconcept{indirectly_writable}@, T> + requires ranges::@\libconcept{sized_range}@ constexpr void unchecked_store(const basic_vec& v, R&& r, flags f = {}); template - requires ranges::@\libconcept{sized_range}@ && @\libconcept{indirectly_writable}@, T> + requires ranges::@\libconcept{sized_range}@ constexpr void unchecked_store(const basic_vec& v, R&& r, const typename basic_vec::mask_type& mask, flags f = {}); template - requires @\libconcept{indirectly_writable}@ constexpr void unchecked_store(const basic_vec& v, I first, iter_difference_t n, flags f = {}); template - requires @\libconcept{indirectly_writable}@ constexpr void unchecked_store(const basic_vec& v, I first, iter_difference_t n, const typename basic_vec::mask_type& mask, flags f = {}); template S, class... Flags> - requires @\libconcept{indirectly_writable}@ constexpr void unchecked_store(const basic_vec& v, I first, S last, flags f = {}); template S, class... Flags> - requires @\libconcept{indirectly_writable}@ constexpr void unchecked_store(const basic_vec& v, I first, S last, const typename basic_vec::mask_type& mask, flags f = {}); \end{itemdecl} @@ -18688,26 +18686,22 @@ \indexlibrarymember{partial_store}{simd} \begin{itemdecl} template - requires ranges::@\libconcept{sized_range}@ && @\libconcept{indirectly_writable}@, T> + requires ranges::@\libconcept{sized_range}@ constexpr void partial_store(const basic_vec& v, R&& r, flags f = {}); template - requires ranges::@\libconcept{sized_range}@ && @\libconcept{indirectly_writable}@, T> + requires ranges::@\libconcept{sized_range}@ constexpr void partial_store(const basic_vec& v, R&& r, const typename basic_vec::mask_type& mask, flags f = {}); template - requires @\libconcept{indirectly_writable}@ constexpr void partial_store(const basic_vec& v, I first, iter_difference_t n, flags f = {}); template - requires @\libconcept{indirectly_writable}@ constexpr void partial_store(const basic_vec& v, I first, iter_difference_t n, const typename basic_vec::mask_type& mask, flags f = {}); template S, class... Flags> - requires @\libconcept{indirectly_writable}@ constexpr void partial_store(const basic_vec& v, I first, S last, flags f = {}); template S, class... Flags> - requires @\libconcept{indirectly_writable}@ constexpr void partial_store(const basic_vec& v, I first, S last, const typename basic_vec::mask_type& mask, flags f = {}); \end{itemdecl} @@ -18725,18 +18719,31 @@ \item \tcode{r} be \tcode{R(first, n)} for the overloads with an \tcode{n} parameter and \tcode{R(first, last)} for the overloads with a \tcode{last} - parameter. + parameter; + \item + \tcode{U} be \tcode{ranges::range_value_t}. +\end{itemize} + +\pnum +\constraints +\begin{itemize} + \item + \tcode{ranges::iterator_t} satisfies + \tcode{\libconcept{indirectly_writable}}, and + \item + \tcode{T} satisfies + \tcode{\exposconcept{explicitly-convertible-to}}. \end{itemize} \pnum \mandates \begin{itemize} \item - \tcode{ranges::range_value_t} is a vectorizable type, and + \tcode{U} is a vectorizable type, and \item if the template parameter pack \tcode{Flags} does not contain \tcode{\exposid{convert-flag}}, then the conversion from \tcode{T} to - \tcode{ranges::range_value_t} is value-preserving. + \tcode{U} is value-preserving. \end{itemize} \pnum @@ -18751,8 +18758,7 @@ \item If the template parameter pack \tcode{Flags} contains \tcode{\exposid{aligned-flag}}, \tcode{ranges::data(r)} points to storage - aligned by \tcode{alignment_v, - ranges::range_value_t>}. + aligned by \tcode{alignment_v, U>}. \item If the template parameter pack \tcode{Flags} contains \tcode{\exposid{overaligned-flag}}, \tcode{ranges::data(r)} points to @@ -18763,7 +18769,7 @@ \effects For all $i$ in the range of \range{0}{basic_vec::size()}, if \tcode{mask[$i$] \&\& $i$ < ranges::\brk{}size(r)} is \tcode{true}, evaluates -\tcode{ranges::data(r)[$i$] = v[$i$]}. +\tcode{ranges::data(r)[$i$] = static_cast(v[$i$])}. \end{itemdescr} \rSec3[simd.permute.static]{Static permute} @@ -18995,6 +19001,11 @@ \tcode{T} be \tcode{typename V::value_type}. \end{itemize} +\pnum +\constraints +\tcode{ranges::range_value_t} is a vectorizable type and satisfies +\tcode{\exposconceptx{explicitly-con\-vert\-ible-to}{explicitly-convertible-to}}. + \pnum \mandates \begin{itemize} @@ -19083,20 +19094,30 @@ \pnum Let \tcode{mask} be \tcode{typename I::mask_type(true)} for the overload with no \tcode{mask} parameter. +Let \tcode{U} be \tcode{ranges::range_value_t}. \pnum \constraints -\tcode{V::size() == I::size()} is \tcode{true}. +\begin{itemize} + \item + \tcode{V::size() == I::size()} is \tcode{true}, + \item + \tcode{ranges::iterator_t} satisfies + \tcode{\libconcept{indirectly_writable}}, and + \item + \tcode{typename V::value_type} satisfies + \tcode{\exposconcept{explicitly-convertible-to}}. +\end{itemize} \pnum \mandates \begin{itemize} \item -\tcode{ranges::range_value_t} is a vectorizable type, and +\tcode{U} is a vectorizable type, and \item if the template parameter pack \tcode{Flags} does not contain \exposid{convert-flag}, -then the conversion from \tcode{typename V::value_type} -to \tcode{ranges::range_value_t} is value-preserving. +then the conversion from \tcode{typename V::value_type} to \tcode{U} is +value-preserving. \end{itemize} \pnum @@ -19107,7 +19128,7 @@ \item If the template parameter pack \tcode{Flags} contains \exposid{aligned-flag}, \tcode{ranges::data(out)} points to storage aligned by -\tcode{alignment_v>}. +\tcode{alignment_v}. \item If the template parameter pack \tcode{Flags} contains \tcode{\exposid{overaligned-flag}},