summaryrefslogtreecommitdiff
path: root/libcxx
diff options
context:
space:
mode:
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"],