summaryrefslogtreecommitdiff
path: root/libcxx
diff options
context:
space:
mode:
authorChristian Trott <crtrott@sandia.gov>2023-05-16 12:38:11 -0700
committerNikolas Klauser <n_klauser@apple.com>2023-05-16 14:30:36 -0700
commitfcaccf817d31d39096f7d0e7014cd6fe2fa3a683 (patch)
tree67d65b900fad74702b04de276fb2f24913cad5c6 /libcxx
parent02a029f7fb5a3feae60759eab6a528880e341358 (diff)
downloadllvm-fcaccf817d31d39096f7d0e7014cd6fe2fa3a683.tar.gz
[libcxx] Add mdspan/extents
This patch adds std::extents. extents is one of the core classes used by std::mdspan. It describes a multi-dimensional index space with a mix of compile time and runtime sizes. Furthermore, it is templated on the index type used to describe the multi-dimensional index space. The class is designed to be highly optimizable in performance critical code sections, and is fully useable in constant expressions contexts. Testing of this class tends to be somewhat combinatorical, due to the large number of possible corner cases involved in situations where we have both runtime and compile time extents. To add to this, the class is designed to be interoperable (in particular constructible) from arguments which only need to be convertible to the index_type, but are otherwise arbitrary user types. For a larger discussion on the design of this class refer to: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p0009r18.html Co-authored-by: Damien L-G <dalg24@gmail.com> Reviewed By: ldionne, #libc Spies: libcxx-commits, H-G-Hristov, tschuett, philnik, arichardson, Mordante, crtrott Differential Revision: https://reviews.llvm.org/D148067
Diffstat (limited to 'libcxx')
-rw-r--r--libcxx/CREDITS.TXT9
-rw-r--r--libcxx/docs/FeatureTestMacroTable.rst2
-rw-r--r--libcxx/docs/Status/Cxx2bPapers.csv2
-rw-r--r--libcxx/include/CMakeLists.txt2
-rw-r--r--libcxx/include/__mdspan/extents.h460
-rw-r--r--libcxx/include/libcxx.imp1
-rw-r--r--libcxx/include/mdspan69
-rw-r--r--libcxx/include/module.modulemap.in10
-rw-r--r--libcxx/include/version2
-rw-r--r--libcxx/test/libcxx/assertions/headers_declare_verbose_abort.sh.cpp174
-rw-r--r--libcxx/test/libcxx/clang_tidy.sh.cpp1
-rw-r--r--libcxx/test/libcxx/double_include.sh.cpp1
-rw-r--r--libcxx/test/libcxx/min_max_macros.compile.pass.cpp2
-rw-r--r--libcxx/test/libcxx/modules_include.sh.cpp188
-rw-r--r--libcxx/test/libcxx/nasty_macros.compile.pass.cpp1
-rw-r--r--libcxx/test/libcxx/no_assert_include.compile.pass.cpp1
-rw-r--r--libcxx/test/libcxx/private_headers.verify.cpp1
-rw-r--r--libcxx/test/libcxx/transitive_includes.sh.cpp222
-rw-r--r--libcxx/test/libcxx/transitive_includes/cxx03.csv6
-rw-r--r--libcxx/test/libcxx/transitive_includes/cxx11.csv6
-rw-r--r--libcxx/test/libcxx/transitive_includes/cxx14.csv6
-rw-r--r--libcxx/test/libcxx/transitive_includes/cxx17.csv6
-rw-r--r--libcxx/test/libcxx/transitive_includes/cxx20.csv6
-rw-r--r--libcxx/test/libcxx/transitive_includes/cxx2b.csv6
-rw-r--r--libcxx/test/std/containers/views/mdspan/extents/ConvertibleToIntegral.h22
-rw-r--r--libcxx/test/std/containers/views/mdspan/extents/CtorTestCombinations.h99
-rw-r--r--libcxx/test/std/containers/views/mdspan/extents/assert.conversion.pass.cpp57
-rw-r--r--libcxx/test/std/containers/views/mdspan/extents/assert.ctor_from_array.pass.cpp69
-rw-r--r--libcxx/test/std/containers/views/mdspan/extents/assert.ctor_from_integral.pass.cpp62
-rw-r--r--libcxx/test/std/containers/views/mdspan/extents/assert.ctor_from_span.pass.cpp62
-rw-r--r--libcxx/test/std/containers/views/mdspan/extents/assert.obs.pass.cpp65
-rw-r--r--libcxx/test/std/containers/views/mdspan/extents/comparison.pass.cpp95
-rw-r--r--libcxx/test/std/containers/views/mdspan/extents/conversion.pass.cpp138
-rw-r--r--libcxx/test/std/containers/views/mdspan/extents/ctad.pass.cpp46
-rw-r--r--libcxx/test/std/containers/views/mdspan/extents/ctor_default.pass.cpp49
-rw-r--r--libcxx/test/std/containers/views/mdspan/extents/ctor_from_array.pass.cpp86
-rw-r--r--libcxx/test/std/containers/views/mdspan/extents/ctor_from_integral.pass.cpp69
-rw-r--r--libcxx/test/std/containers/views/mdspan/extents/ctor_from_span.pass.cpp88
-rw-r--r--libcxx/test/std/containers/views/mdspan/extents/dextents.pass.cpp39
-rw-r--r--libcxx/test/std/containers/views/mdspan/extents/obs_static.pass.cpp88
-rw-r--r--libcxx/test/std/containers/views/mdspan/extents/types.pass.cpp85
-rw-r--r--libcxx/test/std/language.support/support.limits/support.limits.general/mdspan.version.compile.pass.cpp65
-rw-r--r--libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp30
-rwxr-xr-xlibcxx/utils/generate_feature_test_macro_components.py5
44 files changed, 2218 insertions, 285 deletions
diff --git a/libcxx/CREDITS.TXT b/libcxx/CREDITS.TXT
index cd5bc08a60fc..aa3c8cf1a8c6 100644
--- a/libcxx/CREDITS.TXT
+++ b/libcxx/CREDITS.TXT
@@ -92,6 +92,11 @@ E: stl@microsoft.com
E: stl@nuwen.net
D: Implemented floating-point to_chars.
+N: Damien Lebrun-Grandie
+E: dalg24@gmail.com
+E: lebrungrandt@ornl.gov
+D: Implementation of mdspan.
+
N: Microsoft Corporation
D: Contributed floating-point to_chars.
@@ -149,6 +154,10 @@ N: Stephan Tolksdorf
E: st@quanttec.com
D: Minor <atomic> fix
+N: Christian Trott
+E: crtrott@sandia.gov
+D: Implementation of mdspan.
+
N: Ruben Van Boxem
E: vanboxem dot ruben at gmail dot com
D: Initial Windows patches.
diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 677a71922bd0..0f5ee6c24485 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -332,6 +332,8 @@ Status
------------------------------------------------- -----------------
``__cpp_lib_is_scoped_enum`` ``202011L``
------------------------------------------------- -----------------
+ ``__cpp_lib_mdspan`` *unimplemented*
+ ------------------------------------------------- -----------------
``__cpp_lib_move_only_function`` *unimplemented*
------------------------------------------------- -----------------
``__cpp_lib_optional`` ``202110L``
diff --git a/libcxx/docs/Status/Cxx2bPapers.csv b/libcxx/docs/Status/Cxx2bPapers.csv
index a310cfc5ff16..550fb34d4b34 100644
--- a/libcxx/docs/Status/Cxx2bPapers.csv
+++ b/libcxx/docs/Status/Cxx2bPapers.csv
@@ -51,7 +51,7 @@
"`P2442R1 <https://wg21.link/P2442R1>`__","LWG","Windowing range adaptors: ``views::chunk`` and ``views::slide``","February 2022","","","|ranges|"
"`P2443R1 <https://wg21.link/P2443R1>`__","LWG","``views::chunk_by``","February 2022","","","|ranges|"
"","","","","","",""
-"`P0009R18 <https://wg21.link/P0009R18>`__","LWG","mdspan: A Non-Owning Multidimensional Array Reference","July 2022","",""
+"`P0009R18 <https://wg21.link/P0009R18>`__","LWG","mdspan: A Non-Owning Multidimensional Array Reference","July 2022","|In progress|",""
"`P0429R9 <https://wg21.link/P0429R9>`__","LWG","A Standard ``flat_map``","July 2022","",""
"`P1169R4 <https://wg21.link/P1169R4>`__","LWG","``static operator()``","July 2022","|Complete|","16.0"
"`P1222R4 <https://wg21.link/P1222R4>`__","LWG","A Standard ``flat_set``","July 2022","",""
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 04293ba4bad6..190616aaa55c 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -463,6 +463,7 @@ set(files
__locale_dir/locale_base_api/bsd_locale_fallbacks.h
__locale_dir/locale_base_api/locale_guard.h
__mbstate_t.h
+ __mdspan/extents.h
__memory/addressof.h
__memory/align.h
__memory/aligned_alloc.h
@@ -913,6 +914,7 @@ set(files
locale.h
map
math.h
+ mdspan
memory
memory_resource
mutex
diff --git a/libcxx/include/__mdspan/extents.h b/libcxx/include/__mdspan/extents.h
new file mode 100644
index 000000000000..e31e43493f46
--- /dev/null
+++ b/libcxx/include/__mdspan/extents.h
@@ -0,0 +1,460 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+// Kokkos v. 4.0
+// Copyright (2022) National Technology & Engineering
+// Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___MDSPAN_EXTENTS_H
+#define _LIBCPP___MDSPAN_EXTENTS_H
+
+#include <__assert>
+#include <__config>
+#include <__type_traits/common_type.h>
+#include <__type_traits/is_convertible.h>
+#include <__type_traits/is_nothrow_constructible.h>
+#include <__type_traits/is_same.h>
+#include <__type_traits/make_unsigned.h>
+#include <__utility/integer_sequence.h>
+#include <__utility/unreachable.h>
+#include <array>
+#include <cinttypes>
+#include <concepts>
+#include <cstddef>
+#include <limits>
+#include <span>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if _LIBCPP_STD_VER >= 23
+
+namespace __mdspan_detail {
+
+// ------------------------------------------------------------------
+// ------------ __static_array --------------------------------------
+// ------------------------------------------------------------------
+// array like class which provides an array of static values with get
+template <class _Tp, _Tp... _Values>
+struct __static_array {
+ static constexpr array<_Tp, sizeof...(_Values)> __array = {_Values...};
+
+public:
+ _LIBCPP_HIDE_FROM_ABI static constexpr size_t __size() { return sizeof...(_Values); }
+ _LIBCPP_HIDE_FROM_ABI static constexpr _Tp __get(size_t __index) noexcept { return __array[__index]; }
+
+ template <size_t _Index>
+ _LIBCPP_HIDE_FROM_ABI static constexpr _Tp __get() {
+ return __get(_Index);
+ }
+};
+
+// ------------------------------------------------------------------
+// ------------ __possibly_empty_array -----------------------------
+// ------------------------------------------------------------------
+
+// array like class which provides get function and operator [], and
+// has a specialization for the size 0 case.
+// This is needed to make the __maybe_static_array be truly empty, for
+// all static values.
+
+template <class _Tp, size_t _Size>
+struct __possibly_empty_array {
+ _Tp __vals_[_Size];
+ _LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator[](size_t __index) { return __vals_[__index]; }
+ _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& operator[](size_t __index) const { return __vals_[__index]; }
+};
+
+template <class _Tp>
+struct __possibly_empty_array<_Tp, 0> {
+ _LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator[](size_t) { __libcpp_unreachable(); }
+ _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& operator[](size_t) const { __libcpp_unreachable(); }
+};
+
+// ------------------------------------------------------------------
+// ------------ static_partial_sums ---------------------------------
+// ------------------------------------------------------------------
+
+// Provides a compile time partial sum one can index into
+
+template <size_t... _Values>
+struct __static_partial_sums {
+ _LIBCPP_HIDE_FROM_ABI static constexpr array<size_t, sizeof...(_Values)> __static_partial_sums_impl() {
+ array<size_t, sizeof...(_Values)> __values{_Values...};
+ array<size_t, sizeof...(_Values)> __partial_sums{{}};
+ size_t __running_sum = 0;
+ for (int __i = 0; __i != sizeof...(_Values); ++__i) {
+ __partial_sums[__i] = __running_sum;
+ __running_sum += __values[__i];
+ }
+ return __partial_sums;
+ }
+ static constexpr array<size_t, sizeof...(_Values)> __result{__static_partial_sums_impl()};
+
+ _LIBCPP_HIDE_FROM_ABI static constexpr size_t __get(size_t __index) { return __result[__index]; }
+};
+
+// ------------------------------------------------------------------
+// ------------ __maybe_static_array --------------------------------
+// ------------------------------------------------------------------
+
+// array like class which has a mix of static and runtime values but
+// only stores the runtime values.
+// The type of the static and the runtime values can be different.
+// The position of a dynamic value is indicated through a tag value.
+template <class _TDynamic, class _TStatic, _TStatic _DynTag, _TStatic... _Values>
+struct __maybe_static_array {
+ static_assert(is_convertible<_TStatic, _TDynamic>::value,
+ "__maybe_static_array: _TStatic must be convertible to _TDynamic");
+ static_assert(is_convertible<_TDynamic, _TStatic>::value,
+ "__maybe_static_array: _TDynamic must be convertible to _TStatic");
+
+private:
+ // Static values member
+ static constexpr size_t __size_ = sizeof...(_Values);
+ static constexpr size_t __size_dynamic_ = ((_Values == _DynTag) + ... + 0);
+ using _StaticValues = __static_array<_TStatic, _Values...>;
+ using _DynamicValues = __possibly_empty_array<_TDynamic, __size_dynamic_>;
+
+ // Dynamic values member
+ _LIBCPP_NO_UNIQUE_ADDRESS _DynamicValues __dyn_vals_;
+
+ // static mapping of indices to the position in the dynamic values array
+ using _DynamicIdxMap = __static_partial_sums<static_cast<size_t>(_Values == _DynTag)...>;
+
+ template <size_t... Indices>
+ _LIBCPP_HIDE_FROM_ABI static constexpr _DynamicValues __zeros(index_sequence<Indices...>) noexcept {
+ return _DynamicValues{((void)Indices, 0)...};
+ }
+
+public:
+ _LIBCPP_HIDE_FROM_ABI constexpr __maybe_static_array() noexcept
+ : __dyn_vals_{__zeros(make_index_sequence<__size_dynamic_>())} {}
+
+ // constructors from dynamic values only -- this covers the case for rank() == 0
+ template <class... _DynVals>
+ requires(sizeof...(_DynVals) == __size_dynamic_)
+ _LIBCPP_HIDE_FROM_ABI constexpr __maybe_static_array(_DynVals... __vals)
+ : __dyn_vals_{static_cast<_TDynamic>(__vals)...} {}
+
+ template <class _Tp, size_t _Size >
+ requires(_Size == __size_dynamic_)
+ _LIBCPP_HIDE_FROM_ABI constexpr __maybe_static_array([[maybe_unused]] const span<_Tp, _Size>& __vals) {
+ if constexpr (_Size > 0) {
+ for (size_t __i = 0; __i < _Size; __i++)
+ __dyn_vals_[__i] = static_cast<_TDynamic>(__vals[__i]);
+ }
+ }
+
+ // constructors from all values -- here rank will be greater than 0
+ template <class... _DynVals>
+ requires(sizeof...(_DynVals) != __size_dynamic_)
+ _LIBCPP_HIDE_FROM_ABI constexpr __maybe_static_array(_DynVals... __vals) {
+ static_assert((sizeof...(_DynVals) == __size_), "Invalid number of values.");
+ _TDynamic __values[__size_] = {static_cast<_TDynamic>(__vals)...};
+ for (size_t __i = 0; __i < __size_; __i++) {
+ _TStatic __static_val = _StaticValues::__get(__i);
+ if (__static_val == _DynTag) {
+ __dyn_vals_[_DynamicIdxMap::__get(__i)] = __values[__i];
+ }
+ // Precondition check
+ else
+ _LIBCPP_ASSERT(__values[__i] == static_cast<_TDynamic>(__static_val),
+ "extents construction: mismatch of provided arguments with static extents.");
+ }
+ }
+
+ template <class _Tp, size_t _Size>
+ requires(_Size != __size_dynamic_)
+ _LIBCPP_HIDE_FROM_ABI constexpr __maybe_static_array(const span<_Tp, _Size>& __vals) {
+ static_assert((_Size == __size_) || (__size_ == dynamic_extent));
+ for (size_t __i = 0; __i < __size_; __i++) {
+ _TStatic __static_val = _StaticValues::__get(__i);
+ if (__static_val == _DynTag) {
+ __dyn_vals_[_DynamicIdxMap::__get(__i)] = static_cast<_TDynamic>(__vals[__i]);
+ }
+ // Precondition check
+ else
+ _LIBCPP_ASSERT(static_cast<_TDynamic>(__vals[__i]) == static_cast<_TDynamic>(__static_val),
+ "extents construction: mismatch of provided arguments with static extents.");
+ }
+ }
+
+ // access functions
+ _LIBCPP_HIDE_FROM_ABI static constexpr _TStatic __static_value(size_t __i) noexcept {
+ _LIBCPP_ASSERT(__i < __size_, "extents access: index must be less than rank");
+ return _StaticValues::__get(__i);
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr _TDynamic __value(size_t __i) const {
+ _LIBCPP_ASSERT(__i < __size_, "extents access: index must be less than rank");
+ _TStatic __static_val = _StaticValues::__get(__i);
+ return __static_val == _DynTag ? __dyn_vals_[_DynamicIdxMap::__get(__i)] : static_cast<_TDynamic>(__static_val);
+ }
+ _LIBCPP_HIDE_FROM_ABI constexpr _TDynamic operator[](size_t __i) const {
+ _LIBCPP_ASSERT(__i < __size_, "extents access: index must be less than rank");
+ return __value(__i);
+ }
+
+ // observers
+ _LIBCPP_HIDE_FROM_ABI static constexpr size_t __size() { return __size_; }
+ _LIBCPP_HIDE_FROM_ABI static constexpr size_t __size_dynamic() { return __size_dynamic_; }
+};
+
+// Function to check whether a value is representable as another type
+// value must be a positive integer otherwise returns false
+// if _From is not an integral, we just check positivity
+template <integral _To, class _From>
+ requires(is_integral_v<_From>)
+_LIBCPP_HIDE_FROM_ABI constexpr bool __is_representable_as(_From __value) {
+ using _To_u = make_unsigned_t<_To>;
+ using _From_u = make_unsigned_t<_From>;
+ if constexpr (is_signed_v<_From>) {
+ if (__value < 0)
+ return false;
+ }
+ if constexpr (static_cast<_To_u>(numeric_limits<_To>::max()) >= static_cast<_From_u>(numeric_limits<_From>::max())) {
+ return true;
+ } else {
+ return static_cast<_To_u>(numeric_limits<_To>::max()) >= static_cast<_From_u>(__value);
+ }
+}
+
+template <integral _To, class _From>
+ requires(!is_integral_v<_From>)
+_LIBCPP_HIDE_FROM_ABI constexpr bool __is_representable_as(_From __value) {
+ if constexpr (is_signed_v<_To>) {
+ if (static_cast<_To>(__value) < 0)
+ return false;
+ }
+ return true;
+}
+
+template <integral _To, class... _From>
+_LIBCPP_HIDE_FROM_ABI constexpr bool __are_representable_as(_From... __values) {
+ return (__mdspan_detail::__is_representable_as<_To>(__values) && ... && true);
+}
+
+template <integral _To, class _From, size_t _Size>
+_LIBCPP_HIDE_FROM_ABI constexpr bool __are_representable_as(span<_From, _Size> __values) {
+ for (size_t __i = 0; __i < _Size; __i++)
+ if (!__mdspan_detail::__is_representable_as<_To>(__values[__i]))
+ return false;
+ return true;
+}
+
+} // namespace __mdspan_detail
+
+// ------------------------------------------------------------------
+// ------------ extents ---------------------------------------------
+// ------------------------------------------------------------------
+
+// Class to describe the extents of a multi dimensional array.
+// Used by mdspan, mdarray and layout mappings.
+// See ISO C++ standard [mdspan.extents]
+
+template <class _IndexType, size_t... _Extents>
+class extents {
+public:
+ // typedefs for integral types used
+ using index_type = _IndexType;
+ using size_type = make_unsigned_t<index_type>;
+ using rank_type = size_t;
+
+ static_assert(is_integral<index_type>::value && !is_same<index_type, bool>::value,
+ "extents::index_type must be a signed or unsigned integer type");
+ static_assert(((__mdspan_detail::__is_representable_as<index_type>(_Extents) || (_Extents == dynamic_extent)) && ...),
+ "extents ctor: arguments must be representable as index_type and nonnegative");
+
+private:
+ static constexpr rank_type __rank_ = sizeof...(_Extents);
+ static constexpr rank_type __rank_dynamic_ = ((_Extents == dynamic_extent) + ... + 0);
+
+ // internal storage type using __maybe_static_array
+ using _Values = __mdspan_detail::__maybe_static_array<_IndexType, size_t, dynamic_extent, _Extents...>;
+ [[no_unique_address]] _Values __vals_;
+
+public:
+ // [mdspan.extents.obs], observers of multidimensional index space
+ _LIBCPP_HIDE_FROM_ABI static constexpr rank_type rank() noexcept { return __rank_; }
+ _LIBCPP_HIDE_FROM_ABI static constexpr rank_type rank_dynamic() noexcept { return __rank_dynamic_; }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr index_type extent(rank_type __r) const noexcept { return __vals_.__value(__r); }
+ _LIBCPP_HIDE_FROM_ABI static constexpr size_t static_extent(rank_type __r) noexcept {
+ return _Values::__static_value(__r);
+ }
+
+ // [mdspan.extents.cons], constructors
+ _LIBCPP_HIDE_FROM_ABI constexpr extents() noexcept = default;
+
+ // 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
+ : __vals_(static_cast<index_type>(__dynvals)...) {
+ _LIBCPP_ASSERT(__mdspan_detail::__are_representable_as<index_type>(__dynvals...),
+ "extents ctor: arguments must be representable as index_type and nonnegative");
+ }
+
+ template <class _OtherIndexType, size_t _Size>
+ requires(is_convertible_v<_OtherIndexType, index_type> && is_nothrow_constructible_v<index_type, _OtherIndexType> &&
+ (_Size == __rank_ || _Size == __rank_dynamic_))
+ explicit(_Size != __rank_dynamic_)
+ _LIBCPP_HIDE_FROM_ABI constexpr extents(const array<_OtherIndexType, _Size>& __exts) noexcept
+ : __vals_(span(__exts)) {
+ _LIBCPP_ASSERT(__mdspan_detail::__are_representable_as<index_type>(span(__exts)),
+ "extents ctor: arguments must be representable as index_type and nonnegative");
+ }
+
+ template <class _OtherIndexType, size_t _Size>
+ requires(is_convertible_v<_OtherIndexType, index_type> && is_nothrow_constructible_v<index_type, _OtherIndexType> &&
+ (_Size == __rank_ || _Size == __rank_dynamic_))
+ explicit(_Size != __rank_dynamic_)
+ _LIBCPP_HIDE_FROM_ABI constexpr extents(const span<_OtherIndexType, _Size>& __exts) noexcept
+ : __vals_(__exts) {
+ _LIBCPP_ASSERT(__mdspan_detail::__are_representable_as<index_type>(__exts),
+ "extents ctor: arguments must be representable as index_type and nonnegative");
+ }
+
+private:
+ // Function to construct extents storage from other extents.
+ template <size_t _DynCount, size_t _Idx, class _OtherExtents, class... _DynamicValues>
+ requires(_Idx < __rank_)
+ _LIBCPP_HIDE_FROM_ABI constexpr _Values __construct_vals_from_extents(
+ integral_constant<size_t, _DynCount>,
+ integral_constant<size_t, _Idx>,
+ const _OtherExtents& __exts,
+ _DynamicValues... __dynamic_values) noexcept {
+ if constexpr (static_extent(_Idx) == dynamic_extent)
+ return __construct_vals_from_extents(
+ integral_constant<size_t, _DynCount + 1>(),
+ integral_constant<size_t, _Idx + 1>(),
+ __exts,
+ __dynamic_values...,
+ __exts.extent(_Idx));
+ else
+ return __construct_vals_from_extents(
+ integral_constant<size_t, _DynCount>(), integral_constant<size_t, _Idx + 1>(), __exts, __dynamic_values...);
+ }
+
+ template <size_t _DynCount, size_t _Idx, class _OtherExtents, class... _DynamicValues>
+ requires((_Idx == __rank_) && (_DynCount == __rank_dynamic_))
+ _LIBCPP_HIDE_FROM_ABI constexpr _Values __construct_vals_from_extents(
+ integral_constant<size_t, _DynCount>,
+ integral_constant<size_t, _Idx>,
+ const _OtherExtents&,
+ _DynamicValues... __dynamic_values) noexcept {
+ return _Values{static_cast<index_type>(__dynamic_values)...};
+ }
+
+public:
+ // Converting constructor from other extents specializations
+ template <class _OtherIndexType, size_t... _OtherExtents>
+ requires((sizeof...(_OtherExtents) == sizeof...(_Extents)) &&
+ ((_OtherExtents == dynamic_extent || _Extents == dynamic_extent || _OtherExtents == _Extents) && ...))
+ explicit((((_Extents != dynamic_extent) && (_OtherExtents == dynamic_extent)) || ...) ||
+ (static_cast<make_unsigned_t<index_type>>(numeric_limits<index_type>::max()) <
+ static_cast<make_unsigned_t<_OtherIndexType>>(numeric_limits<_OtherIndexType>::max())))
+ _LIBCPP_HIDE_FROM_ABI constexpr extents(const extents<_OtherIndexType, _OtherExtents...>& __other) noexcept
+ : __vals_(
+ __construct_vals_from_extents(integral_constant<size_t, 0>(), integral_constant<size_t, 0>(), __other)) {
+ if constexpr (rank() > 0) {
+ for (size_t __r = 0; __r < rank(); __r++) {
+ if constexpr (static_cast<make_unsigned_t<index_type>>(numeric_limits<index_type>::max()) <
+ static_cast<make_unsigned_t<_OtherIndexType>>(numeric_limits<_OtherIndexType>::max())) {
+ _LIBCPP_ASSERT(__mdspan_detail::__is_representable_as<index_type>(__other.extent(__r)),
+ "extents ctor: arguments must be representable as index_type and nonnegative");
+ }
+ _LIBCPP_ASSERT(
+ (_Values::__static_value(__r) == dynamic_extent) ||
+ (static_cast<index_type>(__other.extent(__r)) == static_cast<index_type>(_Values::__static_value(__r))),
+ "extents construction: mismatch of provided arguments with static extents.");
+ }
+ }
+ }
+
+ // Comparison operator
+ template <class _OtherIndexType, size_t... _OtherExtents>
+ _LIBCPP_HIDE_FROM_ABI friend constexpr bool
+ operator==(const extents& __lhs, const extents<_OtherIndexType, _OtherExtents...>& __rhs) noexcept {
+ if constexpr (rank() != sizeof...(_OtherExtents)) {
+ return false;
+ } else {
+ for (rank_type __r = 0; __r < __rank_; __r++) {
+ // avoid warning when comparing signed and unsigner integers and pick the wider of two types
+ using _CommonType = common_type_t<index_type, _OtherIndexType>;
+ if (static_cast<_CommonType>(__lhs.extent(__r)) != static_cast<_CommonType>(__rhs.extent(__r))) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+};
+
+// Recursive helper classes to implement dextents alias for extents
+namespace __mdspan_detail {
+
+template <class _IndexType, size_t _Rank, class _Extents = extents<_IndexType>>
+struct __make_dextents;
+
+template <class _IndexType, size_t _Rank, size_t... _ExtentsPack>
+struct __make_dextents< _IndexType, _Rank, extents<_IndexType, _ExtentsPack...>> {
+ using type =
+ typename __make_dextents< _IndexType, _Rank - 1, extents<_IndexType, dynamic_extent, _ExtentsPack...>>::type;
+};
+
+template <class _IndexType, size_t... _ExtentsPack>
+struct __make_dextents< _IndexType, 0, extents<_IndexType, _ExtentsPack...>> {
+ using type = extents<_IndexType, _ExtentsPack...>;
+};
+
+} // end namespace __mdspan_detail
+
+// [mdspan.extents.dextents], alias template
+template <class _IndexType, size_t _Rank>
+using dextents = typename __mdspan_detail::__make_dextents<_IndexType, _Rank>::type;
+
+// Deduction guide for extents
+template <class... _IndexTypes>
+extents(_IndexTypes...) -> extents<size_t, size_t((_IndexTypes(), dynamic_extent))...>;
+
+// Helper type traits for identifying a class as extents.
+namespace __mdspan_detail {
+
+template <class _Tp>
+struct __is_extents : false_type {};
+
+template <class _IndexType, size_t... _ExtentsPack>
+struct __is_extents<extents<_IndexType, _ExtentsPack...>> : true_type {};
+
+template <class _Tp>
+inline constexpr bool __is_extents_v = __is_extents<_Tp>::value;
+
+} // namespace __mdspan_detail
+
+#endif // _LIBCPP_STD_VER >= 23
+
+_LIBCPP_END_NAMESPACE_STD
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___MDSPAN_EXTENTS_H
diff --git a/libcxx/include/libcxx.imp b/libcxx/include/libcxx.imp
index 271812e9eb9d..8414773228bb 100644
--- a/libcxx/include/libcxx.imp
+++ b/libcxx/include/libcxx.imp
@@ -33,6 +33,7 @@
{ include: [ "@<__ios/.*>", "private", "<ios>", "public" ] },
{ include: [ "@<__iterator/.*>", "private", "<iterator>", "public" ] },
{ include: [ "@<__locale_dir/.*>", "private", "<locale>", "public" ] },
+ { include: [ "@<__mdspan/.*>", "private", "<mdspan>", "public" ] },
{ include: [ "@<__memory/.*>", "private", "<memory>", "public" ] },
{ include: [ "@<__memory_resource/.*>", "private", "<memory_resource>", "public" ] },
{ include: [ "@<__mutex/.*>", "private", "<mutex>", "public" ] },
diff --git a/libcxx/include/mdspan b/libcxx/include/mdspan
new file mode 100644
index 000000000000..16b4e3e1641a
--- /dev/null
+++ b/libcxx/include/mdspan
@@ -0,0 +1,69 @@
+// -*-C++ - *-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+
+/*
+ extents synopsis
+
+namespace std {
+ template<class _IndexType, size_t... _Extents>
+ class extents {
+ public:
+ using index_type = _IndexType;
+ using size_type = make_unsigned_t<index_type>;
+ using rank_type = size_t;
+
+ // [mdspan.extents.obs], observers of the multidimensional index space
+ static constexpr rank_type rank() noexcept { return sizeof...(_Extents); }
+ static constexpr rank_type rank_dynamic() noexcept { return dynamic-index(rank()); }
+ static constexpr size_t static_extent(rank_type) noexcept;
+ constexpr index_type extent(rank_type) const noexcept;
+
+ // [mdspan.extents.cons], constructors
+ constexpr extents() noexcept = default;
+
+ template<class _OtherIndexType, size_t... _OtherExtents>
+ constexpr explicit(see below)
+ extents(const extents<_OtherIndexType, _OtherExtents...>&) noexcept;
+ template<class... _OtherIndexTypes>
+ constexpr explicit extents(_OtherIndexTypes...) noexcept;
+ template<class _OtherIndexType, size_t N>
+ constexpr explicit(N != rank_dynamic())
+ extents(span<_OtherIndexType, N>) noexcept;
+ template<class _OtherIndexType, size_t N>
+ constexpr explicit(N != rank_dynamic())
+ extents(const array<_OtherIndexType, N>&) noexcept;
+
+ // [mdspan.extents.cmp], comparison operators
+ template<class _OtherIndexType, size_t... _OtherExtents>
+ friend constexpr bool operator==(const extents&,
+ const extents<_OtherIndexType, _OtherExtents...>&) noexcept;
+
+ private:
+ // libcxx note: we do not use an array here, but we need to preserve the as-if behavior
+ // for example the default constructor must zero initialize dynamic extents
+ array<index_type, rank_dynamic()> dynamic-extents{}; // exposition only
+ };
+
+ template<class... Integrals>
+ explicit extents(Integrals...)
+ -> see below;
+}
+*/
+
+#ifndef _LIBCPP_MDSPAN
+#define _LIBCPP_MDSPAN
+
+#include <__config>
+#include <__mdspan/extents.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+#endif // _LIBCPP_MDSPAN
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index af65d60227af..7bde1becba5d 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -1162,6 +1162,16 @@ module std [system] {
export initializer_list
export *
}
+ module mdspan {
+ header "mdspan"
+ export array
+ export span
+ export *
+
+ module __mdspan {
+ module extents { private header "__mdspan/extents.h" }
+ }
+ }
module memory {
header "memory"
export *
diff --git a/libcxx/include/version b/libcxx/include/version
index f58b51e49fee..b87abdfce522 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -123,6 +123,7 @@ __cpp_lib_make_unique 201304L <memory>
__cpp_lib_map_try_emplace 201411L <map>
__cpp_lib_math_constants 201907L <numbers>
__cpp_lib_math_special_functions 201603L <cmath>
+__cpp_lib_mdspan 202207L <mdspan>
__cpp_lib_memory_resource 201603L <memory_resource>
__cpp_lib_move_iterator_concept 202207L <iterator>
__cpp_lib_move_only_function 202110L <functional>
@@ -408,6 +409,7 @@ __cpp_lib_void_t 201411L <type_traits>
# define __cpp_lib_forward_like 202207L
# define __cpp_lib_invoke_r 202106L
# define __cpp_lib_is_scoped_enum 202011L
+// # define __cpp_lib_mdspan 202207L
// # define __cpp_lib_move_only_function 202110L
# undef __cpp_lib_optional
# define __cpp_lib_optional 202110L
diff --git a/libcxx/test/libcxx/assertions/headers_declare_verbose_abort.sh.cpp b/libcxx/test/libcxx/assertions/headers_declare_verbose_abort.sh.cpp
index 1f2a4650c9d5..5587e21a131a 100644
--- a/libcxx/test/libcxx/assertions/headers_declare_verbose_abort.sh.cpp
+++ b/libcxx/test/libcxx/assertions/headers_declare_verbose_abort.sh.cpp
@@ -418,330 +418,336 @@ int main(int, char**) { return 0; }
// RUN: %{build} -DTEST_71
#if defined(TEST_71)
-# include <memory>
+# include <mdspan>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
// RUN: %{build} -DTEST_72
#if defined(TEST_72)
-# include <memory_resource>
+# include <memory>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
// RUN: %{build} -DTEST_73
-#if defined(TEST_73) && !defined(_LIBCPP_HAS_NO_THREADS)
-# include <mutex>
+#if defined(TEST_73)
+# include <memory_resource>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
// RUN: %{build} -DTEST_74
-#if defined(TEST_74)
-# include <new>
+#if defined(TEST_74) && !defined(_LIBCPP_HAS_NO_THREADS)
+# include <mutex>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
// RUN: %{build} -DTEST_75
#if defined(TEST_75)
-# include <numbers>
+# include <new>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
// RUN: %{build} -DTEST_76
#if defined(TEST_76)
-# include <numeric>
+# include <numbers>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
// RUN: %{build} -DTEST_77
#if defined(TEST_77)
-# include <optional>
+# include <numeric>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
// RUN: %{build} -DTEST_78
-#if defined(TEST_78) && !defined(_LIBCPP_HAS_NO_LOCALIZATION)
-# include <ostream>
+#if defined(TEST_78)
+# include <optional>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
// RUN: %{build} -DTEST_79
-#if defined(TEST_79)
-# include <queue>
+#if defined(TEST_79) && !defined(_LIBCPP_HAS_NO_LOCALIZATION)
+# include <ostream>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
// RUN: %{build} -DTEST_80
#if defined(TEST_80)
-# include <random>
+# include <queue>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
// RUN: %{build} -DTEST_81
#if defined(TEST_81)
-# include <ranges>
+# include <random>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
// RUN: %{build} -DTEST_82
#if defined(TEST_82)
-# include <ratio>
+# include <ranges>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
// RUN: %{build} -DTEST_83
-#if defined(TEST_83) && !defined(_LIBCPP_HAS_NO_LOCALIZATION)
-# include <regex>
+#if defined(TEST_83)
+# include <ratio>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
// RUN: %{build} -DTEST_84
-#if defined(TEST_84)
-# include <scoped_allocator>
+#if defined(TEST_84) && !defined(_LIBCPP_HAS_NO_LOCALIZATION)
+# include <regex>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
// RUN: %{build} -DTEST_85
-#if defined(TEST_85) && !defined(_LIBCPP_HAS_NO_THREADS)
-# include <semaphore>
+#if defined(TEST_85)
+# include <scoped_allocator>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
// RUN: %{build} -DTEST_86
-#if defined(TEST_86)
-# include <set>
+#if defined(TEST_86) && !defined(_LIBCPP_HAS_NO_THREADS)
+# include <semaphore>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
-// RUN: %{build} -DTEST_88
-#if defined(TEST_88) && !defined(_LIBCPP_HAS_NO_THREADS)
-# include <shared_mutex>
+// RUN: %{build} -DTEST_87
+#if defined(TEST_87)
+# include <set>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
// RUN: %{build} -DTEST_89
-#if defined(TEST_89)
-# include <source_location>
+#if defined(TEST_89) && !defined(_LIBCPP_HAS_NO_THREADS)
+# include <shared_mutex>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
// RUN: %{build} -DTEST_90
#if defined(TEST_90)
-# include <span>
+# include <source_location>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
// RUN: %{build} -DTEST_91
-#if defined(TEST_91) && !defined(_LIBCPP_HAS_NO_LOCALIZATION)
-# include <sstream>
+#if defined(TEST_91)
+# include <span>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
// RUN: %{build} -DTEST_92
-#if defined(TEST_92)
+#if defined(TEST_92) && !defined(_LIBCPP_HAS_NO_LOCALIZATION)
+# include <sstream>
+ using HandlerType = decltype(std::__libcpp_verbose_abort);
+#endif
+
+// RUN: %{build} -DTEST_93
+#if defined(TEST_93)
# include <stack>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
-// RUN: %{build} -DTEST_96
-#if defined(TEST_96)
+// RUN: %{build} -DTEST_97
+#if defined(TEST_97)
# include <stdexcept>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
-// RUN: %{build} -DTEST_100
-#if defined(TEST_100) && !defined(_LIBCPP_HAS_NO_LOCALIZATION)
+// RUN: %{build} -DTEST_101
+#if defined(TEST_101) && !defined(_LIBCPP_HAS_NO_LOCALIZATION)
# include <streambuf>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
-// RUN: %{build} -DTEST_101
-#if defined(TEST_101)
+// RUN: %{build} -DTEST_102
+#if defined(TEST_102)
# include <string>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
-// RUN: %{build} -DTEST_103
-#if defined(TEST_103)
+// RUN: %{build} -DTEST_104
+#if defined(TEST_104)
# include <string_view>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
-// RUN: %{build} -DTEST_104
-#if defined(TEST_104) && !defined(_LIBCPP_HAS_NO_LOCALIZATION)
+// RUN: %{build} -DTEST_105
+#if defined(TEST_105) && !defined(_LIBCPP_HAS_NO_LOCALIZATION)
# include <strstream>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
-// RUN: %{build} -DTEST_105
-#if defined(TEST_105)
+// RUN: %{build} -DTEST_106
+#if defined(TEST_106)
# include <system_error>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
-// RUN: %{build} -DTEST_107
-#if defined(TEST_107) && !defined(_LIBCPP_HAS_NO_THREADS)
-# include <thread>
- using HandlerType = decltype(std::__libcpp_verbose_abort);
-#endif
-
// RUN: %{build} -DTEST_108
-#if defined(TEST_108)
-# include <tuple>
+#if defined(TEST_108) && !defined(_LIBCPP_HAS_NO_THREADS)
+# include <thread>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
// RUN: %{build} -DTEST_109
#if defined(TEST_109)
-# include <type_traits>
+# include <tuple>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
// RUN: %{build} -DTEST_110
#if defined(TEST_110)
-# include <typeindex>
+# include <type_traits>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
// RUN: %{build} -DTEST_111
#if defined(TEST_111)
-# include <typeinfo>
+# include <typeindex>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
-// RUN: %{build} -DTEST_113
-#if defined(TEST_113)
-# include <unordered_map>
+// RUN: %{build} -DTEST_112
+#if defined(TEST_112)
+# include <typeinfo>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
// RUN: %{build} -DTEST_114
#if defined(TEST_114)
-# include <unordered_set>
+# include <unordered_map>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
// RUN: %{build} -DTEST_115
#if defined(TEST_115)
-# include <utility>
+# include <unordered_set>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
// RUN: %{build} -DTEST_116
#if defined(TEST_116)
-# include <valarray>
+# include <utility>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
// RUN: %{build} -DTEST_117
#if defined(TEST_117)
-# include <variant>
+# include <valarray>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
// RUN: %{build} -DTEST_118
#if defined(TEST_118)
-# include <vector>
+# include <variant>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
// RUN: %{build} -DTEST_119
#if defined(TEST_119)
-# include <version>
+# include <vector>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
-// RUN: %{build} -DTEST_122
-#if defined(TEST_122) && __cplusplus >= 201103L
-# include <experimental/deque>
+// RUN: %{build} -DTEST_120
+#if defined(TEST_120)
+# include <version>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
// RUN: %{build} -DTEST_123
#if defined(TEST_123) && __cplusplus >= 201103L
-# include <experimental/forward_list>
+# include <experimental/deque>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
// RUN: %{build} -DTEST_124
#if defined(TEST_124) && __cplusplus >= 201103L
-# include <experimental/iterator>
+# include <experimental/forward_list>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
// RUN: %{build} -DTEST_125
#if defined(TEST_125) && __cplusplus >= 201103L
-# include <experimental/list>
+# include <experimental/iterator>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
// RUN: %{build} -DTEST_126
#if defined(TEST_126) && __cplusplus >= 201103L
-# include <experimental/map>
+# include <experimental/list>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
// RUN: %{build} -DTEST_127
#if defined(TEST_127) && __cplusplus >= 201103L
-# include <experimental/memory_resource>
+# include <experimental/map>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
// RUN: %{build} -DTEST_128
#if defined(TEST_128) && __cplusplus >= 201103L
-# include <experimental/propagate_const>
+# include <experimental/memory_resource>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
// RUN: %{build} -DTEST_129
-#if defined(TEST_129) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) && __cplusplus >= 201103L
-# include <experimental/regex>
+#if defined(TEST_129) && __cplusplus >= 201103L
+# include <experimental/propagate_const>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
// RUN: %{build} -DTEST_130
-#if defined(TEST_130) && __cplusplus >= 201103L
-# include <experimental/set>
+#if defined(TEST_130) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) && __cplusplus >= 201103L
+# include <experimental/regex>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
// RUN: %{build} -DTEST_131
#if defined(TEST_131) && __cplusplus >= 201103L
-# include <experimental/simd>
+# include <experimental/set>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
// RUN: %{build} -DTEST_132
#if defined(TEST_132) && __cplusplus >= 201103L
-# include <experimental/string>
+# include <experimental/simd>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
// RUN: %{build} -DTEST_133
#if defined(TEST_133) && __cplusplus >= 201103L
-# include <experimental/type_traits>
+# include <experimental/string>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
// RUN: %{build} -DTEST_134
#if defined(TEST_134) && __cplusplus >= 201103L
-# include <experimental/unordered_map>
+# include <experimental/type_traits>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
// RUN: %{build} -DTEST_135
#if defined(TEST_135) && __cplusplus >= 201103L
-# include <experimental/unordered_set>
+# include <experimental/unordered_map>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
// RUN: %{build} -DTEST_136
#if defined(TEST_136) && __cplusplus >= 201103L
-# include <experimental/utility>
+# include <experimental/unordered_set>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
// RUN: %{build} -DTEST_137
#if defined(TEST_137) && __cplusplus >= 201103L
+# include <experimental/utility>
+ using HandlerType = decltype(std::__libcpp_verbose_abort);
+#endif
+
+// RUN: %{build} -DTEST_138
+#if defined(TEST_138) && __cplusplus >= 201103L
# include <experimental/vector>
using HandlerType = decltype(std::__libcpp_verbose_abort);
#endif
diff --git a/libcxx/test/libcxx/clang_tidy.sh.cpp b/libcxx/test/libcxx/clang_tidy.sh.cpp
index ab9bbc6c3914..c4bce6b155f3 100644
--- a/libcxx/test/libcxx/clang_tidy.sh.cpp
+++ b/libcxx/test/libcxx/clang_tidy.sh.cpp
@@ -134,6 +134,7 @@ END-SCRIPT
#endif
#include <map>
#include <math.h>
+#include <mdspan>
#include <memory>
#include <memory_resource>
#if !defined(_LIBCPP_HAS_NO_THREADS)
diff --git a/libcxx/test/libcxx/double_include.sh.cpp b/libcxx/test/libcxx/double_include.sh.cpp
index 292f53a0d077..7f61fef65662 100644
--- a/libcxx/test/libcxx/double_include.sh.cpp
+++ b/libcxx/test/libcxx/double_include.sh.cpp
@@ -132,6 +132,7 @@ END-SCRIPT
#endif
#include <map>
#include <math.h>
+#include <mdspan>
#include <memory>
#include <memory_resource>
#if !defined(_LIBCPP_HAS_NO_THREADS)
diff --git a/libcxx/test/libcxx/min_max_macros.compile.pass.cpp b/libcxx/test/libcxx/min_max_macros.compile.pass.cpp
index d032e97f1ddc..0bd4c4791b29 100644
--- a/libcxx/test/libcxx/min_max_macros.compile.pass.cpp
+++ b/libcxx/test/libcxx/min_max_macros.compile.pass.cpp
@@ -203,6 +203,8 @@ TEST_MACROS();
TEST_MACROS();
#include <math.h>
TEST_MACROS();
+#include <mdspan>
+TEST_MACROS();
#include <memory>
TEST_MACROS();
#include <memory_resource>
diff --git a/libcxx/test/libcxx/modules_include.sh.cpp b/libcxx/test/libcxx/modules_include.sh.cpp
index 3f3967aa418b..8a625890f760 100644
--- a/libcxx/test/libcxx/modules_include.sh.cpp
+++ b/libcxx/test/libcxx/modules_include.sh.cpp
@@ -465,405 +465,410 @@ END-SCRIPT
// RUN: echo 'TEST_71=$!' >> %t.sh
// RUN: echo "wait $TEST_55" >> %t.sh
#if defined(TEST_71)
-#include <memory>
+#include <mdspan>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_72 &' >> %t.sh
// RUN: echo 'TEST_72=$!' >> %t.sh
// RUN: echo "wait $TEST_56" >> %t.sh
#if defined(TEST_72)
-#include <memory_resource>
+#include <memory>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_73 &' >> %t.sh
// RUN: echo 'TEST_73=$!' >> %t.sh
// RUN: echo "wait $TEST_57" >> %t.sh
-#if defined(TEST_73) && !defined(_LIBCPP_HAS_NO_THREADS)
-#include <mutex>
+#if defined(TEST_73)
+#include <memory_resource>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_74 &' >> %t.sh
// RUN: echo 'TEST_74=$!' >> %t.sh
// RUN: echo "wait $TEST_58" >> %t.sh
-#if defined(TEST_74)
-#include <new>
+#if defined(TEST_74) && !defined(_LIBCPP_HAS_NO_THREADS)
+#include <mutex>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_75 &' >> %t.sh
// RUN: echo 'TEST_75=$!' >> %t.sh
// RUN: echo "wait $TEST_59" >> %t.sh
#if defined(TEST_75)
-#include <numbers>
+#include <new>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_76 &' >> %t.sh
// RUN: echo 'TEST_76=$!' >> %t.sh
// RUN: echo "wait $TEST_60" >> %t.sh
#if defined(TEST_76)
-#include <numeric>
+#include <numbers>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_77 &' >> %t.sh
// RUN: echo 'TEST_77=$!' >> %t.sh
// RUN: echo "wait $TEST_61" >> %t.sh
#if defined(TEST_77)
-#include <optional>
+#include <numeric>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_78 &' >> %t.sh
// RUN: echo 'TEST_78=$!' >> %t.sh
// RUN: echo "wait $TEST_62" >> %t.sh
-#if defined(TEST_78) && !defined(_LIBCPP_HAS_NO_LOCALIZATION)
-#include <ostream>
+#if defined(TEST_78)
+#include <optional>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_79 &' >> %t.sh
// RUN: echo 'TEST_79=$!' >> %t.sh
// RUN: echo "wait $TEST_63" >> %t.sh
-#if defined(TEST_79)
-#include <queue>
+#if defined(TEST_79) && !defined(_LIBCPP_HAS_NO_LOCALIZATION)
+#include <ostream>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_80 &' >> %t.sh
// RUN: echo 'TEST_80=$!' >> %t.sh
// RUN: echo "wait $TEST_64" >> %t.sh
#if defined(TEST_80)
-#include <random>
+#include <queue>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_81 &' >> %t.sh
// RUN: echo 'TEST_81=$!' >> %t.sh
// RUN: echo "wait $TEST_65" >> %t.sh
#if defined(TEST_81)
-#include <ranges>
+#include <random>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_82 &' >> %t.sh
// RUN: echo 'TEST_82=$!' >> %t.sh
// RUN: echo "wait $TEST_66" >> %t.sh
#if defined(TEST_82)
-#include <ratio>
+#include <ranges>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_83 &' >> %t.sh
// RUN: echo 'TEST_83=$!' >> %t.sh
// RUN: echo "wait $TEST_67" >> %t.sh
-#if defined(TEST_83) && !defined(_LIBCPP_HAS_NO_LOCALIZATION)
-#include <regex>
+#if defined(TEST_83)
+#include <ratio>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_84 &' >> %t.sh
// RUN: echo 'TEST_84=$!' >> %t.sh
// RUN: echo "wait $TEST_68" >> %t.sh
-#if defined(TEST_84)
-#include <scoped_allocator>
+#if defined(TEST_84) && !defined(_LIBCPP_HAS_NO_LOCALIZATION)
+#include <regex>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_85 &' >> %t.sh
// RUN: echo 'TEST_85=$!' >> %t.sh
// RUN: echo "wait $TEST_69" >> %t.sh
-#if defined(TEST_85) && !defined(_LIBCPP_HAS_NO_THREADS)
-#include <semaphore>
+#if defined(TEST_85)
+#include <scoped_allocator>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_86 &' >> %t.sh
// RUN: echo 'TEST_86=$!' >> %t.sh
// RUN: echo "wait $TEST_70" >> %t.sh
-#if defined(TEST_86)
-#include <set>
+#if defined(TEST_86) && !defined(_LIBCPP_HAS_NO_THREADS)
+#include <semaphore>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_87 &' >> %t.sh
// RUN: echo 'TEST_87=$!' >> %t.sh
// RUN: echo "wait $TEST_71" >> %t.sh
#if defined(TEST_87)
-#include <setjmp.h>
+#include <set>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_88 &' >> %t.sh
// RUN: echo 'TEST_88=$!' >> %t.sh
// RUN: echo "wait $TEST_72" >> %t.sh
-#if defined(TEST_88) && !defined(_LIBCPP_HAS_NO_THREADS)
-#include <shared_mutex>
+#if defined(TEST_88)
+#include <setjmp.h>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_89 &' >> %t.sh
// RUN: echo 'TEST_89=$!' >> %t.sh
// RUN: echo "wait $TEST_73" >> %t.sh
-#if defined(TEST_89)
-#include <source_location>
+#if defined(TEST_89) && !defined(_LIBCPP_HAS_NO_THREADS)
+#include <shared_mutex>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_90 &' >> %t.sh
// RUN: echo 'TEST_90=$!' >> %t.sh
// RUN: echo "wait $TEST_74" >> %t.sh
#if defined(TEST_90)
-#include <span>
+#include <source_location>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_91 &' >> %t.sh
// RUN: echo 'TEST_91=$!' >> %t.sh
// RUN: echo "wait $TEST_75" >> %t.sh
-#if defined(TEST_91) && !defined(_LIBCPP_HAS_NO_LOCALIZATION)
-#include <sstream>
+#if defined(TEST_91)
+#include <span>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_92 &' >> %t.sh
// RUN: echo 'TEST_92=$!' >> %t.sh
// RUN: echo "wait $TEST_76" >> %t.sh
-#if defined(TEST_92)
-#include <stack>
+#if defined(TEST_92) && !defined(_LIBCPP_HAS_NO_LOCALIZATION)
+#include <sstream>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_93 &' >> %t.sh
// RUN: echo 'TEST_93=$!' >> %t.sh
// RUN: echo "wait $TEST_77" >> %t.sh
-#if defined(TEST_93) && __cplusplus > 202002L && !defined(_LIBCPP_HAS_NO_THREADS)
-#include <stdatomic.h>
+#if defined(TEST_93)
+#include <stack>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_94 &' >> %t.sh
// RUN: echo 'TEST_94=$!' >> %t.sh
// RUN: echo "wait $TEST_78" >> %t.sh
-#if defined(TEST_94)
-#include <stdbool.h>
+#if defined(TEST_94) && __cplusplus > 202002L && !defined(_LIBCPP_HAS_NO_THREADS)
+#include <stdatomic.h>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_95 &' >> %t.sh
// RUN: echo 'TEST_95=$!' >> %t.sh
// RUN: echo "wait $TEST_79" >> %t.sh
#if defined(TEST_95)
-#include <stddef.h>
+#include <stdbool.h>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_96 &' >> %t.sh
// RUN: echo 'TEST_96=$!' >> %t.sh
// RUN: echo "wait $TEST_80" >> %t.sh
#if defined(TEST_96)
-#include <stdexcept>
+#include <stddef.h>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_97 &' >> %t.sh
// RUN: echo 'TEST_97=$!' >> %t.sh
// RUN: echo "wait $TEST_81" >> %t.sh
#if defined(TEST_97)
-#include <stdint.h>
+#include <stdexcept>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_98 &' >> %t.sh
// RUN: echo 'TEST_98=$!' >> %t.sh
// RUN: echo "wait $TEST_82" >> %t.sh
#if defined(TEST_98)
-#include <stdio.h>
+#include <stdint.h>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_99 &' >> %t.sh
// RUN: echo 'TEST_99=$!' >> %t.sh
// RUN: echo "wait $TEST_83" >> %t.sh
#if defined(TEST_99)
-#include <stdlib.h>
+#include <stdio.h>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_100 &' >> %t.sh
// RUN: echo 'TEST_100=$!' >> %t.sh
// RUN: echo "wait $TEST_84" >> %t.sh
-#if defined(TEST_100) && !defined(_LIBCPP_HAS_NO_LOCALIZATION)
-#include <streambuf>
+#if defined(TEST_100)
+#include <stdlib.h>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_101 &' >> %t.sh
// RUN: echo 'TEST_101=$!' >> %t.sh
// RUN: echo "wait $TEST_85" >> %t.sh
-#if defined(TEST_101)
-#include <string>
+#if defined(TEST_101) && !defined(_LIBCPP_HAS_NO_LOCALIZATION)
+#include <streambuf>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_102 &' >> %t.sh
// RUN: echo 'TEST_102=$!' >> %t.sh
// RUN: echo "wait $TEST_86" >> %t.sh
#if defined(TEST_102)
-#include <string.h>
+#include <string>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_103 &' >> %t.sh
// RUN: echo 'TEST_103=$!' >> %t.sh
// RUN: echo "wait $TEST_87" >> %t.sh
#if defined(TEST_103)
-#include <string_view>
+#include <string.h>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_104 &' >> %t.sh
// RUN: echo 'TEST_104=$!' >> %t.sh
// RUN: echo "wait $TEST_88" >> %t.sh
-#if defined(TEST_104) && !defined(_LIBCPP_HAS_NO_LOCALIZATION)
-#include <strstream>
+#if defined(TEST_104)
+#include <string_view>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_105 &' >> %t.sh
// RUN: echo 'TEST_105=$!' >> %t.sh
// RUN: echo "wait $TEST_89" >> %t.sh
-#if defined(TEST_105)
-#include <system_error>
+#if defined(TEST_105) && !defined(_LIBCPP_HAS_NO_LOCALIZATION)
+#include <strstream>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_106 &' >> %t.sh
// RUN: echo 'TEST_106=$!' >> %t.sh
// RUN: echo "wait $TEST_90" >> %t.sh
#if defined(TEST_106)
-#include <tgmath.h>
+#include <system_error>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_107 &' >> %t.sh
// RUN: echo 'TEST_107=$!' >> %t.sh
// RUN: echo "wait $TEST_91" >> %t.sh
-#if defined(TEST_107) && !defined(_LIBCPP_HAS_NO_THREADS)
-#include <thread>
+#if defined(TEST_107)
+#include <tgmath.h>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_108 &' >> %t.sh
// RUN: echo 'TEST_108=$!' >> %t.sh
// RUN: echo "wait $TEST_92" >> %t.sh
-#if defined(TEST_108)
-#include <tuple>
+#if defined(TEST_108) && !defined(_LIBCPP_HAS_NO_THREADS)
+#include <thread>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_109 &' >> %t.sh
// RUN: echo 'TEST_109=$!' >> %t.sh
// RUN: echo "wait $TEST_93" >> %t.sh
#if defined(TEST_109)
-#include <type_traits>
+#include <tuple>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_110 &' >> %t.sh
// RUN: echo 'TEST_110=$!' >> %t.sh
// RUN: echo "wait $TEST_94" >> %t.sh
#if defined(TEST_110)
-#include <typeindex>
+#include <type_traits>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_111 &' >> %t.sh
// RUN: echo 'TEST_111=$!' >> %t.sh
// RUN: echo "wait $TEST_95" >> %t.sh
#if defined(TEST_111)
-#include <typeinfo>
+#include <typeindex>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_112 &' >> %t.sh
// RUN: echo 'TEST_112=$!' >> %t.sh
// RUN: echo "wait $TEST_96" >> %t.sh
#if defined(TEST_112)
-#include <uchar.h>
+#include <typeinfo>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_113 &' >> %t.sh
// RUN: echo 'TEST_113=$!' >> %t.sh
// RUN: echo "wait $TEST_97" >> %t.sh
#if defined(TEST_113)
-#include <unordered_map>
+#include <uchar.h>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_114 &' >> %t.sh
// RUN: echo 'TEST_114=$!' >> %t.sh
// RUN: echo "wait $TEST_98" >> %t.sh
#if defined(TEST_114)
-#include <unordered_set>
+#include <unordered_map>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_115 &' >> %t.sh
// RUN: echo 'TEST_115=$!' >> %t.sh
// RUN: echo "wait $TEST_99" >> %t.sh
#if defined(TEST_115)
-#include <utility>
+#include <unordered_set>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_116 &' >> %t.sh
// RUN: echo 'TEST_116=$!' >> %t.sh
// RUN: echo "wait $TEST_100" >> %t.sh
#if defined(TEST_116)
-#include <valarray>
+#include <utility>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_117 &' >> %t.sh
// RUN: echo 'TEST_117=$!' >> %t.sh
// RUN: echo "wait $TEST_101" >> %t.sh
#if defined(TEST_117)
-#include <variant>
+#include <valarray>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_118 &' >> %t.sh
// RUN: echo 'TEST_118=$!' >> %t.sh
// RUN: echo "wait $TEST_102" >> %t.sh
#if defined(TEST_118)
-#include <vector>
+#include <variant>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_119 &' >> %t.sh
// RUN: echo 'TEST_119=$!' >> %t.sh
// RUN: echo "wait $TEST_103" >> %t.sh
#if defined(TEST_119)
-#include <version>
+#include <vector>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_120 &' >> %t.sh
// RUN: echo 'TEST_120=$!' >> %t.sh
// RUN: echo "wait $TEST_104" >> %t.sh
-#if defined(TEST_120) && !defined(_LIBCPP_HAS_NO_WIDE_CHARACTERS)
-#include <wchar.h>
+#if defined(TEST_120)
+#include <version>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_121 &' >> %t.sh
// RUN: echo 'TEST_121=$!' >> %t.sh
// RUN: echo "wait $TEST_105" >> %t.sh
#if defined(TEST_121) && !defined(_LIBCPP_HAS_NO_WIDE_CHARACTERS)
-#include <wctype.h>
+#include <wchar.h>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_122 &' >> %t.sh
// RUN: echo 'TEST_122=$!' >> %t.sh
// RUN: echo "wait $TEST_106" >> %t.sh
-#if defined(TEST_122) && __cplusplus >= 201103L
-#include <experimental/deque>
+#if defined(TEST_122) && !defined(_LIBCPP_HAS_NO_WIDE_CHARACTERS)
+#include <wctype.h>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_123 &' >> %t.sh
// RUN: echo 'TEST_123=$!' >> %t.sh
// RUN: echo "wait $TEST_107" >> %t.sh
#if defined(TEST_123) && __cplusplus >= 201103L
-#include <experimental/forward_list>
+#include <experimental/deque>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_124 &' >> %t.sh
// RUN: echo 'TEST_124=$!' >> %t.sh
// RUN: echo "wait $TEST_108" >> %t.sh
#if defined(TEST_124) && __cplusplus >= 201103L
-#include <experimental/iterator>
+#include <experimental/forward_list>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_125 &' >> %t.sh
// RUN: echo 'TEST_125=$!' >> %t.sh
// RUN: echo "wait $TEST_109" >> %t.sh
#if defined(TEST_125) && __cplusplus >= 201103L
-#include <experimental/list>
+#include <experimental/iterator>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_126 &' >> %t.sh
// RUN: echo 'TEST_126=$!' >> %t.sh
// RUN: echo "wait $TEST_110" >> %t.sh
#if defined(TEST_126) && __cplusplus >= 201103L
-#include <experimental/map>
+#include <experimental/list>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_127 &' >> %t.sh
// RUN: echo 'TEST_127=$!' >> %t.sh
// RUN: echo "wait $TEST_111" >> %t.sh
#if defined(TEST_127) && __cplusplus >= 201103L
-#include <experimental/memory_resource>
+#include <experimental/map>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_128 &' >> %t.sh
// RUN: echo 'TEST_128=$!' >> %t.sh
// RUN: echo "wait $TEST_112" >> %t.sh
#if defined(TEST_128) && __cplusplus >= 201103L
-#include <experimental/propagate_const>
+#include <experimental/memory_resource>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_129 &' >> %t.sh
// RUN: echo 'TEST_129=$!' >> %t.sh
// RUN: echo "wait $TEST_113" >> %t.sh
-#if defined(TEST_129) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) && __cplusplus >= 201103L
-#include <experimental/regex>
+#if defined(TEST_129) && __cplusplus >= 201103L
+#include <experimental/propagate_const>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_130 &' >> %t.sh
// RUN: echo 'TEST_130=$!' >> %t.sh
// RUN: echo "wait $TEST_114" >> %t.sh
-#if defined(TEST_130) && __cplusplus >= 201103L
-#include <experimental/set>
+#if defined(TEST_130) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) && __cplusplus >= 201103L
+#include <experimental/regex>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_131 &' >> %t.sh
// RUN: echo 'TEST_131=$!' >> %t.sh
// RUN: echo "wait $TEST_115" >> %t.sh
#if defined(TEST_131) && __cplusplus >= 201103L
-#include <experimental/simd>
+#include <experimental/set>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_132 &' >> %t.sh
// RUN: echo 'TEST_132=$!' >> %t.sh
// RUN: echo "wait $TEST_116" >> %t.sh
#if defined(TEST_132) && __cplusplus >= 201103L
-#include <experimental/string>
+#include <experimental/simd>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_133 &' >> %t.sh
// RUN: echo 'TEST_133=$!' >> %t.sh
// RUN: echo "wait $TEST_117" >> %t.sh
#if defined(TEST_133) && __cplusplus >= 201103L
-#include <experimental/type_traits>
+#include <experimental/string>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_134 &' >> %t.sh
// RUN: echo 'TEST_134=$!' >> %t.sh
// RUN: echo "wait $TEST_118" >> %t.sh
#if defined(TEST_134) && __cplusplus >= 201103L
-#include <experimental/unordered_map>
+#include <experimental/type_traits>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_135 &' >> %t.sh
// RUN: echo 'TEST_135=$!' >> %t.sh
// RUN: echo "wait $TEST_119" >> %t.sh
#if defined(TEST_135) && __cplusplus >= 201103L
-#include <experimental/unordered_set>
+#include <experimental/unordered_map>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_136 &' >> %t.sh
// RUN: echo 'TEST_136=$!' >> %t.sh
// RUN: echo "wait $TEST_120" >> %t.sh
#if defined(TEST_136) && __cplusplus >= 201103L
-#include <experimental/utility>
+#include <experimental/unordered_set>
#endif
// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_137 &' >> %t.sh
// RUN: echo 'TEST_137=$!' >> %t.sh
// RUN: echo "wait $TEST_121" >> %t.sh
#if defined(TEST_137) && __cplusplus >= 201103L
-#include <experimental/vector>
+#include <experimental/utility>
#endif
+// RUN: echo '%{cxx} %s %{flags} %{compile_flags} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only -DTEST_138 &' >> %t.sh
+// RUN: echo 'TEST_138=$!' >> %t.sh
// RUN: echo "wait $TEST_122" >> %t.sh
+#if defined(TEST_138) && __cplusplus >= 201103L
+#include <experimental/vector>
+#endif
// RUN: echo "wait $TEST_123" >> %t.sh
// RUN: echo "wait $TEST_124" >> %t.sh
// RUN: echo "wait $TEST_125" >> %t.sh
@@ -879,5 +884,6 @@ END-SCRIPT
// RUN: echo "wait $TEST_135" >> %t.sh
// RUN: echo "wait $TEST_136" >> %t.sh
// RUN: echo "wait $TEST_137" >> %t.sh
+// RUN: echo "wait $TEST_138" >> %t.sh
// RUN: bash %t.sh
// GENERATED-MARKER
diff --git a/libcxx/test/libcxx/nasty_macros.compile.pass.cpp b/libcxx/test/libcxx/nasty_macros.compile.pass.cpp
index 5254e0d78e88..49ab781e8771 100644
--- a/libcxx/test/libcxx/nasty_macros.compile.pass.cpp
+++ b/libcxx/test/libcxx/nasty_macros.compile.pass.cpp
@@ -257,6 +257,7 @@ END-SCRIPT
#endif
#include <map>
#include <math.h>
+#include <mdspan>
#include <memory>
#include <memory_resource>
#if !defined(_LIBCPP_HAS_NO_THREADS)
diff --git a/libcxx/test/libcxx/no_assert_include.compile.pass.cpp b/libcxx/test/libcxx/no_assert_include.compile.pass.cpp
index 779a21a02dd5..b5ac8519320c 100644
--- a/libcxx/test/libcxx/no_assert_include.compile.pass.cpp
+++ b/libcxx/test/libcxx/no_assert_include.compile.pass.cpp
@@ -129,6 +129,7 @@ END-SCRIPT
#endif
#include <map>
#include <math.h>
+#include <mdspan>
#include <memory>
#include <memory_resource>
#if !defined(_LIBCPP_HAS_NO_THREADS)
diff --git a/libcxx/test/libcxx/private_headers.verify.cpp b/libcxx/test/libcxx/private_headers.verify.cpp
index 6762913512c7..3ff91e1de143 100644
--- a/libcxx/test/libcxx/private_headers.verify.cpp
+++ b/libcxx/test/libcxx/private_headers.verify.cpp
@@ -493,6 +493,7 @@ END-SCRIPT
#include <__iterator/wrap_iter.h> // expected-error@*:* {{use of private header from outside its module: '__iterator/wrap_iter.h'}}
#include <__locale> // expected-error@*:* {{use of private header from outside its module: '__locale'}}
#include <__mbstate_t.h> // expected-error@*:* {{use of private header from outside its module: '__mbstate_t.h'}}
+#include <__mdspan/extents.h> // expected-error@*:* {{use of private header from outside its module: '__mdspan/extents.h'}}
#include <__memory/addressof.h> // expected-error@*:* {{use of private header from outside its module: '__memory/addressof.h'}}
#include <__memory/align.h> // expected-error@*:* {{use of private header from outside its module: '__memory/align.h'}}
#include <__memory/aligned_alloc.h> // expected-error@*:* {{use of private header from outside its module: '__memory/aligned_alloc.h'}}
diff --git a/libcxx/test/libcxx/transitive_includes.sh.cpp b/libcxx/test/libcxx/transitive_includes.sh.cpp
index 1bbc906bb507..db462025bb1c 100644
--- a/libcxx/test/libcxx/transitive_includes.sh.cpp
+++ b/libcxx/test/libcxx/transitive_includes.sh.cpp
@@ -317,224 +317,228 @@ END-SCRIPT
#if defined(TEST_69)
#include <map>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_71 > /dev/null 2> %t/header.memory
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_71 > /dev/null 2> %t/header.mdspan
#if defined(TEST_71)
-#include <memory>
+#include <mdspan>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_72 > /dev/null 2> %t/header.memory_resource
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_72 > /dev/null 2> %t/header.memory
#if defined(TEST_72)
-#include <memory_resource>
+#include <memory>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_73 > /dev/null 2> %t/header.mutex
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_73 > /dev/null 2> %t/header.memory_resource
#if defined(TEST_73)
-#include <mutex>
+#include <memory_resource>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_74 > /dev/null 2> %t/header.new
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_74 > /dev/null 2> %t/header.mutex
#if defined(TEST_74)
-#include <new>
+#include <mutex>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_75 > /dev/null 2> %t/header.numbers
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_75 > /dev/null 2> %t/header.new
#if defined(TEST_75)
-#include <numbers>
+#include <new>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_76 > /dev/null 2> %t/header.numeric
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_76 > /dev/null 2> %t/header.numbers
#if defined(TEST_76)
-#include <numeric>
+#include <numbers>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_77 > /dev/null 2> %t/header.optional
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_77 > /dev/null 2> %t/header.numeric
#if defined(TEST_77)
-#include <optional>
+#include <numeric>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_78 > /dev/null 2> %t/header.ostream
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_78 > /dev/null 2> %t/header.optional
#if defined(TEST_78)
-#include <ostream>
+#include <optional>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_79 > /dev/null 2> %t/header.queue
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_79 > /dev/null 2> %t/header.ostream
#if defined(TEST_79)
-#include <queue>
+#include <ostream>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_80 > /dev/null 2> %t/header.random
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_80 > /dev/null 2> %t/header.queue
#if defined(TEST_80)
-#include <random>
+#include <queue>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_81 > /dev/null 2> %t/header.ranges
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_81 > /dev/null 2> %t/header.random
#if defined(TEST_81)
-#include <ranges>
+#include <random>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_82 > /dev/null 2> %t/header.ratio
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_82 > /dev/null 2> %t/header.ranges
#if defined(TEST_82)
-#include <ratio>
+#include <ranges>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_83 > /dev/null 2> %t/header.regex
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_83 > /dev/null 2> %t/header.ratio
#if defined(TEST_83)
-#include <regex>
+#include <ratio>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_84 > /dev/null 2> %t/header.scoped_allocator
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_84 > /dev/null 2> %t/header.regex
#if defined(TEST_84)
-#include <scoped_allocator>
+#include <regex>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_85 > /dev/null 2> %t/header.semaphore
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_85 > /dev/null 2> %t/header.scoped_allocator
#if defined(TEST_85)
-#include <semaphore>
+#include <scoped_allocator>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_86 > /dev/null 2> %t/header.set
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_86 > /dev/null 2> %t/header.semaphore
#if defined(TEST_86)
+#include <semaphore>
+#endif
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_87 > /dev/null 2> %t/header.set
+#if defined(TEST_87)
#include <set>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_88 > /dev/null 2> %t/header.shared_mutex
-#if defined(TEST_88)
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_89 > /dev/null 2> %t/header.shared_mutex
+#if defined(TEST_89)
#include <shared_mutex>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_89 > /dev/null 2> %t/header.source_location
-#if defined(TEST_89)
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_90 > /dev/null 2> %t/header.source_location
+#if defined(TEST_90)
#include <source_location>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_90 > /dev/null 2> %t/header.span
-#if defined(TEST_90)
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_91 > /dev/null 2> %t/header.span
+#if defined(TEST_91)
#include <span>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_91 > /dev/null 2> %t/header.sstream
-#if defined(TEST_91)
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_92 > /dev/null 2> %t/header.sstream
+#if defined(TEST_92)
#include <sstream>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_92 > /dev/null 2> %t/header.stack
-#if defined(TEST_92)
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_93 > /dev/null 2> %t/header.stack
+#if defined(TEST_93)
#include <stack>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_96 > /dev/null 2> %t/header.stdexcept
-#if defined(TEST_96)
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_97 > /dev/null 2> %t/header.stdexcept
+#if defined(TEST_97)
#include <stdexcept>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_100 > /dev/null 2> %t/header.streambuf
-#if defined(TEST_100)
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_101 > /dev/null 2> %t/header.streambuf
+#if defined(TEST_101)
#include <streambuf>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_101 > /dev/null 2> %t/header.string
-#if defined(TEST_101)
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_102 > /dev/null 2> %t/header.string
+#if defined(TEST_102)
#include <string>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_103 > /dev/null 2> %t/header.string_view
-#if defined(TEST_103)
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_104 > /dev/null 2> %t/header.string_view
+#if defined(TEST_104)
#include <string_view>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_104 > /dev/null 2> %t/header.strstream
-#if defined(TEST_104)
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_105 > /dev/null 2> %t/header.strstream
+#if defined(TEST_105)
#include <strstream>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_105 > /dev/null 2> %t/header.system_error
-#if defined(TEST_105)
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_106 > /dev/null 2> %t/header.system_error
+#if defined(TEST_106)
#include <system_error>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_107 > /dev/null 2> %t/header.thread
-#if defined(TEST_107)
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_108 > /dev/null 2> %t/header.thread
+#if defined(TEST_108)
#include <thread>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_108 > /dev/null 2> %t/header.tuple
-#if defined(TEST_108)
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_109 > /dev/null 2> %t/header.tuple
+#if defined(TEST_109)
#include <tuple>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_109 > /dev/null 2> %t/header.type_traits
-#if defined(TEST_109)
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_110 > /dev/null 2> %t/header.type_traits
+#if defined(TEST_110)
#include <type_traits>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_110 > /dev/null 2> %t/header.typeindex
-#if defined(TEST_110)
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_111 > /dev/null 2> %t/header.typeindex
+#if defined(TEST_111)
#include <typeindex>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_111 > /dev/null 2> %t/header.typeinfo
-#if defined(TEST_111)
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_112 > /dev/null 2> %t/header.typeinfo
+#if defined(TEST_112)
#include <typeinfo>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_113 > /dev/null 2> %t/header.unordered_map
-#if defined(TEST_113)
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_114 > /dev/null 2> %t/header.unordered_map
+#if defined(TEST_114)
#include <unordered_map>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_114 > /dev/null 2> %t/header.unordered_set
-#if defined(TEST_114)
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_115 > /dev/null 2> %t/header.unordered_set
+#if defined(TEST_115)
#include <unordered_set>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_115 > /dev/null 2> %t/header.utility
-#if defined(TEST_115)
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_116 > /dev/null 2> %t/header.utility
+#if defined(TEST_116)
#include <utility>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_116 > /dev/null 2> %t/header.valarray
-#if defined(TEST_116)
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_117 > /dev/null 2> %t/header.valarray
+#if defined(TEST_117)
#include <valarray>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_117 > /dev/null 2> %t/header.variant
-#if defined(TEST_117)
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_118 > /dev/null 2> %t/header.variant
+#if defined(TEST_118)
#include <variant>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_118 > /dev/null 2> %t/header.vector
-#if defined(TEST_118)
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_119 > /dev/null 2> %t/header.vector
+#if defined(TEST_119)
#include <vector>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_119 > /dev/null 2> %t/header.version
-#if defined(TEST_119)
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_120 > /dev/null 2> %t/header.version
+#if defined(TEST_120)
#include <version>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_122 > /dev/null 2> %t/header.experimental_deque
-#if defined(TEST_122)
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_123 > /dev/null 2> %t/header.experimental_deque
+#if defined(TEST_123)
#include <experimental/deque>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_123 > /dev/null 2> %t/header.experimental_forward_list
-#if defined(TEST_123)
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_124 > /dev/null 2> %t/header.experimental_forward_list
+#if defined(TEST_124)
#include <experimental/forward_list>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_124 > /dev/null 2> %t/header.experimental_iterator
-#if defined(TEST_124)
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_125 > /dev/null 2> %t/header.experimental_iterator
+#if defined(TEST_125)
#include <experimental/iterator>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_125 > /dev/null 2> %t/header.experimental_list
-#if defined(TEST_125)
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_126 > /dev/null 2> %t/header.experimental_list
+#if defined(TEST_126)
#include <experimental/list>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_126 > /dev/null 2> %t/header.experimental_map
-#if defined(TEST_126)
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_127 > /dev/null 2> %t/header.experimental_map
+#if defined(TEST_127)
#include <experimental/map>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_127 > /dev/null 2> %t/header.experimental_memory_resource
-#if defined(TEST_127)
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_128 > /dev/null 2> %t/header.experimental_memory_resource
+#if defined(TEST_128)
#include <experimental/memory_resource>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_128 > /dev/null 2> %t/header.experimental_propagate_const
-#if defined(TEST_128)
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_129 > /dev/null 2> %t/header.experimental_propagate_const
+#if defined(TEST_129)
#include <experimental/propagate_const>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_129 > /dev/null 2> %t/header.experimental_regex
-#if defined(TEST_129)
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_130 > /dev/null 2> %t/header.experimental_regex
+#if defined(TEST_130)
#include <experimental/regex>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_130 > /dev/null 2> %t/header.experimental_set
-#if defined(TEST_130)
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_131 > /dev/null 2> %t/header.experimental_set
+#if defined(TEST_131)
#include <experimental/set>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_131 > /dev/null 2> %t/header.experimental_simd
-#if defined(TEST_131)
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_132 > /dev/null 2> %t/header.experimental_simd
+#if defined(TEST_132)
#include <experimental/simd>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_132 > /dev/null 2> %t/header.experimental_string
-#if defined(TEST_132)
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_133 > /dev/null 2> %t/header.experimental_string
+#if defined(TEST_133)
#include <experimental/string>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_133 > /dev/null 2> %t/header.experimental_type_traits
-#if defined(TEST_133)
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_134 > /dev/null 2> %t/header.experimental_type_traits
+#if defined(TEST_134)
#include <experimental/type_traits>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_134 > /dev/null 2> %t/header.experimental_unordered_map
-#if defined(TEST_134)
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_135 > /dev/null 2> %t/header.experimental_unordered_map
+#if defined(TEST_135)
#include <experimental/unordered_map>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_135 > /dev/null 2> %t/header.experimental_unordered_set
-#if defined(TEST_135)
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_136 > /dev/null 2> %t/header.experimental_unordered_set
+#if defined(TEST_136)
#include <experimental/unordered_set>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_136 > /dev/null 2> %t/header.experimental_utility
-#if defined(TEST_136)
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_137 > /dev/null 2> %t/header.experimental_utility
+#if defined(TEST_137)
#include <experimental/utility>
#endif
-// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_137 > /dev/null 2> %t/header.experimental_vector
-#if defined(TEST_137)
+// RUN: %{cxx} %s %{flags} %{compile_flags} --trace-includes -fshow-skipped-includes --preprocess -DTEST_138 > /dev/null 2> %t/header.experimental_vector
+#if defined(TEST_138)
#include <experimental/vector>
#endif
// RUN: %{python} %S/transitive_includes_to_csv.py %t > %t/transitive_includes.csv
diff --git a/libcxx/test/libcxx/transitive_includes/cxx03.csv b/libcxx/test/libcxx/transitive_includes/cxx03.csv
index 172f222d18cb..0770eaaed821 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx03.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx03.csv
@@ -515,6 +515,12 @@ map tuple
map type_traits
map utility
map version
+mdspan array
+mdspan cinttypes
+mdspan concepts
+mdspan cstddef
+mdspan limits
+mdspan span
memory atomic
memory compare
memory concepts
diff --git a/libcxx/test/libcxx/transitive_includes/cxx11.csv b/libcxx/test/libcxx/transitive_includes/cxx11.csv
index f75a9987622e..f60756138b55 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx11.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx11.csv
@@ -515,6 +515,12 @@ map tuple
map type_traits
map utility
map version
+mdspan array
+mdspan cinttypes
+mdspan concepts
+mdspan cstddef
+mdspan limits
+mdspan span
memory atomic
memory compare
memory concepts
diff --git a/libcxx/test/libcxx/transitive_includes/cxx14.csv b/libcxx/test/libcxx/transitive_includes/cxx14.csv
index f402f3e2e66d..2fe6248ae667 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx14.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx14.csv
@@ -517,6 +517,12 @@ map tuple
map type_traits
map utility
map version
+mdspan array
+mdspan cinttypes
+mdspan concepts
+mdspan cstddef
+mdspan limits
+mdspan span
memory atomic
memory compare
memory concepts
diff --git a/libcxx/test/libcxx/transitive_includes/cxx17.csv b/libcxx/test/libcxx/transitive_includes/cxx17.csv
index f402f3e2e66d..2fe6248ae667 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx17.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx17.csv
@@ -517,6 +517,12 @@ map tuple
map type_traits
map utility
map version
+mdspan array
+mdspan cinttypes
+mdspan concepts
+mdspan cstddef
+mdspan limits
+mdspan span
memory atomic
memory compare
memory concepts
diff --git a/libcxx/test/libcxx/transitive_includes/cxx20.csv b/libcxx/test/libcxx/transitive_includes/cxx20.csv
index 79ad40506851..2c743b9672f2 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx20.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx20.csv
@@ -523,6 +523,12 @@ map tuple
map type_traits
map utility
map version
+mdspan array
+mdspan cinttypes
+mdspan concepts
+mdspan cstddef
+mdspan limits
+mdspan span
memory atomic
memory compare
memory concepts
diff --git a/libcxx/test/libcxx/transitive_includes/cxx2b.csv b/libcxx/test/libcxx/transitive_includes/cxx2b.csv
index 833df27c70f5..0a386315e72a 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx2b.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx2b.csv
@@ -351,6 +351,12 @@ map optional
map stdexcept
map tuple
map version
+mdspan array
+mdspan cinttypes
+mdspan concepts
+mdspan cstddef
+mdspan limits
+mdspan span
memory compare
memory cstddef
memory cstdint
diff --git a/libcxx/test/std/containers/views/mdspan/extents/ConvertibleToIntegral.h b/libcxx/test/std/containers/views/mdspan/extents/ConvertibleToIntegral.h
new file mode 100644
index 000000000000..1cdb198739ec
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/extents/ConvertibleToIntegral.h
@@ -0,0 +1,22 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef TEST_STD_CONTAINERS_CONVERTIBLE_TO_INTEGRAL_H
+#define TEST_STD_CONTAINERS_CONVERTIBLE_TO_INTEGRAL_H
+
+struct IntType {
+ int val;
+ constexpr IntType() = default;
+ constexpr IntType(int v) noexcept : val(v){};
+
+ constexpr bool operator==(const IntType& rhs) const { return val == rhs.val; }
+ constexpr operator int() const noexcept { return val; }
+ constexpr operator unsigned char() const noexcept { return val; }
+};
+
+#endif // TEST_STD_CONTAINERS_CONVERTIBLE_TO_INTEGRAL_H
diff --git a/libcxx/test/std/containers/views/mdspan/extents/CtorTestCombinations.h b/libcxx/test/std/containers/views/mdspan/extents/CtorTestCombinations.h
new file mode 100644
index 000000000000..4914b5c1d874
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/extents/CtorTestCombinations.h
@@ -0,0 +1,99 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <mdspan>
+
+#include <mdspan>
+#include <cassert>
+#include <array>
+#include <span>
+
+#include "ConvertibleToIntegral.h"
+#include "test_macros.h"
+
+// Helper file to implement combinatorical testing of extents constructor
+//
+// std::extents can be constructed from just indices, a std::array, or a std::span
+// In each of those cases one can either provide all extents, or just the dynamic ones
+// If constructed from std::span, the span needs to have a static extent
+// Furthermore, the indices/array/span can have integer types other than index_type
+
+template <class E, class AllExtents>
+constexpr void test_runtime_observers(E ext, AllExtents expected) {
+ for (typename E::rank_type r = 0; r < ext.rank(); r++) {
+ ASSERT_SAME_TYPE(decltype(ext.extent(0)), typename E::index_type);
+ ASSERT_NOEXCEPT(ext.extent(0));
+ assert(ext.extent(r) == static_cast<typename E::index_type>(expected[r]));
+ }
+}
+
+template <class E, class AllExtents>
+constexpr void test_implicit_construction_call(E e, AllExtents all_ext) {
+ test_runtime_observers(e, all_ext);
+}
+
+template <class E, class Test, class AllExtents>
+constexpr void test_construction(AllExtents all_ext) {
+ // test construction from all extents
+ Test::template test_construction<E>(all_ext, all_ext, std::make_index_sequence<E::rank()>());
+
+ // test construction from just dynamic extents
+ // create an array of just the extents corresponding to dynamic values
+ std::array<typename AllExtents::value_type, E::rank_dynamic()> dyn_ext{0};
+ size_t dynamic_idx = 0;
+ for (size_t r = 0; r < E::rank(); r++) {
+ if (E::static_extent(r) == std::dynamic_extent) {
+ dyn_ext[dynamic_idx] = all_ext[r];
+ dynamic_idx++;
+ }
+ }
+ Test::template test_construction<E>(all_ext, dyn_ext, std::make_index_sequence<E::rank_dynamic()>());
+}
+
+template <class T, class TArg, class Test>
+constexpr void test() {
+ constexpr size_t D = std::dynamic_extent;
+
+ test_construction<std::extents<T>, Test>(std::array<TArg, 0>{});
+
+ test_construction<std::extents<T, 3>, Test>(std::array<TArg, 1>{3});
+ test_construction<std::extents<T, D>, Test>(std::array<TArg, 1>{3});
+
+ test_construction<std::extents<T, 3, 7>, Test>(std::array<TArg, 2>{3, 7});
+ test_construction<std::extents<T, 3, D>, Test>(std::array<TArg, 2>{3, 7});
+ test_construction<std::extents<T, D, 7>, Test>(std::array<TArg, 2>{3, 7});
+ test_construction<std::extents<T, D, D>, Test>(std::array<TArg, 2>{3, 7});
+
+ test_construction<std::extents<T, 3, 7, 9>, Test>(std::array<TArg, 3>{3, 7, 9});
+ test_construction<std::extents<T, 3, 7, D>, Test>(std::array<TArg, 3>{3, 7, 9});
+ test_construction<std::extents<T, 3, D, D>, Test>(std::array<TArg, 3>{3, 7, 9});
+ test_construction<std::extents<T, D, 7, D>, Test>(std::array<TArg, 3>{3, 7, 9});
+ test_construction<std::extents<T, D, D, D>, Test>(std::array<TArg, 3>{3, 7, 9});
+ test_construction<std::extents<T, 3, D, 9>, Test>(std::array<TArg, 3>{3, 7, 9});
+ test_construction<std::extents<T, D, D, 9>, Test>(std::array<TArg, 3>{3, 7, 9});
+ test_construction<std::extents<T, D, 7, 9>, Test>(std::array<TArg, 3>{3, 7, 9});
+
+ test_construction<std::extents<T, 1, 2, 3, 4, 5, 6, 7, 8, 9>, Test>(std::array<TArg, 9>{1, 2, 3, 4, 5, 6, 7, 8, 9});
+ test_construction<std::extents<T, D, 2, 3, D, 5, D, 7, D, 9>, Test>(std::array<TArg, 9>{1, 2, 3, 4, 5, 6, 7, 8, 9});
+ test_construction<std::extents<T, D, D, D, D, D, D, D, D, D>, Test>(std::array<TArg, 9>{1, 2, 3, 4, 5, 6, 7, 8, 9});
+}
+
+template <class Test>
+constexpr bool test_index_type_combo() {
+ test<int, int, Test>();
+ test<int, size_t, Test>();
+ test<unsigned, int, Test>();
+ test<char, size_t, Test>();
+ test<long long, unsigned, Test>();
+ test<size_t, int, Test>();
+ test<size_t, size_t, Test>();
+ test<int, IntType, Test>();
+ test<unsigned char, IntType, Test>();
+ return true;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/extents/assert.conversion.pass.cpp b/libcxx/test/std/containers/views/mdspan/extents/assert.conversion.pass.cpp
new file mode 100644
index 000000000000..1ca4e2ec178a
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/extents/assert.conversion.pass.cpp
@@ -0,0 +1,57 @@
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// REQUIRES: has-unix-headers
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+// XFAIL: availability-verbose_abort-missing
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
+
+// <mdspan>
+
+// template<class OtherIndexType, size_t... OtherExtents>
+// constexpr explicit(see below) extents(const extents<OtherIndexType, OtherExtents...>&) noexcept;
+//
+// Constraints:
+// * sizeof...(OtherExtents) == rank() is true.
+// * ((OtherExtents == dynamic_extent || Extents == dynamic_extent ||
+// OtherExtents == Extents) && ...) is true.
+//
+// Preconditions:
+// * other.extent(r) equals Er for each r for which Er is a static extent, and
+// * either
+// - sizeof...(OtherExtents) is zero, or
+// - other.extent(r) is representable as a value of type index_type for
+// every rank index r of other.
+//
+// Remarks: The expression inside explicit is equivalent to:
+// (((Extents != dynamic_extent) && (OtherExtents == dynamic_extent)) || ... ) ||
+// (numeric_limits<index_type>::max() < numeric_limits<OtherIndexType>::max())
+
+#include <mdspan>
+#include <cassert>
+
+#include "check_assertion.h"
+
+int main(int, char**) {
+ constexpr size_t D = std::dynamic_extent;
+ std::extents<int, D, D> arg{1000, 5};
+
+ // working case
+ {
+ [[maybe_unused]] std::extents<size_t, D, 5> e(arg); // should work
+ }
+ // mismatch of static extent
+ {
+ TEST_LIBCPP_ASSERT_FAILURE(([=] { std::extents<int, D, 3> e(arg); }()),
+ "extents construction: mismatch of provided arguments with static extents.");
+ }
+ // value out of range
+ {
+ TEST_LIBCPP_ASSERT_FAILURE(([=] { std::extents<char, D, 5> e(arg); }()),
+ "extents ctor: arguments must be representable as index_type and nonnegative");
+ }
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/extents/assert.ctor_from_array.pass.cpp b/libcxx/test/std/containers/views/mdspan/extents/assert.ctor_from_array.pass.cpp
new file mode 100644
index 000000000000..b5e74df97ca2
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/extents/assert.ctor_from_array.pass.cpp
@@ -0,0 +1,69 @@
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// REQUIRES: has-unix-headers
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+// XFAIL: availability-verbose_abort-missing
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
+
+// <mdspan>
+
+// Test construction from array:
+//
+// template<class OtherIndexType, size_t N>
+// constexpr explicit(N != rank_dynamic()) extents(const array<OtherIndexType, N>& exts) noexcept;
+//
+// Constraints:
+// * is_convertible_v<const OtherIndexType&, index_type> is true,
+// * is_nothrow_constructible_v<index_type, const OtherIndexType&> is true, and
+// * N == rank_dynamic() || N == rank() is true.
+//
+// Preconditions:
+// * If N != rank_dynamic() is true, exts[r] equals Er for each r for which
+// Er is a static extent, and
+// * either
+// - N is zero, or
+// - exts[r] is nonnegative and is representable as a value of type index_type
+// for every rank index r.
+//
+
+#include <mdspan>
+#include <cassert>
+
+#include "check_assertion.h"
+
+int main(int, char**) {
+ constexpr size_t D = std::dynamic_extent;
+ // working case
+ {
+ [[maybe_unused]] std::extents<int, D, 5> e1(std::array{1000, 5}); // should work
+ }
+ // mismatch of static extent
+ {
+ TEST_LIBCPP_ASSERT_FAILURE(
+ ([] {
+ std::extents<int, D, 5> e1(std::array{1000, 3});
+ }()),
+ "extents construction: mismatch of provided arguments with static extents.");
+ }
+ // value out of range
+ {
+ TEST_LIBCPP_ASSERT_FAILURE(
+ ([] {
+ std::extents<char, D, 5> e1(std::array{1000, 5});
+ }()),
+ "extents ctor: arguments must be representable as index_type and nonnegative");
+ }
+ // negative value
+ {
+ TEST_LIBCPP_ASSERT_FAILURE(
+ ([] {
+ std::extents<char, D, 5> e1(std::array{-1, 5});
+ }()),
+ "extents ctor: arguments must be representable as index_type and nonnegative");
+ }
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/extents/assert.ctor_from_integral.pass.cpp b/libcxx/test/std/containers/views/mdspan/extents/assert.ctor_from_integral.pass.cpp
new file mode 100644
index 000000000000..69f8436f5653
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/extents/assert.ctor_from_integral.pass.cpp
@@ -0,0 +1,62 @@
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// REQUIRES: has-unix-headers
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+// XFAIL: availability-verbose_abort-missing
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
+
+// <mdspan>
+
+// Test construction from integral:
+//
+// template<class ... OtherIndexTypes>
+// constexpr explicit extents(OtherIndexTypes ... exts) noexcept;
+//
+// Let N be sizeof...(OtherIndexTypes), and let
+// exts_arr be array<index_type, N>{static_cast<index_type>(std::move(exts))...}.
+//
+// Constraints:
+// * (is_convertible_v<OtherIndexTypes, index_type> && ...) is true,
+// * (is_nothrow_constructible_v<index_type, OtherIndexType> && ...) is true, and
+// * N == rank_dynamic() || N == rank() is true.
+//
+// Preconditions:
+// * If N != rank_dynamic() is true, exts_arr[r] equals Er for each r for which
+// Er is a static extent, and
+// * either
+// - sizeof...(exts) == 0 is true, or
+// - each element of exts is nonnegative and is representable as a value of type index_type.
+//
+
+#include <mdspan>
+#include <cassert>
+
+#include "check_assertion.h"
+
+int main(int, char**) {
+ constexpr size_t D = std::dynamic_extent;
+ // working case
+ {
+ [[maybe_unused]] std::extents<int, D, 5> e1(1000, 5); // should work
+ }
+ // mismatch of static extent
+ {
+ TEST_LIBCPP_ASSERT_FAILURE(([] { std::extents<int, D, 5> e1(1000, 3); }()),
+ "extents construction: mismatch of provided arguments with static extents.");
+ }
+ // value out of range
+ {
+ TEST_LIBCPP_ASSERT_FAILURE(([] { std::extents<char, D, 5> e1(1000, 5); }()),
+ "extents ctor: arguments must be representable as index_type and nonnegative");
+ }
+ // negative value
+ {
+ TEST_LIBCPP_ASSERT_FAILURE(([] { std::extents<char, D, 5> e1(-1, 5); }()),
+ "extents ctor: arguments must be representable as index_type and nonnegative");
+ }
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/extents/assert.ctor_from_span.pass.cpp b/libcxx/test/std/containers/views/mdspan/extents/assert.ctor_from_span.pass.cpp
new file mode 100644
index 000000000000..0375ca43054a
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/extents/assert.ctor_from_span.pass.cpp
@@ -0,0 +1,62 @@
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// REQUIRES: has-unix-headers
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+// XFAIL: availability-verbose_abort-missing
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
+
+// Test construction from span:
+//
+// template<class OtherIndexType, size_t N>
+// constexpr explicit(N != rank_dynamic()) extents(span<OtherIndexType, N> exts) noexcept;
+//
+// Constraints:
+// * is_convertible_v<const OtherIndexType&, index_type> is true,
+// * is_nothrow_constructible_v<index_type, const OtherIndexType&> is true, and
+// * N == rank_dynamic() || N == rank() is true.
+//
+// Preconditions:
+// * If N != rank_dynamic() is true, exts[r] equals Er for each r for which
+// Er is a static extent, and
+// * either
+// - N is zero, or
+// - exts[r] is nonnegative and is representable as a value of type index_type
+// for every rank index r.
+//
+
+#include <mdspan>
+#include <cassert>
+
+#include "check_assertion.h"
+
+int main(int, char**) {
+ constexpr size_t D = std::dynamic_extent;
+ // working case sanity check
+ {
+ std::array args{1000, 5};
+ [[maybe_unused]] std::extents<int, D, 5> e1(std::span{args});
+ }
+ // mismatch of static extent
+ {
+ std::array args{1000, 3};
+ TEST_LIBCPP_ASSERT_FAILURE(([=] { std::extents<int, D, 5> e1(std::span{args}); }()),
+ "extents construction: mismatch of provided arguments with static extents.");
+ }
+ // value out of range
+ {
+ std::array args{1000, 5};
+ TEST_LIBCPP_ASSERT_FAILURE(([=] { std::extents<char, D, 5> e1(std::span{args}); }()),
+ "extents ctor: arguments must be representable as index_type and nonnegative");
+ }
+ // negative value
+ {
+ std::array args{-1, 5};
+ TEST_LIBCPP_ASSERT_FAILURE(([=] { std::extents<char, D, 5> e1(std::span{args}); }()),
+ "extents ctor: arguments must be representable as index_type and nonnegative");
+ }
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/extents/assert.obs.pass.cpp b/libcxx/test/std/containers/views/mdspan/extents/assert.obs.pass.cpp
new file mode 100644
index 000000000000..acf09bdc0c5a
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/extents/assert.obs.pass.cpp
@@ -0,0 +1,65 @@
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// REQUIRES: has-unix-headers
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+// XFAIL: availability-verbose_abort-missing
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
+
+// <mdspan>
+
+// static constexpr size_t static_extent(rank_type i) noexcept;
+//
+// Preconditions: i < rank() is true.
+//
+// Returns: Ei.
+//
+//
+// constexpr index_type extent(rank_type i) const noexcept;
+//
+// Preconditions: i < rank() is true.
+//
+// Returns: Di.
+
+#include <mdspan>
+#include <cassert>
+
+#include "check_assertion.h"
+
+int main(int, char**) {
+ constexpr size_t D = std::dynamic_extent;
+
+ // mismatch of static extent
+ {
+ std::extents<int> e;
+ TEST_LIBCPP_ASSERT_FAILURE(([=] { e.extent(0); }()), "extents access: index must be less than rank");
+ TEST_LIBCPP_ASSERT_FAILURE(([=] { e.static_extent(0); }()), "extents access: index must be less than rank");
+ }
+ {
+ std::extents<int, D> e;
+ TEST_LIBCPP_ASSERT_FAILURE(([=] { e.extent(2); }()), "extents access: index must be less than rank");
+ TEST_LIBCPP_ASSERT_FAILURE(([=] { e.static_extent(2); }()), "extents access: index must be less than rank");
+ }
+ {
+ std::extents<int, 5> e;
+ TEST_LIBCPP_ASSERT_FAILURE(([=] { e.extent(2); }()), "extents access: index must be less than rank");
+ TEST_LIBCPP_ASSERT_FAILURE(([=] { e.static_extent(2); }()), "extents access: index must be less than rank");
+ }
+ {
+ std::extents<int, D, 5> e;
+ TEST_LIBCPP_ASSERT_FAILURE(([=] { e.extent(2); }()), "extents access: index must be less than rank");
+ TEST_LIBCPP_ASSERT_FAILURE(([=] { e.static_extent(2); }()), "extents access: index must be less than rank");
+ }
+ {
+ std::extents<int, 1, 2, 3, 4, 5, 6, 7, 8> e;
+ TEST_LIBCPP_ASSERT_FAILURE(([=] { e.extent(9); }()), "extents access: index must be less than rank");
+ TEST_LIBCPP_ASSERT_FAILURE(([=] { e.static_extent(9); }()), "extents access: index must be less than rank");
+ }
+
+ // check that static_extent works in constant expression with assertions enabled
+ static_assert(std::extents<int, D, 5>::static_extent(1) == 5);
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/extents/comparison.pass.cpp b/libcxx/test/std/containers/views/mdspan/extents/comparison.pass.cpp
new file mode 100644
index 000000000000..77fbd46fb7ca
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/extents/comparison.pass.cpp
@@ -0,0 +1,95 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <mdspan>
+//
+// template<class OtherIndexType, size_t... OtherExtents>
+// friend constexpr bool operator==(const extents& lhs,
+// const extents<OtherIndexType, OtherExtents...>& rhs) noexcept;
+//
+// Returns: true if lhs.rank() equals rhs.rank() and
+// if lhs.extent(r) equals rhs.extent(r) for every rank index r of rhs, otherwise false.
+//
+
+#include <mdspan>
+#include <type_traits>
+#include <concepts>
+#include <cassert>
+
+#include "test_macros.h"
+
+template <class To, class From>
+constexpr void test_comparison(bool equal, To dest, From src) {
+ ASSERT_NOEXCEPT(dest == src);
+ assert((dest == src) == equal);
+ assert((dest != src) == !equal);
+}
+
+template <class T1, class T2>
+constexpr void test_comparison_different_rank() {
+ constexpr size_t D = std::dynamic_extent;
+
+ test_comparison(false, std::extents<T1>(), std::extents<T2, D>(1));
+ test_comparison(false, std::extents<T1>(), std::extents<T2, 1>());
+
+ test_comparison(false, std::extents<T1, D>(1), std::extents<T2>());
+ test_comparison(false, std::extents<T1, 1>(), std::extents<T2>());
+
+ test_comparison(false, std::extents<T1, D>(5), std::extents<T2, D, D>(5, 5));
+ test_comparison(false, std::extents<T1, 5>(), std::extents<T2, 5, D>(5));
+ test_comparison(false, std::extents<T1, 5>(), std::extents<T2, 5, 1>());
+
+ test_comparison(false, std::extents<T1, D, D>(5, 5), std::extents<T2, D>(5));
+ test_comparison(false, std::extents<T1, 5, D>(5), std::extents<T2, D>(5));
+ test_comparison(false, std::extents<T1, 5, 5>(), std::extents<T2, 5>());
+}
+
+template <class T1, class T2>
+constexpr void test_comparison_same_rank() {
+ constexpr size_t D = std::dynamic_extent;
+
+ test_comparison(true, std::extents<T1>(), std::extents<T2>());
+
+ test_comparison(true, std::extents<T1, D>(5), std::extents<T2, D>(5));
+ test_comparison(true, std::extents<T1, 5>(), std::extents<T2, D>(5));
+ test_comparison(true, std::extents<T1, D>(5), std::extents<T2, 5>());
+ test_comparison(true, std::extents<T1, 5>(), std::extents< T2, 5>());
+ test_comparison(false, std::extents<T1, D>(5), std::extents<T2, D>(7));
+ test_comparison(false, std::extents<T1, 5>(), std::extents<T2, D>(7));
+ test_comparison(false, std::extents<T1, D>(5), std::extents<T2, 7>());
+ test_comparison(false, std::extents<T1, 5>(), std::extents<T2, 7>());
+
+ test_comparison(true, std::extents<T1, D, D, D, D, D>(5, 6, 7, 8, 9), std::extents<T2, D, D, D, D, D>(5, 6, 7, 8, 9));
+ test_comparison(true, std::extents<T1, D, 6, D, 8, D>(5, 7, 9), std::extents<T2, 5, D, D, 8, 9>(6, 7));
+ test_comparison(true, std::extents<T1, 5, 6, 7, 8, 9>(5, 6, 7, 8, 9), std::extents<T2, 5, 6, 7, 8, 9>());
+ test_comparison(
+ false, std::extents<T1, D, D, D, D, D>(5, 6, 7, 8, 9), std::extents<T2, D, D, D, D, D>(5, 6, 3, 8, 9));
+ test_comparison(false, std::extents<T1, D, 6, D, 8, D>(5, 7, 9), std::extents<T2, 5, D, D, 3, 9>(6, 7));
+ test_comparison(false, std::extents<T1, 5, 6, 7, 8, 9>(5, 6, 7, 8, 9), std::extents<T2, 5, 6, 7, 3, 9>());
+}
+
+template <class T1, class T2>
+constexpr void test_comparison() {
+ test_comparison_same_rank<T1, T2>();
+ test_comparison_different_rank<T1, T2>();
+}
+
+constexpr bool test() {
+ test_comparison<int, int>();
+ test_comparison<int, size_t>();
+ test_comparison<size_t, int>();
+ test_comparison<size_t, long>();
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/extents/conversion.pass.cpp b/libcxx/test/std/containers/views/mdspan/extents/conversion.pass.cpp
new file mode 100644
index 000000000000..6b0ecff02baa
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/extents/conversion.pass.cpp
@@ -0,0 +1,138 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <mdspan>
+
+// template<class OtherIndexType, size_t... OtherExtents>
+// constexpr explicit(see below) extents(const extents<OtherIndexType, OtherExtents...>&) noexcept;
+//
+// Constraints:
+// * sizeof...(OtherExtents) == rank() is true.
+// * ((OtherExtents == dynamic_extent || Extents == dynamic_extent ||
+// OtherExtents == Extents) && ...) is true.
+//
+// Preconditions:
+// * other.extent(r) equals Er for each r for which Er is a static extent, and
+// * either
+// - sizeof...(OtherExtents) is zero, or
+// - other.extent(r) is representable as a value of type index_type for
+// every rank index r of other.
+//
+// Remarks: The expression inside explicit is equivalent to:
+// (((Extents != dynamic_extent) && (OtherExtents == dynamic_extent)) || ... ) ||
+// (numeric_limits<index_type>::max() < numeric_limits<OtherIndexType>::max())
+
+#include <mdspan>
+#include <type_traits>
+#include <concepts>
+#include <cassert>
+#include <limits>
+
+#include "test_macros.h"
+
+template <class To, class From>
+constexpr void test_implicit_conversion(To dest, From src) {
+ assert(dest == src);
+}
+
+template <bool implicit, class To, class From>
+constexpr void test_conversion(From src) {
+ To dest(src);
+ assert(dest == src);
+ if constexpr (implicit) {
+ dest = src;
+ assert(dest == src);
+ test_implicit_conversion<To, From>(src, src);
+ }
+}
+
+template <class T1, class T2>
+constexpr void test_conversion() {
+ constexpr size_t D = std::dynamic_extent;
+ constexpr bool idx_convertible =
+ static_cast<size_t>(std::numeric_limits<T1>::max()) >= static_cast<size_t>(std::numeric_limits<T2>::max());
+
+ // clang-format off
+ test_conversion<idx_convertible && true, std::extents<T1>>(std::extents<T2>());
+ test_conversion<idx_convertible && true, std::extents<T1, D>>(std::extents<T2, D>(5));
+ test_conversion<idx_convertible && false, std::extents<T1, 5>>(std::extents<T2, D>(5));
+ test_conversion<idx_convertible && true, std::extents<T1, 5>>(std::extents<T2, 5>());
+ test_conversion<idx_convertible && false, std::extents<T1, 5, D>>(std::extents<T2, D, D>(5, 5));
+ test_conversion<idx_convertible && true, std::extents<T1, D, D>>(std::extents<T2, D, D>(5, 5));
+ test_conversion<idx_convertible && true, std::extents<T1, D, D>>(std::extents<T2, D, 7>(5));
+ test_conversion<idx_convertible && true, std::extents<T1, 5, 7>>(std::extents<T2, 5, 7>());
+ test_conversion<idx_convertible && false, std::extents<T1, 5, D, 8, D, D>>(std::extents<T2, D, D, 8, 9, 1>(5, 7));
+ test_conversion<idx_convertible && true, std::extents<T1, D, D, D, D, D>>(
+ std::extents<T2, D, D, D, D, D>(5, 7, 8, 9, 1));
+ test_conversion<idx_convertible && true, std::extents<T1, D, D, 8, 9, D>>(std::extents<T2, D, 7, 8, 9, 1>(5));
+ test_conversion<idx_convertible && true, std::extents<T1, 5, 7, 8, 9, 1>>(std::extents<T2, 5, 7, 8, 9, 1>());
+ // clang-format on
+}
+
+constexpr void test_no_implicit_conversion() {
+ constexpr size_t D = std::dynamic_extent;
+ // Sanity check that one static to dynamic conversion works
+ static_assert(std::is_constructible_v<std::extents<int, D>, std::extents<int, 5>>, "");
+ static_assert(std::is_convertible_v<std::extents<int, 5>, std::extents<int, D>>, "");
+
+ // Check that dynamic to static conversion only works explicitly only
+ static_assert(std::is_constructible_v<std::extents<int, 5>, std::extents<int, D>>, "");
+ static_assert(!std::is_convertible_v<std::extents<int, D>, std::extents<int, 5>>, "");
+
+ // Sanity check that one static to dynamic conversion works
+ static_assert(std::is_constructible_v<std::extents<int, D, 7>, std::extents<int, 5, 7>>, "");
+ static_assert(std::is_convertible_v<std::extents<int, 5, 7>, std::extents<int, D, 7>>, "");
+
+ // Check that dynamic to static conversion only works explicitly only
+ static_assert(std::is_constructible_v<std::extents<int, 5, 7>, std::extents<int, D, 7>>, "");
+ static_assert(!std::is_convertible_v<std::extents<int, D, 7>, std::extents<int, 5, 7>>, "");
+
+ // Sanity check that smaller index_type to larger index_type conversion works
+ static_assert(std::is_constructible_v<std::extents<size_t, 5>, std::extents<int, 5>>, "");
+ static_assert(std::is_convertible_v<std::extents<int, 5>, std::extents<size_t, 5>>, "");
+
+ // Check that larger index_type to smaller index_type conversion works explicitly only
+ static_assert(std::is_constructible_v<std::extents<int, 5>, std::extents<size_t, 5>>, "");
+ static_assert(!std::is_convertible_v<std::extents<size_t, 5>, std::extents<int, 5>>, "");
+}
+
+constexpr void test_rank_mismatch() {
+ constexpr size_t D = std::dynamic_extent;
+
+ static_assert(!std::is_constructible_v<std::extents<int, D>, std::extents<int>>, "");
+ static_assert(!std::is_constructible_v<std::extents<int>, std::extents<int, D, D>>, "");
+ static_assert(!std::is_constructible_v<std::extents<int, D>, std::extents<int, D, D>>, "");
+ static_assert(!std::is_constructible_v<std::extents<int, D, D, D>, std::extents<int, D, D>>, "");
+}
+
+constexpr void test_static_extent_mismatch() {
+ constexpr size_t D = std::dynamic_extent;
+
+ static_assert(!std::is_constructible_v<std::extents<int, D, 5>, std::extents<int, D, 4>>, "");
+ static_assert(!std::is_constructible_v<std::extents<int, 5>, std::extents<int, 4>>, "");
+ static_assert(!std::is_constructible_v<std::extents<int, 5, D>, std::extents<int, 4, D>>, "");
+}
+
+constexpr bool test() {
+ test_conversion<int, int>();
+ test_conversion<int, size_t>();
+ test_conversion<size_t, int>();
+ test_conversion<size_t, long>();
+ test_no_implicit_conversion();
+ test_rank_mismatch();
+ test_static_extent_mismatch();
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/extents/ctad.pass.cpp b/libcxx/test/std/containers/views/mdspan/extents/ctad.pass.cpp
new file mode 100644
index 000000000000..81d85c1faf0f
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/extents/ctad.pass.cpp
@@ -0,0 +1,46 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <mdspan>
+
+// template <class... Integrals>
+// explicit extents(Integrals...) -> see below;
+// Constraints: (is_convertible_v<Integrals, size_t> && ...) is true.
+//
+// Remarks: The deduced type is dextents<size_t, sizeof...(Integrals)>.
+
+#include <mdspan>
+#include <cassert>
+
+#include "ConvertibleToIntegral.h"
+#include "test_macros.h"
+
+template <class E, class Expected>
+constexpr void test(E e, Expected expected) {
+ ASSERT_SAME_TYPE(E, Expected);
+ assert(e == expected);
+}
+
+constexpr bool test() {
+ constexpr std::size_t D = std::dynamic_extent;
+
+ test(std::extents(), std::extents<size_t>());
+ test(std::extents(1), std::extents<std::size_t, D>(1));
+ test(std::extents(1, 2u), std::extents<std::size_t, D, D>(1, 2u));
+ test(std::extents(1, 2u, 3, 4, 5, 6, 7, 8, 9),
+ std::extents<std::size_t, D, D, D, D, D, D, D, D, D>(1, 2u, 3, 4, 5, 6, 7, 8, 9));
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/extents/ctor_default.pass.cpp b/libcxx/test/std/containers/views/mdspan/extents/ctor_default.pass.cpp
new file mode 100644
index 000000000000..b2de473f8e8c
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/extents/ctor_default.pass.cpp
@@ -0,0 +1,49 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <mdspan>
+
+// Test default construction:
+//
+// constexpr extents() noexcept = default;
+//
+// Remarks: since the standard uses an exposition only array member, dynamic extents
+// need to be zero intialized!
+
+#include <mdspan>
+#include <cassert>
+#include <array>
+
+#include "ConvertibleToIntegral.h"
+#include "CtorTestCombinations.h"
+#include "test_macros.h"
+
+struct DefaultCtorTest {
+ template <class E, class AllExtents, class Extents, size_t... Indices>
+ static constexpr void test_construction(AllExtents all_ext, Extents, std::index_sequence<Indices...>) {
+ // This function gets called twice: once with Extents being just the dynamic ones, and once with all the extents specified.
+ // We only test during the all extent case, since then Indices is the correct number. This allows us to reuse the same
+ // testing machinery used in other constructor tests.
+ if constexpr (sizeof...(Indices) == E::rank()) {
+ ASSERT_NOEXCEPT(E{});
+ // Need to construct new expected values, replacing dynamic values with 0
+ std::array<typename AllExtents::value_type, E::rank()> expected_exts{
+ ((E::static_extent(Indices) == std::dynamic_extent)
+ ? typename AllExtents::value_type(0)
+ : all_ext[Indices])...};
+ test_runtime_observers(E{}, expected_exts);
+ }
+ }
+};
+
+int main(int, char**) {
+ test_index_type_combo<DefaultCtorTest>();
+ static_assert(test_index_type_combo<DefaultCtorTest>());
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/extents/ctor_from_array.pass.cpp b/libcxx/test/std/containers/views/mdspan/extents/ctor_from_array.pass.cpp
new file mode 100644
index 000000000000..48286e112849
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/extents/ctor_from_array.pass.cpp
@@ -0,0 +1,86 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <mdspan>
+
+// Test construction from array:
+//
+// template<class OtherIndexType, size_t N>
+// constexpr explicit(N != rank_dynamic()) extents(const array<OtherIndexType, N>& exts) noexcept;
+//
+// Constraints:
+// * is_convertible_v<const OtherIndexType&, index_type> is true,
+// * is_nothrow_constructible_v<index_type, const OtherIndexType&> is true, and
+// * N == rank_dynamic() || N == rank() is true.
+//
+// Preconditions:
+// * If N != rank_dynamic() is true, exts[r] equals Er for each r for which
+// Er is a static extent, and
+// * either
+// - N is zero, or
+// - exts[r] is nonnegative and is representable as a value of type index_type
+// for every rank index r.
+//
+
+#include <mdspan>
+#include <cassert>
+#include <array>
+#include <type_traits>
+
+#include "ConvertibleToIntegral.h"
+#include "CtorTestCombinations.h"
+#include "test_macros.h"
+
+struct ArrayCtorTest {
+ template <class E, class T, size_t N, class Extents, size_t... Indices>
+ static constexpr void test_construction(std::array<T, N> all_ext, Extents ext, std::index_sequence<Indices...>) {
+ ASSERT_NOEXCEPT(E(ext));
+ if constexpr (N == E::rank_dynamic()) {
+ test_implicit_construction_call<E>(ext, all_ext);
+ }
+ test_runtime_observers(E(ext), all_ext);
+ }
+};
+
+template <class E>
+struct implicit_construction {
+ bool value;
+ implicit_construction(E) : value(true) {}
+ template <class T>
+ implicit_construction(T) : value(false) {}
+};
+
+int main(int, char**) {
+ test_index_type_combo<ArrayCtorTest>();
+ static_assert(test_index_type_combo<ArrayCtorTest>());
+
+ constexpr size_t D = std::dynamic_extent;
+ using E = std::extents<int, 1, D, 3, D>;
+
+ // check can't construct from too few arguments
+ static_assert(!std::is_constructible_v<E, std::array<int, 1>>, "extents constructible from illegal arguments");
+ // check can't construct from rank_dynamic < #args < rank
+ static_assert(!std::is_constructible_v<E, std::array<int, 3>>, "extents constructible from illegal arguments");
+ // check can't construct from too many arguments
+ static_assert(!std::is_constructible_v<E, std::array<int, 5>>, "extents constructible from illegal arguments");
+
+ // test implicit construction fails from span and array if all extents are given
+ std::array a5{3, 4, 5, 6, 7};
+ // check that explicit construction works, i.e. no error
+ static_assert(std::is_constructible_v< std::extents<int, D, D, 5, D, D>, decltype(a5)>,
+ "extents unexpectectly not constructible");
+ // check that implicit construction doesn't work
+ assert((implicit_construction<std::extents<int, D, D, 5, D, D>>(a5).value == false));
+
+ // test construction fails from types not convertible to index_type but convertible to other integer types
+ static_assert(std::is_convertible_v<IntType, int>, "Test helper IntType unexpectedly not convertible to int");
+ static_assert(!std::is_constructible_v< std::extents<unsigned long, D>, std::array<IntType, 1>>,
+ "extents constructible from illegal arguments");
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/extents/ctor_from_integral.pass.cpp b/libcxx/test/std/containers/views/mdspan/extents/ctor_from_integral.pass.cpp
new file mode 100644
index 000000000000..fd3624e74a3d
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/extents/ctor_from_integral.pass.cpp
@@ -0,0 +1,69 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <mdspan>
+
+// Test construction from integral:
+//
+// template<class ... OtherIndexTypes>
+// constexpr explicit extents(OtherIndexTypes ... exts) noexcept;
+//
+// Let N be sizeof...(OtherIndexTypes), and let
+// exts_arr be array<index_type, N>{static_cast<index_type>(std::move(exts))...}.
+//
+// Constraints:
+// * (is_convertible_v<OtherIndexTypes, index_type> && ...) is true,
+// * (is_nothrow_constructible_v<index_type, OtherIndexType> && ...) is true, and
+// * N == rank_dynamic() || N == rank() is true.
+//
+// Preconditions:
+// * If N != rank_dynamic() is true, exts_arr[r] equals Er for each r for which
+// Er is a static extent, and
+// * either
+// - sizeof...(exts) == 0 is true, or
+// - each element of exts is nonnegative and is representable as a value of type index_type.
+//
+
+#include <mdspan>
+#include <cassert>
+#include <type_traits>
+
+#include "ConvertibleToIntegral.h"
+#include "CtorTestCombinations.h"
+#include "test_macros.h"
+
+struct IntegralCtorTest {
+ template <class E, class AllExtents, class Extents, size_t... Indices>
+ static constexpr void test_construction(AllExtents all_ext, Extents ext, std::index_sequence<Indices...>) {
+ // construction from indices
+ ASSERT_NOEXCEPT(E(ext[Indices]...));
+ test_runtime_observers(E(ext[Indices]...), all_ext);
+ }
+};
+
+int main(int, char**) {
+ test_index_type_combo<IntegralCtorTest>();
+ static_assert(test_index_type_combo<IntegralCtorTest>());
+
+ constexpr size_t D = std::dynamic_extent;
+ using E = std::extents<int, 1, D, 3, D>;
+
+ // check can't construct from too few arguments
+ static_assert(!std::is_constructible_v<E, int>, "extents constructible from illegal arguments");
+ // check can't construct from rank_dynamic < #args < rank
+ static_assert(!std::is_constructible_v<E, int, int, int>, "extents constructible from illegal arguments");
+ // check can't construct from too many arguments
+ static_assert(!std::is_constructible_v<E, int, int, int, int, int>, "extents constructible from illegal arguments");
+
+ // test construction fails from types not convertible to index_type but convertible to other integer types
+ static_assert(std::is_convertible_v<IntType, int>, "Test helper IntType unexpectedly not convertible to int");
+ static_assert(!std::is_constructible_v< std::extents<unsigned long, D>, IntType>,
+ "extents constructible from illegal arguments");
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/extents/ctor_from_span.pass.cpp b/libcxx/test/std/containers/views/mdspan/extents/ctor_from_span.pass.cpp
new file mode 100644
index 000000000000..2e69bab1461c
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/extents/ctor_from_span.pass.cpp
@@ -0,0 +1,88 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <mdspan>
+
+// Test construction from span:
+//
+// template<class OtherIndexType, size_t N>
+// constexpr explicit(N != rank_dynamic()) extents(span<OtherIndexType, N> exts) noexcept;
+//
+// Constraints:
+// * is_convertible_v<const OtherIndexType&, index_type> is true,
+// * is_nothrow_constructible_v<index_type, const OtherIndexType&> is true, and
+// * N == rank_dynamic() || N == rank() is true.
+//
+// Preconditions:
+// * If N != rank_dynamic() is true, exts[r] equals Er for each r for which
+// Er is a static extent, and
+// * either
+// - N is zero, or
+// - exts[r] is nonnegative and is representable as a value of type index_type
+// for every rank index r.
+//
+
+#include <mdspan>
+#include <cassert>
+#include <array>
+#include <span>
+#include <type_traits>
+
+#include "ConvertibleToIntegral.h"
+#include "CtorTestCombinations.h"
+#include "test_macros.h"
+
+struct SpanCtorTest {
+ template <class E, class T, size_t N, class Extents, size_t... Indices>
+ static constexpr void test_construction(std::array<T, N> all_ext, Extents ext, std::index_sequence<Indices...>) {
+ ASSERT_NOEXCEPT(E(ext));
+ if constexpr (N == E::rank_dynamic()) {
+ test_implicit_construction_call<E>(std::span(ext), all_ext);
+ }
+ test_runtime_observers(E(std::span(ext)), all_ext);
+ }
+};
+
+template <class E>
+struct implicit_construction {
+ bool value;
+ implicit_construction(E) : value(true) {}
+ template <class T>
+ implicit_construction(T) : value(false) {}
+};
+
+int main(int, char**) {
+ test_index_type_combo<SpanCtorTest>();
+ static_assert(test_index_type_combo<SpanCtorTest>());
+
+ constexpr size_t D = std::dynamic_extent;
+ using E = std::extents<int, 1, D, 3, D>;
+
+ // check can't construct from too few arguments
+ static_assert(!std::is_constructible_v<E, std::span<int, 1>>, "extents constructible from illegal arguments");
+ // check can't construct from rank_dynamic < #args < rank
+ static_assert(!std::is_constructible_v<E, std::span<int, 3>>, "extents constructible from illegal arguments");
+ // check can't construct from too many arguments
+ static_assert(!std::is_constructible_v<E, std::span<int, 5>>, "extents constructible from illegal arguments");
+
+ // test implicit construction fails from span and array if all extents are given
+ std::array a5{3, 4, 5, 6, 7};
+ std::span<int, 5> s5(a5.data(), 5);
+ // check that explicit construction works, i.e. no error
+ static_assert(std::is_constructible_v< std::extents<int, D, D, 5, D, D>, decltype(s5)>,
+ "extents unexpectectly not constructible");
+ // check that implicit construction doesn't work
+ assert((implicit_construction<std::extents<int, D, D, 5, D, D>>(s5).value == false));
+
+ // test construction fails from types not convertible to index_type but convertible to other integer types
+ static_assert(std::is_convertible_v<IntType, int>, "Test helper IntType unexpectedly not convertible to int");
+ static_assert(!std::is_constructible_v< std::extents<unsigned long, D>, std::span<IntType, 1>>,
+ "extents constructible from illegal arguments");
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/extents/dextents.pass.cpp b/libcxx/test/std/containers/views/mdspan/extents/dextents.pass.cpp
new file mode 100644
index 000000000000..a9fc8f3bed07
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/extents/dextents.pass.cpp
@@ -0,0 +1,39 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <mdspan>
+
+// template<class IndexType, size_t Rank>
+// using dextents = see below;
+//
+// Result: A type E that is a specialization of extents such that
+// E::rank() == Rank && E::rank() == E::rank_dynamic() is true,
+// and E::index_type denotes IndexType.
+
+#include <mdspan>
+#include <cstddef>
+
+#include "test_macros.h"
+
+template <class IndexType>
+void test_alias_template_dextents() {
+ constexpr size_t D = std::dynamic_extent;
+ ASSERT_SAME_TYPE(std::dextents<IndexType, 0>, std::extents<IndexType>);
+ ASSERT_SAME_TYPE(std::dextents<IndexType, 1>, std::extents<IndexType, D>);
+ ASSERT_SAME_TYPE(std::dextents<IndexType, 2>, std::extents<IndexType, D, D>);
+ ASSERT_SAME_TYPE(std::dextents<IndexType, 3>, std::extents<IndexType, D, D, D>);
+ ASSERT_SAME_TYPE(std::dextents<IndexType, 9>, std::extents<IndexType, D, D, D, D, D, D, D, D, D>);
+}
+
+int main(int, char**) {
+ test_alias_template_dextents<int>();
+ test_alias_template_dextents<unsigned int>();
+ test_alias_template_dextents<size_t>();
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/extents/obs_static.pass.cpp b/libcxx/test/std/containers/views/mdspan/extents/obs_static.pass.cpp
new file mode 100644
index 000000000000..90b482b3bc06
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/extents/obs_static.pass.cpp
@@ -0,0 +1,88 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <mdspan>
+
+// static constexpr rank_type rank() noexcept;
+// static constexpr rank_type rank_dynamic() noexcept;
+//
+// static constexpr size_t static_extent(rank_type i) noexcept;
+//
+// Preconditions: i < rank() is true.
+//
+// Returns: Ei.
+//
+//
+// constexpr index_type extent(rank_type i) const noexcept;
+//
+// Preconditions: i < rank() is true.
+//
+// Returns: Di.
+//
+
+#include <mdspan>
+#include <cassert>
+#include <utility>
+
+#include "test_macros.h"
+
+template <class E, size_t rank, size_t rank_dynamic, size_t... StaticExts, size_t... Indices>
+void test_static_observers(std::index_sequence<StaticExts...>, std::index_sequence<Indices...>) {
+ ASSERT_NOEXCEPT(E::rank());
+ static_assert(E::rank() == rank);
+ ASSERT_NOEXCEPT(E::rank_dynamic());
+ static_assert(E::rank_dynamic() == rank_dynamic);
+
+ // Let's only test this if the call isn't a precondition violation
+ if constexpr (rank > 0) {
+ ASSERT_NOEXCEPT(E::static_extent(0));
+ ASSERT_SAME_TYPE(decltype(E::static_extent(0)), size_t);
+ static_assert(((E::static_extent(Indices) == StaticExts) && ...));
+ }
+}
+
+template <class E, size_t rank, size_t rank_dynamic, size_t... StaticExts>
+void test_static_observers() {
+ test_static_observers<E, rank, rank_dynamic>(
+ std::index_sequence<StaticExts...>(), std::make_index_sequence<sizeof...(StaticExts)>());
+}
+
+template <class T>
+void test() {
+ constexpr size_t D = std::dynamic_extent;
+ constexpr size_t S = 5;
+
+ test_static_observers<std::extents<T>, 0, 0>();
+
+ test_static_observers<std::extents<T, S>, 1, 0, S>();
+ test_static_observers<std::extents<T, D>, 1, 1, D>();
+
+ test_static_observers<std::extents<T, S, S>, 2, 0, S, S>();
+ test_static_observers<std::extents<T, S, D>, 2, 1, S, D>();
+ test_static_observers<std::extents<T, D, S>, 2, 1, D, S>();
+ test_static_observers<std::extents<T, D, D>, 2, 2, D, D>();
+
+ test_static_observers<std::extents<T, S, S, S>, 3, 0, S, S, S>();
+ test_static_observers<std::extents<T, S, S, D>, 3, 1, S, S, D>();
+ test_static_observers<std::extents<T, S, D, S>, 3, 1, S, D, S>();
+ test_static_observers<std::extents<T, D, S, S>, 3, 1, D, S, S>();
+ test_static_observers<std::extents<T, S, D, D>, 3, 2, S, D, D>();
+ test_static_observers<std::extents<T, D, S, D>, 3, 2, D, S, D>();
+ test_static_observers<std::extents<T, D, D, S>, 3, 2, D, D, S>();
+ test_static_observers<std::extents<T, D, D, D>, 3, 3, D, D, D>();
+}
+
+int main(int, char**) {
+ test<int>();
+ test<unsigned>();
+ test<char>();
+ test<long long>();
+ test<size_t>();
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/extents/types.pass.cpp b/libcxx/test/std/containers/views/mdspan/extents/types.pass.cpp
new file mode 100644
index 000000000000..228194533399
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/extents/types.pass.cpp
@@ -0,0 +1,85 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <mdspan>
+
+// template<class IndexType, size_t... Extents>
+// class extents {
+// public:
+// // types
+// using index_type = IndexType;
+// using size_type = make_unsigned_t<index_type>;
+// using rank_type = size_t;
+//
+// static constexpr rank_type rank() noexcept { return sizeof...(Extents); }
+// static constexpr rank_type rank_dynamic() noexcept { return dynamic-index(rank()); }
+// ...
+// }
+
+#include <mdspan>
+#include <type_traits>
+#include <concepts>
+#include <cassert>
+
+#include "test_macros.h"
+
+template <class E, class IndexType, size_t... Extents>
+void testExtents() {
+ ASSERT_SAME_TYPE(typename E::index_type, IndexType);
+ ASSERT_SAME_TYPE(typename E::size_type, std::make_unsigned_t<IndexType>);
+ ASSERT_SAME_TYPE(typename E::rank_type, size_t);
+
+ static_assert(sizeof...(Extents) == E::rank());
+ static_assert((static_cast<size_t>(Extents == std::dynamic_extent) + ...) == E::rank_dynamic());
+
+ static_assert(std::regular<E>);
+ static_assert(std::is_trivially_copyable_v<E>);
+
+// Did never find a way to make this true on windows
+#ifndef _WIN32
+ LIBCPP_STATIC_ASSERT(std::is_empty_v<E> == (E::rank_dynamic() == 0));
+#endif
+}
+
+template <class IndexType, size_t... Extents>
+void testExtents() {
+ testExtents<std::extents<IndexType, Extents...>, IndexType, Extents...>();
+}
+
+template <class T>
+void test() {
+ constexpr size_t D = std::dynamic_extent;
+ testExtents<T, D>();
+ testExtents<T, 3>();
+ testExtents<T, 3, 3>();
+ testExtents<T, 3, D>();
+ testExtents<T, D, 3>();
+ testExtents<T, D, D>();
+ testExtents<T, 3, 3, 3>();
+ testExtents<T, 3, 3, D>();
+ testExtents<T, 3, D, D>();
+ testExtents<T, D, 3, D>();
+ testExtents<T, D, D, D>();
+ testExtents<T, 3, D, 3>();
+ testExtents<T, D, 3, 3>();
+ testExtents<T, D, D, 3>();
+
+ testExtents<T, 9, 8, 7, 6, 5, 4, 3, 2, 1>();
+ testExtents<T, 9, D, 7, 6, D, D, 3, D, D>();
+ testExtents<T, D, D, D, D, D, D, D, D, D>();
+}
+
+int main(int, char**) {
+ test<int>();
+ test<unsigned>();
+ test<char>();
+ test<long long>();
+ test<size_t>();
+ return 0;
+}
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/mdspan.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/mdspan.version.compile.pass.cpp
new file mode 100644
index 000000000000..26c2600f14e6
--- /dev/null
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/mdspan.version.compile.pass.cpp
@@ -0,0 +1,65 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// WARNING: This test was generated by generate_feature_test_macro_components.py
+// and should not be edited manually.
+//
+// clang-format off
+
+// <mdspan>
+
+// Test the feature test macros defined by <mdspan>
+
+/* Constant Value
+ __cpp_lib_mdspan 202207L [C++2b]
+*/
+
+#include <mdspan>
+#include "test_macros.h"
+
+#if TEST_STD_VER < 14
+
+# ifdef __cpp_lib_mdspan
+# error "__cpp_lib_mdspan should not be defined before c++2b"
+# endif
+
+#elif TEST_STD_VER == 14
+
+# ifdef __cpp_lib_mdspan
+# error "__cpp_lib_mdspan should not be defined before c++2b"
+# endif
+
+#elif TEST_STD_VER == 17
+
+# ifdef __cpp_lib_mdspan
+# error "__cpp_lib_mdspan should not be defined before c++2b"
+# endif
+
+#elif TEST_STD_VER == 20
+
+# ifdef __cpp_lib_mdspan
+# error "__cpp_lib_mdspan should not be defined before c++2b"
+# endif
+
+#elif TEST_STD_VER > 20
+
+# if !defined(_LIBCPP_VERSION)
+# ifndef __cpp_lib_mdspan
+# error "__cpp_lib_mdspan should be defined in c++2b"
+# endif
+# if __cpp_lib_mdspan != 202207L
+# error "__cpp_lib_mdspan should have the value 202207L in c++2b"
+# endif
+# else // _LIBCPP_VERSION
+# ifdef __cpp_lib_mdspan
+# error "__cpp_lib_mdspan should not be defined because it is unimplemented in libc++!"
+# endif
+# endif
+
+#endif // TEST_STD_VER > 20
+
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
index a289eebb4309..e1bdde4551a7 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
@@ -117,6 +117,7 @@
__cpp_lib_map_try_emplace 201411L [C++17]
__cpp_lib_math_constants 201907L [C++20]
__cpp_lib_math_special_functions 201603L [C++17]
+ __cpp_lib_mdspan 202207L [C++2b]
__cpp_lib_memory_resource 201603L [C++17]
__cpp_lib_move_iterator_concept 202207L [C++20]
__cpp_lib_move_only_function 202110L [C++2b]
@@ -585,6 +586,10 @@
# error "__cpp_lib_math_special_functions should not be defined before c++17"
# endif
+# ifdef __cpp_lib_mdspan
+# error "__cpp_lib_mdspan should not be defined before c++2b"
+# endif
+
# ifdef __cpp_lib_memory_resource
# error "__cpp_lib_memory_resource should not be defined before c++17"
# endif
@@ -1269,6 +1274,10 @@
# error "__cpp_lib_math_special_functions should not be defined before c++17"
# endif
+# ifdef __cpp_lib_mdspan
+# error "__cpp_lib_mdspan should not be defined before c++2b"
+# endif
+
# ifdef __cpp_lib_memory_resource
# error "__cpp_lib_memory_resource should not be defined before c++17"
# endif
@@ -2100,6 +2109,10 @@
# endif
# endif
+# ifdef __cpp_lib_mdspan
+# error "__cpp_lib_mdspan should not be defined before c++2b"
+# endif
+
# ifndef __cpp_lib_memory_resource
# error "__cpp_lib_memory_resource should be defined in c++17"
# endif
@@ -3216,6 +3229,10 @@
# endif
# endif
+# ifdef __cpp_lib_mdspan
+# error "__cpp_lib_mdspan should not be defined before c++2b"
+# endif
+
# ifndef __cpp_lib_memory_resource
# error "__cpp_lib_memory_resource should be defined in c++20"
# endif
@@ -4488,6 +4505,19 @@
# endif
# endif
+# if !defined(_LIBCPP_VERSION)
+# ifndef __cpp_lib_mdspan
+# error "__cpp_lib_mdspan should be defined in c++2b"
+# endif
+# if __cpp_lib_mdspan != 202207L
+# error "__cpp_lib_mdspan should have the value 202207L in c++2b"
+# endif
+# else // _LIBCPP_VERSION
+# ifdef __cpp_lib_mdspan
+# error "__cpp_lib_mdspan should not be defined because it is unimplemented in libc++!"
+# endif
+# endif
+
# ifndef __cpp_lib_memory_resource
# error "__cpp_lib_memory_resource should be defined in c++2b"
# endif
diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index fb59395115e3..5ace82348dcb 100755
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -495,6 +495,11 @@ feature_test_macros = [ add_version_header(x) for x in [
"headers": ["cmath"],
"unimplemented": True,
}, {
+ "name": "__cpp_lib_mdspan",
+ "values": { "c++2b": 202207 },
+ "headers": ["mdspan"],
+ "unimplemented": True,
+ }, {
"name": "__cpp_lib_memory_resource",
"values": { "c++17": 201603 },
"headers": ["memory_resource"],