[libcxx-commits] [libcxx] [libc++][mdspan] Add missing `std::move` in `std::extents` (PR #196574)

A. Jiang via libcxx-commits libcxx-commits at lists.llvm.org
Fri May 8 18:58:31 PDT 2026


================
@@ -322,7 +322,7 @@ class extents {
              (is_nothrow_constructible_v<index_type, _OtherIndexTypes> && ...) &&
              (sizeof...(_OtherIndexTypes) == __rank_ || sizeof...(_OtherIndexTypes) == __rank_dynamic_))
   _LIBCPP_HIDE_FROM_ABI constexpr explicit extents(_OtherIndexTypes... __dynvals) noexcept
-      : __vals_(static_cast<index_type>(__dynvals)...) {
+      : __vals_(static_cast<index_type>(std::move(__dynvals))...) {
----------------
frederick-vs-ja wrote:

I think we can introduce the following helper function:

```c++
// in namespace __mdspan_detail, after __are_representable_as

template <integral _To, class _From>
_LIBCPP_HIDE_FROM_ABI constexpr _To __representability_checked_cast(_From __value) {
  if constexpr (integral<_From>) {
    using _To_u   = make_unsigned_t<_To>;
    using _From_u = make_unsigned_t<_From>;
    if constexpr (is_signed_v<_From>) {
      _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
          __value >= 0, "extents ctor: arguments must be representable as index_type and nonnegative");
    }
    if constexpr (static_cast<_To_u>(numeric_limits<_To>::max()) < static_cast<_From_u>(numeric_limits<_From>::max())) {
      _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
          static_cast<_To_u>(numeric_limits<_To>::max()) >= static_cast<_From_u>(__value),
          "extents ctor: arguments must be representable as index_type and nonnegative");
    }
    return static_cast<_To>(__value);
  } else {
    auto __converted_val = static_cast<_To>(std::move(__value));
    if constexpr (is_signed_v<_To>) {
      _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
          __converted_val >= 0, "extents ctor: arguments must be representable as index_type and nonnegative");
    }
    return __converted_val;
  }
}
```

And then refactor this constructor as:
```c++
  // Construction from just dynamic or all values.
  // Precondition check is deferred to __maybe_static_array constructor
  template <class... _OtherIndexTypes>
    requires((is_convertible_v<_OtherIndexTypes, index_type> && ...) &&
             (is_nothrow_constructible_v<index_type, _OtherIndexTypes> && ...) &&
             (sizeof...(_OtherIndexTypes) == __rank_ || sizeof...(_OtherIndexTypes) == __rank_dynamic_))
  _LIBCPP_HIDE_FROM_ABI constexpr explicit extents(_OtherIndexTypes... __dynvals) noexcept
      // Not catching this could lead to out of bounds errors later
      // e.g. mdspan m(ptr, dextents<char, 1>(200u)); leads to an extent of -56 on m
      : __vals_(__mdspan_detail::__representability_checked_cast<index_type>(std::move(__dynvals))...) {}
```

Such strategy should be able to avoid double move while keeping checks.

https://github.com/llvm/llvm-project/pull/196574


More information about the libcxx-commits mailing list