This commit adds a new layout layout_left_padded as standardized in
N5014 but with one deviation. It includes checking of all mandates and
prerequisites. It adds a purely internal feature testing macro
padded_layouts and registers layout_left_padded in the std module.

The standard mandates that the padding_value is representable as
index_type. However, padding_value can be dynamic_extent which is
defined as `size_t(-1)`. Hence, it's impossible to use a dynamic
padding_value if index_type is int. The deviation is to only require
static padding values to be representable as index_type; and thereby
allow dynamic padding values for every index_type.

libstdc++-v3/ChangeLog:

        * include/bits/version.def (padded_layouts): Add as internal
        only.
        * include/bits/version.h: Regenerate.
        * include/std/mdspan (__fwd_prod): New overload.
        (layout_left_padded): Add declaration and implementation.
        (layout_right_padded): Add declaration only.
        (__is_left_padded_mapping): New concept.
        (__is_right_padded_mapping): Ditto.
        (__standardized_mapping): Recognize left and right padded
        mappings.
        (layout_left::mapping::mapping): New overload for left
        padded mappings.
        * src/c++23/std.cc.in (layout_left_padded): Add.
        * testsuite/23_containers/mdspan/layouts/class_mandate_neg.cc:
        Add tests for layout_left_padded.
        * testsuite/23_containers/mdspan/layouts/ctors.cc: Ditto.
        * testsuite/23_containers/mdspan/layouts/empty.cc: Ditto.
        * testsuite/23_containers/mdspan/layouts/mapping.cc: Ditto.
        * testsuite/23_containers/mdspan/layouts/debug/padded_neg.cc: New test.
        * testsuite/23_containers/mdspan/layouts/padded.cc: Ditto.
        * testsuite/23_containers/mdspan/layouts/padded_neg.cc: Ditto.

Signed-off-by: Luc Grosheintz <[email protected]>
---
 libstdc++-v3/include/bits/version.def         |  10 +
 libstdc++-v3/include/bits/version.h           |   9 +
 libstdc++-v3/include/std/mdspan               | 522 ++++++++++++++-
 libstdc++-v3/src/c++23/std.cc.in              |   8 +-
 .../mdspan/layouts/class_mandate_neg.cc       |   1 +
 .../23_containers/mdspan/layouts/ctors.cc     |  61 +-
 .../mdspan/layouts/debug/padded_neg.cc        |  22 +
 .../23_containers/mdspan/layouts/empty.cc     |  12 +-
 .../23_containers/mdspan/layouts/mapping.cc   |  72 ++-
 .../23_containers/mdspan/layouts/padded.cc    | 611 ++++++++++++++++++
 .../mdspan/layouts/padded_neg.cc              | 280 ++++++++
 11 files changed, 1592 insertions(+), 16 deletions(-)
 create mode 100644 
libstdc++-v3/testsuite/23_containers/mdspan/layouts/debug/padded_neg.cc
 create mode 100644 
libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded.cc
 create mode 100644 
libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded_neg.cc

diff --git a/libstdc++-v3/include/bits/version.def 
b/libstdc++-v3/include/bits/version.def
index 65b9a278776..63e5f394a8f 100644
--- a/libstdc++-v3/include/bits/version.def
+++ b/libstdc++-v3/include/bits/version.def
@@ -1050,6 +1050,16 @@ ftms = {
     cxxmin = 26;
     extra_cond = "__glibcxx_assume_aligned "
     "&& __glibcxx_is_sufficiently_aligned";
+    };
+};
+
+// Unofficial macro signaling presence of the two padded layouts.
+ftms = {
+  name = padded_layouts;
+  no_stdname = true; // Don't change: it's not a standardized FTM.
+  values = {
+    v = 1;
+    cxxmin = 26;
   };
 };
 
diff --git a/libstdc++-v3/include/bits/version.h 
b/libstdc++-v3/include/bits/version.h
index b05249857d2..6b4197e599d 100644
--- a/libstdc++-v3/include/bits/version.h
+++ b/libstdc++-v3/include/bits/version.h
@@ -1178,6 +1178,15 @@
 #endif /* !defined(__cpp_lib_aligned_accessor) && 
defined(__glibcxx_want_aligned_accessor) */
 #undef __glibcxx_want_aligned_accessor
 
+#if !defined(__cpp_lib_padded_layouts)
+# if (__cplusplus >  202302L)
+#  define __glibcxx_padded_layouts 1L
+#  if defined(__glibcxx_want_all) || defined(__glibcxx_want_padded_layouts)
+#  endif
+# endif
+#endif /* !defined(__cpp_lib_padded_layouts) && 
defined(__glibcxx_want_padded_layouts) */
+#undef __glibcxx_want_padded_layouts
+
 #if !defined(__cpp_lib_ssize)
 # if (__cplusplus >= 202002L)
 #  define __glibcxx_ssize 201902L
diff --git a/libstdc++-v3/include/std/mdspan b/libstdc++-v3/include/std/mdspan
index 9dd0c85f5b0..251566c7051 100644
--- a/libstdc++-v3/include/std/mdspan
+++ b/libstdc++-v3/include/std/mdspan
@@ -233,6 +233,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        _S_static_extents() noexcept
        { return _Extents; }
 
+       static constexpr span<const size_t>
+       _S_static_extents(size_t __begin, size_t __end) noexcept
+       { return span(_Extents.data() + __begin, __end - __begin); }
+
        constexpr span<const _IndexType>
        _M_dynamic_extents(size_t __begin, size_t __end) const noexcept
        requires (_Extents.size() > 0)
@@ -261,6 +265,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       __static_extents() noexcept
       { return _Extents::_Storage::_S_static_extents(); }
 
+    template<typename _Extents>
+      constexpr span<const size_t>
+      __static_extents(size_t __begin, size_t __end) noexcept
+      { return _Extents::_Storage::_S_static_extents(__begin, __end); }
+
     // Pre-compute: \prod_{i = 0}^r _Extents[i], for r = 0,..., n (exclusive)
     template<array _Extents>
       constexpr auto __fwd_partial_prods = [] consteval
@@ -420,6 +429,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       friend const array<size_t, rank()>&
       __mdspan::__static_extents<extents>();
 
+      friend span<const size_t>
+      __mdspan::__static_extents<extents>(size_t __begin, size_t __end);
+
       friend span<const index_type>
       __mdspan::__dynamic_extents<extents>(const extents&, size_t, size_t);
 
@@ -476,6 +488,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       }
 
     // Preconditions: _r < _Extents::rank()
+    template<typename _Extents>
+      constexpr typename _Extents::index_type
+      __fwd_prod(const _Extents& __exts, size_t __begin, size_t __end) noexcept
+      {
+       size_t __sta_prod = [__begin, __end] {
+         span<const size_t> __sta_exts = __static_extents<_Extents>();
+         size_t __ret = 1;
+         for(auto __ext : __sta_exts.subspan(__begin, __end - __begin))
+           if (__ext != dynamic_extent)
+             __ret *= __ext;
+         return __ret;
+       }();
+       return __extents_prod(__exts, __sta_prod, __begin, __end);
+      }
+
     template<typename _Extents>
       constexpr typename _Extents::index_type
       __fwd_prod(const _Extents& __exts, size_t __r) noexcept
@@ -567,6 +594,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       class mapping;
   };
 
+#ifdef __glibcxx_padded_layouts
+  template<size_t _PaddingValue>
+    struct layout_left_padded
+    {
+      template<typename _Extents>
+       class mapping;
+    };
+
+  template<size_t _PaddingValue>
+    struct layout_right_padded
+    {
+      template<typename _Extents>
+       class mapping;
+    };
+#endif
+
   namespace __mdspan
   {
     template<typename _Tp>
@@ -669,10 +712,39 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        is_same_v<typename _Layout::template mapping<typename 
_Mapping::extents_type>,
                  _Mapping>;
 
+    template<template<size_t> typename _Layout, typename _Mapping>
+      concept __is_padded_mapping_of = requires
+      {
+       typename _Mapping::extents_type;
+       { _Mapping::padding_value } -> same_as<const size_t&>;
+      }
+      && same_as<_Mapping, typename _Layout<_Mapping::padding_value>::mapping<
+         typename _Mapping::extents_type>>;
+
+#ifdef __glibcxx_padded_layouts
+    template<typename _Mapping>
+      constexpr bool __is_left_padded_mapping = __is_padded_mapping_of<
+       layout_left_padded, _Mapping>;
+
+    template<typename _Mapping>
+      constexpr bool __is_right_padded_mapping = __is_padded_mapping_of<
+       layout_right_padded, _Mapping>;
+#endif
+
+    template<typename _PaddedMapping>
+      consteval size_t
+      __get_static_stride()
+      { return _PaddedMapping::_S_static_stride; }
+
     template<typename _Mapping>
       concept __standardized_mapping = __mapping_of<layout_left, _Mapping>
                                       || __mapping_of<layout_right, _Mapping>
-                                      || __mapping_of<layout_stride, _Mapping>;
+                                      || __mapping_of<layout_stride, _Mapping>
+#ifdef __glibcxx_padded_layouts
+                                      || __is_left_padded_mapping<_Mapping>
+                                      || __is_right_padded_mapping<_Mapping>
+#endif
+                                      ;
 
     // A tag type to create internal ctors.
     class __internal_ctor
@@ -726,6 +798,30 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        : mapping(__other.extents(), __mdspan::__internal_ctor{})
        { __glibcxx_assert(*this == __other); }
 
+#if __glibcxx_padded_layouts
+      template<class _LeftPaddedMapping>
+       requires __mdspan::__is_left_padded_mapping<_LeftPaddedMapping>
+                && is_constructible_v<extents_type,
+                                      typename 
_LeftPaddedMapping::extents_type>
+       constexpr
+       explicit(!is_convertible_v<typename _LeftPaddedMapping::extents_type,
+                                  extents_type>)
+       mapping(const _LeftPaddedMapping& __other) noexcept
+       : mapping(__other.extents(), __mdspan::__internal_ctor{})
+       {
+         constexpr size_t __ostride_sta = __mdspan::__get_static_stride<
+           _LeftPaddedMapping>();
+
+         if constexpr (extents_type::rank() > 1
+             && extents_type::static_extent(0) != dynamic_extent
+             && __ostride_sta != dynamic_extent)
+           static_assert(extents_type::static_extent(0) == __ostride_sta);
+
+         __glibcxx_assert(extents_type::rank() <= 1
+           || __other.stride(1) == __other.extents().extent(0));
+       }
+#endif
+
       constexpr mapping&
       operator=(const mapping&) noexcept = default;
 
@@ -1173,6 +1269,430 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       [[no_unique_address]] _Strides _M_strides;
     };
 
+#ifdef __glibcxx_padded_layouts
+  namespace __mdspan
+  {
+    constexpr size_t
+    __least_multiple_at_least(size_t __x, size_t __y)
+    {
+      if (__x <= 1)
+       return __y;
+      return (__y / __x + (__y % __x != 0)) * __x ;
+    }
+
+    template<typename _IndexType>
+    constexpr bool
+    __is_representable_least_multiple(size_t __x, size_t __y)
+    {
+      constexpr auto __y_max = numeric_limits<_IndexType>::max();
+      if(std::cmp_greater(__y, __y_max))
+       return false;
+
+      if(__x <= 1)
+       return true;
+
+      auto __max_delta = __y_max - static_cast<_IndexType>(__y);
+      auto __delta = (__y % __x == 0) ? size_t(0) : (__x - (__y % __x));
+      return std::cmp_less_equal(__delta, __max_delta);
+    }
+
+    template<size_t _PaddingValue, typename _Extents, typename _IndexType>
+      concept __valid_static_stride = (_Extents::rank() <= 1)
+       || (_PaddingValue == dynamic_extent)
+       || (_Extents::static_extent(0) == dynamic_extent)
+       || (__is_representable_least_multiple<_IndexType>(
+           _PaddingValue, _Extents::static_extent(0)));
+
+    template<typename _IndexType, size_t _StaticStride1, size_t _Extent0, 
size_t..._Extents>
+      constexpr auto __make_left_padded_extent(
+       extents<_IndexType, _StaticStride1> __stride1,
+       const extents<_IndexType, _Extent0, _Extents...>& __exts)
+      {
+       auto __impl = [&]<size_t... _Indices>(integer_sequence<size_t, 
_Indices...>)
+       {
+         return extents<_IndexType, _StaticStride1, _Extents...>{
+           __stride1.extent(0), __exts.extent(_Indices + 1)...};
+       };
+       return __impl(make_index_sequence<sizeof...(_Extents)>());
+      }
+
+    template<typename _Stride, typename _Extents>
+      constexpr bool
+      __is_representable_left_padded_size(const _Stride& __stride1,
+                                         const _Extents& __exts)
+      {
+       return __is_representable_extents(
+         __make_left_padded_extent(__stride1, __exts));
+      }
+
+    template<size_t _PaddingValue, typename _Extents, typename _TargetInt>
+      concept __valid_leftpad_size = (_Extents::rank() <= 1)
+       || (_PaddingValue == dynamic_extent)
+       || (!__all_static(__static_extents<_Extents>()))
+       || (__contains_zero(__static_extents<_Extents>()))
+       || (__static_quotient(__static_extents<_Extents>(1, _Extents::rank()),
+             numeric_limits<_TargetInt>::max() / __least_multiple_at_least(
+               _PaddingValue, _Extents::static_extent(0))) != 0);
+
+    template<typename _Extents, typename _Stride, typename... _Indices>
+      constexpr typename _Extents::index_type
+      __linear_index_leftpad(const _Extents& __exts, _Stride __stride,
+                            _Indices... __indices)
+      {
+       // i0 + stride*(i1 + extents.extent(1)*...)
+       using _IndexType = typename _Extents::index_type;
+       _IndexType __res = 0;
+       if constexpr (sizeof...(__indices) > 0)
+         {
+           _IndexType __mult = 1;
+
+           auto __update_rest = [&, __pos = 1u](_IndexType __idx) mutable
+             {
+               __res += __idx * __mult;
+               __mult *= __exts.extent(__pos);
+               ++__pos;
+             };
+
+           auto __update = [&](_IndexType __idx, auto... __rest)
+             {
+               __res += __idx;
+               __mult = __stride.extent(0);
+               (__update_rest(__rest), ...);
+             };
+           __update(__indices...);
+         }
+       return __res;
+      }
+  }
+
+  template<size_t _PaddingValue>
+    template<typename _Extents>
+      class layout_left_padded<_PaddingValue>::mapping
+      {
+      public:
+       static constexpr size_t padding_value = _PaddingValue;
+
+       using extents_type = _Extents;
+       using index_type = typename extents_type::index_type;
+       using size_type = typename extents_type::size_type;
+       using rank_type = typename extents_type::rank_type;
+       using layout_type = layout_left_padded<padding_value>;
+
+       static_assert(__mdspan::__representable_size<extents_type, index_type>,
+         "The size of extents_type must be representable as index_type");
+
+       static_assert(__mdspan::__valid_static_stride<padding_value, 
extents_type,
+                                                     index_type>,
+         "stride(1) must be representable as index_type");
+
+       static_assert(__mdspan::__valid_static_stride<padding_value, 
extents_type,
+                                                     size_t>,
+         "stride(1) must be representable as size_t");
+
+       static_assert(__mdspan::__valid_leftpad_size<padding_value, 
extents_type, index_type>);
+       static_assert(__mdspan::__valid_leftpad_size<padding_value, 
extents_type, size_t>);
+
+       // DEVIATION the standard requires that _PaddingValue is representable
+       // as index_type. This seems unlikely, because if index_type < size_t
+       // then the mandate is violated for `padding_value == dynamic_extent`.
+       // Which means that padding_value == dynamic_extent only reliably work
+       // if index_type == size_t (e.g. it fails for index_type == int on a
+       // 64bit system).
+       static_assert((padding_value == dynamic_extent)
+           || (cmp_less_equal(padding_value,
+                              numeric_limits<index_type>::max())),
+         "padding_value must be representable as index_type");
+
+      private:
+       static constexpr size_t _S_rank = _Extents::rank();
+       static constexpr size_t _S_static_stride = [] consteval
+       {
+         if constexpr (_S_rank <= 1)
+           return size_t(0);
+         else if constexpr (padding_value == dynamic_extent
+             || _Extents::static_extent(0) == dynamic_extent)
+           return dynamic_extent;
+         else
+           return __mdspan::__least_multiple_at_least(
+               padding_value, _Extents::static_extent(0));
+       }();
+
+       consteval friend size_t
+       __mdspan::__get_static_stride<mapping>();
+
+      public:
+       constexpr
+       mapping() noexcept
+       : mapping(extents_type{})
+       { }
+
+       constexpr
+       mapping(const mapping&) noexcept = default;
+
+       constexpr
+       mapping(const extents_type& __exts)
+       : _M_extents(__exts)
+       {
+         __glibcxx_assert(__mdspan::__is_representable_extents(_M_extents));
+         if constexpr (_S_rank > 1)
+           {
+             if constexpr (padding_value != dynamic_extent)
+               __glibcxx_assert(
+                   __mdspan::__is_representable_least_multiple<index_type>(
+                     padding_value, _M_extents.extent(0)));
+
+             index_type __stride;
+             if constexpr (padding_value == dynamic_extent)
+               __stride = __exts.extent(0);
+             else if constexpr (__exts.static_extent(0) != dynamic_extent)
+               return;
+             else
+               {
+                 __stride = static_cast<index_type>(
+                   __mdspan::__least_multiple_at_least(padding_value,
+                                                       __exts.extent(0)));
+                 __glibcxx_assert(
+                   __mdspan::__is_representable_left_padded_size(
+                     std::dextents<index_type, 1>{__stride},
+                     _M_extents));
+               }
+             _M_stride = _Stride{__stride};
+           }
+       }
+
+       template<__mdspan::__valid_index_type<index_type> _OIndexType>
+         constexpr mapping(const extents_type& __exts, _OIndexType __opad)
+         : _M_extents(__exts)
+         {
+           if constexpr (std::is_integral_v<_OIndexType>)
+             {
+               __glibcxx_assert(cmp_less_equal(__opad,
+                   numeric_limits<index_type>::max()));
+               if constexpr (std::is_signed_v<_OIndexType>)
+                 __glibcxx_assert(__opad >= 0);
+             }
+           auto __pad = static_cast<index_type>(std::move(__opad));
+           if constexpr (std::is_signed_v<index_type>)
+             __glibcxx_assert(__pad >= 0);
+           if constexpr (padding_value != dynamic_extent)
+             __glibcxx_assert(cmp_equal(padding_value, __pad));
+           if constexpr (_S_rank > 1 && _S_static_stride == dynamic_extent)
+             {
+               __glibcxx_assert(
+                 __mdspan::__is_representable_least_multiple<index_type>(
+                   __pad, _M_extents.extent(0)));
+
+               _M_stride = _Stride{static_cast<index_type>(
+                 __mdspan::__least_multiple_at_least(
+                   __pad, _M_extents.extent(0)))};
+
+               __glibcxx_assert(
+                 __mdspan::__is_representable_left_padded_size(
+                   _M_stride, _M_extents));
+             }
+         }
+
+       template<typename _OExtents>
+         requires is_constructible_v<extents_type, _OExtents>
+         constexpr explicit(!is_convertible_v<_OExtents, extents_type>)
+         mapping(const layout_left::mapping<_OExtents>& __other)
+         : mapping(extents_type(__other.extents()))
+         {
+           if constexpr (_OExtents::rank() > 1)
+             static_assert(_S_static_stride == dynamic_extent
+                 || _OExtents::static_extent(0) == dynamic_extent
+                 || _S_static_stride == _OExtents::static_extent(0),
+               "(*this).stride(1) must be compatible with other.stride(1)");
+
+           __glibcxx_assert((!(_S_rank > 1 && padding_value != dynamic_extent))
+             || (std::cmp_equal(_M_stride.extent(0),
+                                __other.extents().extent(0))));
+         }
+
+       template<typename _OExtents>
+         requires is_constructible_v<_OExtents, extents_type>
+         constexpr explicit(_OExtents::rank() > 0)
+         mapping(const typename layout_stride::mapping<_OExtents>& __other)
+         : _M_extents(__other.extents())
+         {
+           if constexpr (_S_rank > 1 && padding_value != dynamic_extent)
+             __glibcxx_assert(cmp_equal(__other.stride(1),
+                 __mdspan::__least_multiple_at_least(padding_value,
+                   __other.extents().extent(0))));
+
+           if constexpr (_S_rank > 0)
+             __glibcxx_assert(__other.stride(0) == 1);
+
+           __glibcxx_assert(cmp_less_equal(__other.required_span_size(),
+                                           numeric_limits<index_type>::max()));
+
+           if constexpr (_S_rank > 1 && _S_static_stride == dynamic_extent)
+             _M_stride = _Stride{__other.stride(1)};
+
+           if constexpr (_S_rank > 2)
+             {
+               _GLIBCXX_DEBUG_ASSERT([&]()
+                 {
+                   for (size_t __i = 2; __i < _S_rank; ++__i)
+                     if (stride(__i) != __other.stride(__i))
+                       return false;
+                   return true;
+                 }());
+             }
+         }
+
+       template<typename _LeftPaddedMapping>
+         requires __mdspan::__is_left_padded_mapping<_LeftPaddedMapping>
+             && is_constructible_v<extents_type,
+                                   typename _LeftPaddedMapping::extents_type>
+         constexpr explicit(_S_rank > 1 && (padding_value != dynamic_extent
+               || _LeftPaddedMapping::padding_value == dynamic_extent))
+         mapping(const _LeftPaddedMapping& __other)
+         : _M_extents(__other.extents())
+         {
+           if constexpr (_S_rank > 1)
+           {
+             static_assert(padding_value == dynamic_extent
+                 || _LeftPaddedMapping::padding_value == dynamic_extent
+                 || padding_value == _LeftPaddedMapping::padding_value,
+               "If neither padding_value is dynamic_extent, then they must "
+               "be equal");
+
+             __glibcxx_assert((padding_value == dynamic_extent
+                 || cmp_equal(__other.stride(1),
+                      __mdspan::__least_multiple_at_least(padding_value,
+                        __other.extents().extent(0))))
+               && "other.stride(1) must be the next larger multiple of "
+                  "padding_value that is greater or equal to other.extent(0)");
+           }
+           __glibcxx_assert(cmp_less_equal(__other.required_span_size(),
+               numeric_limits<index_type>::max()));
+
+           if constexpr (_S_rank > 1 && (_S_static_stride == dynamic_extent))
+             _M_stride = _Stride{__other.stride(1)};
+         }
+
+       template<typename _RightPaddedMapping>
+         requires (__mdspan::__is_right_padded_mapping<_RightPaddedMapping>
+             || __mdspan::__mapping_of<layout_right, _RightPaddedMapping>)
+           && (_S_rank <= 1)
+           && is_constructible_v<extents_type,
+                                 typename _RightPaddedMapping::extents_type>
+         constexpr explicit(!is_convertible_v<
+             typename _RightPaddedMapping::extents_type, extents_type>)
+         mapping(const _RightPaddedMapping& __other) noexcept
+         : _M_extents(__other.extents())
+         {
+           __glibcxx_assert(cmp_less_equal(__other.required_span_size(),
+               numeric_limits<index_type>::max()));
+         }
+
+       constexpr mapping&
+       operator=(const mapping&) noexcept = default;
+
+       constexpr const extents_type&
+       extents() const noexcept { return _M_extents; }
+
+       constexpr array<index_type, _S_rank>
+       strides() const noexcept
+       {
+         array<index_type, _S_rank> __ret;
+         if constexpr (_S_rank > 0)
+           __ret[0] = 1;
+         if constexpr (_S_rank > 1)
+           __ret[1] = _M_stride.extent(0);
+         if constexpr (_S_rank > 2)
+           for(size_t __i = 2; __i < _S_rank; ++__i)
+             __ret[__i] = __ret[__i - 1] * _M_extents.extent(__i - 1);
+         return __ret;
+       }
+
+       constexpr index_type
+       required_span_size() const noexcept
+       {
+         if constexpr (_S_rank == 0)
+           return 1;
+         else if (__mdspan::__empty(_M_extents))
+           return 0;
+         else
+           return _M_stride.extent(0) * __mdspan::__rev_prod(_M_extents, 0)
+                  - (_M_stride.extent(0) - _M_extents.extent(0));
+       }
+
+       // _GLIBCXX_RESOLVE_LIB_DEFECTS
+       // 4314. Missing move in mdspan layout mapping::operator()
+       template<__mdspan::__valid_index_type<index_type>... _Indices>
+         requires (sizeof...(_Indices) == _S_rank)
+         constexpr index_type
+         operator()(_Indices... __indices) const noexcept
+         {
+           return __mdspan::__linear_index_leftpad(_M_extents, _M_stride,
+             static_cast<index_type>(std::move(__indices))...);
+         }
+
+       static constexpr bool
+       is_always_unique() noexcept { return true; }
+
+       static constexpr bool
+       is_always_exhaustive() noexcept
+       {
+         if constexpr (_S_rank <= 1)
+           return true;
+         else
+           return extents_type::static_extent(0) != dynamic_extent
+                  && _S_static_stride != dynamic_extent
+                  && extents_type::static_extent(0) == _S_static_stride;
+       }
+
+       static constexpr bool
+       is_always_strided() noexcept { return true; }
+
+       static constexpr bool
+       is_unique() noexcept { return true; }
+
+       constexpr bool
+       is_exhaustive() const noexcept
+       {
+         if constexpr (is_always_exhaustive())
+           return true;
+         else
+           return _M_extents.extent(0) == _M_stride.extent(0);
+       }
+
+       static constexpr bool
+       is_strided() noexcept { return true; }
+
+       constexpr index_type
+       stride(rank_type __r) const noexcept
+       {
+         __glibcxx_assert(__r < _S_rank);
+         if (__r == 0)
+           return 1;
+         else
+           return static_cast<index_type>(
+             static_cast<size_t>(_M_stride.extent(0)) *
+             static_cast<size_t>(__mdspan::__fwd_prod(_M_extents, 1, __r)));
+       }
+
+       template<typename _LeftPaddedMapping>
+         requires(__mdspan::__is_left_padded_mapping<_LeftPaddedMapping>
+                  && _LeftPaddedMapping::extents_type::rank() == _S_rank)
+         friend constexpr bool
+         operator==(const mapping& __self, const _LeftPaddedMapping& __other)
+         noexcept
+         {
+           return __self.extents() == __other.extents()
+             && (_S_rank < 2 || cmp_equal(__self.stride(1),
+                                          __other.stride(1)));
+         }
+
+      private:
+       using _Stride = std::extents<index_type, _S_static_stride>;
+       [[no_unique_address]] _Stride _M_stride;
+       [[no_unique_address]] extents_type _M_extents{};
+      };
+#endif
+
   template<typename _ElementType>
     struct default_accessor
     {
diff --git a/libstdc++-v3/src/c++23/std.cc.in b/libstdc++-v3/src/c++23/std.cc.in
index a217a87330b..8b2f4b24c9c 100644
--- a/libstdc++-v3/src/c++23/std.cc.in
+++ b/libstdc++-v3/src/c++23/std.cc.in
@@ -1869,9 +1869,11 @@ export namespace std
   using std::aligned_accessor;
 #endif
   using std::mdspan;
-  // FIXME layout_left_padded, layout_right_padded, strided_slice,
-  // submdspan_mapping_result, full_extent_t, full_extent, submdspan_extents,
-  // mdsubspan
+#if __glibcxx_padded_layouts
+  using std::layout_left_padded;
+#endif
+  // FIXME layout_right_padded, strided_slice, submdspan_mapping_result,
+  // full_extent_t, full_extent, submdspan_extents, mdsubspan
 }
 #endif
 
diff --git 
a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/class_mandate_neg.cc 
b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/class_mandate_neg.cc
index 7091153daba..edf07c983da 100644
--- a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/class_mandate_neg.cc
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/class_mandate_neg.cc
@@ -46,3 +46,4 @@ auto b6 = B<6, std::layout_stride, std::layout_left>();   // 
{ dg-error "require
 auto b7 = B<7, std::layout_stride, std::layout_stride>(); // { dg-error 
"required from" }
 
 // { dg-prune-output "must be representable as index_type" }
+// { dg-prune-output "static assertion failed" }
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/ctors.cc 
b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/ctors.cc
index 23c0a55dae1..54f79fcd6ec 100644
--- a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/ctors.cc
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/ctors.cc
@@ -6,6 +6,16 @@
 
 constexpr size_t dyn = std::dynamic_extent;
 
+template<typename Layout>
+  constexpr bool
+  is_layout_leftpad = false;
+
+#ifdef __glibcxx_padded_layouts
+template<size_t Pad>
+  constexpr bool
+  is_layout_leftpad<std::layout_left_padded<Pad>> = true;
+#endif
+
 template<typename Mapping, typename IndexType, size_t... Extents>
   constexpr void
   verify(std::extents<IndexType, Extents...> oexts)
@@ -27,7 +37,6 @@ template<typename Mapping, typename OMapping>
        VERIFY(std::cmp_equal(m.stride(i), other.stride(i)));
   }
 
-
 template<typename To, typename From>
   constexpr void
   verify_convertible(From from)
@@ -40,7 +49,10 @@ template<typename To, typename From>
   constexpr void
   verify_nothrow_convertible(From from)
   {
-    static_assert(std::is_nothrow_constructible_v<To, From>);
+    if constexpr (is_layout_leftpad<typename To::layout_type>)
+      static_assert(std::is_constructible_v<To, From>);
+    else
+      static_assert(std::is_nothrow_constructible_v<To, From>);
     verify_convertible<To>(from);
   }
 
@@ -57,7 +69,10 @@ template<typename To, typename From>
   constexpr void
   verify_nothrow_constructible(From from)
   {
-    static_assert(std::is_nothrow_constructible_v<To, From>);
+    if constexpr (is_layout_leftpad<typename To::layout_type>)
+      static_assert(std::is_constructible_v<To, From>);
+    else
+      static_assert(std::is_nothrow_constructible_v<To, From>);
     verify_constructible<To>(from);
   }
 
@@ -196,6 +211,16 @@ namespace from_extents
 // ctor: mapping(mapping<OExtents>)
 namespace from_same_layout
 {
+  template<typename Layout, typename Extents, typename OExtents>
+    constexpr void
+    verify_convertible(OExtents exts)
+    {
+      using Mapping = typename Layout::mapping<Extents>;
+      using OMapping = typename Layout::mapping<OExtents>;
+
+      ::verify_convertible<Mapping>(OMapping(exts));
+    }
+
   template<typename Layout, typename Extents, typename OExtents>
     constexpr void
     verify_nothrow_convertible(OExtents exts)
@@ -223,8 +248,12 @@ namespace from_same_layout
       verify_nothrow_convertible<Layout, std::extents<unsigned int>>(
        std::extents<int>{});
 
-      verify_nothrow_constructible<Layout, std::extents<int>>(
-       std::extents<unsigned int>{});
+      if constexpr (!is_layout_leftpad<Layout>)
+       verify_nothrow_constructible<Layout, std::extents<int>>(
+         std::extents<unsigned int>{});
+      else
+       verify_convertible<Layout, std::extents<int>>(
+         std::extents<unsigned int>{});
 
       assert_not_constructible<
        typename Layout::mapping<std::extents<int>>,
@@ -234,8 +263,12 @@ namespace from_same_layout
        typename Layout::mapping<std::extents<int, 1>>,
        typename Layout::mapping<std::extents<int>>>();
 
-      verify_nothrow_constructible<Layout, std::extents<int, 1>>(
-       std::extents<int, dyn>{1});
+      if constexpr (!is_layout_leftpad<Layout>)
+       verify_nothrow_constructible<Layout, std::extents<int, 1>>(
+         std::extents<int, dyn>{1});
+      else
+       verify_convertible<Layout, std::extents<int, 1>>(
+         std::extents<int, dyn>{1});
 
       verify_nothrow_convertible<Layout, std::extents<int, dyn>>(
        std::extents<int, 1>{});
@@ -247,8 +280,12 @@ namespace from_same_layout
       verify_nothrow_constructible<Layout, std::extents<int, 1, 2>>(
        std::extents<int, dyn, 2>{1});
 
-      verify_nothrow_convertible<Layout, std::extents<int, dyn, 2>>(
-       std::extents<int, 1, 2>{});
+      if constexpr (!is_layout_leftpad<Layout>)
+       verify_nothrow_convertible<Layout, std::extents<int, dyn, 2>>(
+         std::extents<int, 1, 2>{});
+      else
+       verify_nothrow_constructible<Layout, std::extents<int, dyn, 2>>(
+         std::extents<int, 1, 2>{});
       return true;
     }
 
@@ -429,6 +466,12 @@ main()
 {
   test_all<std::layout_left>();
   test_all<std::layout_right>();
+#ifdef __glibcxx_padded_layouts
+  test_all<std::layout_left_padded<0>>();
+  test_all<std::layout_left_padded<1>>();
+  test_all<std::layout_left_padded<2>>();
+  test_all<std::layout_left_padded<dyn>>();
+#endif
 
   from_left_or_right::test_all<std::layout_left, std::layout_right>();
   from_left_or_right::test_all<std::layout_right, std::layout_left>();
diff --git 
a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/debug/padded_neg.cc 
b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/debug/padded_neg.cc
new file mode 100644
index 00000000000..189becfb92f
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/debug/padded_neg.cc
@@ -0,0 +1,22 @@
+// { dg-do run { target c++26 xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <mdspan>
+#include <array>
+
+void
+test_from_strided_mismatching_strides()
+{
+  auto exts = std::extents(3, 5, 7);
+  auto strides = std::array<size_t, 3>{1, 4, 21 /* != 20 */};
+  auto ms = std::layout_stride::mapping(exts, strides);
+  auto m = std::layout_left_padded<2>::mapping<std::dims<3>>(ms);
+  (void) m;
+}
+
+int
+main()
+{
+  test_from_strided_mismatching_strides();
+  return 0;
+};
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/empty.cc 
b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/empty.cc
index 655b9b6d6c3..123e3c61deb 100644
--- a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/empty.cc
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/empty.cc
@@ -35,7 +35,8 @@ test_static_overflow()
 {
   constexpr Int n1 = std::numeric_limits<Int>::max();
   constexpr size_t n2 = std::dynamic_extent - 1;
-  constexpr size_t n = std::cmp_less(n1, n2) ? size_t(n1) : n2;
+  // Allow some room for padding.
+  constexpr size_t n = (std::cmp_less(n1, n2) ? size_t(n1) : n2) - 4;
 
   verify_all(typename Layout::mapping<std::extents<Int, n, n, 0, n, n>>{});
   verify_all(typename Layout::mapping<std::extents<Int, 0, n, n, n>>{});
@@ -73,7 +74,8 @@ test_dynamic_overflow()
 {
   constexpr Int n1 = std::numeric_limits<Int>::max();
   constexpr size_t n2 = std::dynamic_extent - 1;
-  constexpr Int n = std::cmp_less(n1, n2) ? n1 : Int(n2);
+  // Allow some room for padding.
+  constexpr Int n = (std::cmp_less(n1, n2) ? n1 : Int(n2)) - 4;
 
   verify_all(make_mapping<Layout>(
       std::extents<Int, dyn, dyn, 0, dyn, dyn>{n, n, n, n}));
@@ -127,5 +129,11 @@ main()
   static_assert(test_all<std::layout_left>());
   static_assert(test_all<std::layout_right>());
   static_assert(test_all<std::layout_stride>());
+#ifdef __glibcxx_padded_layouts
+  static_assert(test_all<std::layout_left_padded<0>>());
+  static_assert(test_all<std::layout_left_padded<1>>());
+  static_assert(test_all<std::layout_left_padded<2>>());
+  static_assert(test_all<std::layout_left_padded<dyn>>());
+#endif
   return 0;
 }
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/mapping.cc 
b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/mapping.cc
index db15e2a48f3..91d66ea87b8 100644
--- a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/mapping.cc
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/mapping.cc
@@ -370,6 +370,30 @@ template<>
     }
   };
 
+#if __glibcxx_padded_layouts
+template<size_t PaddingValue>
+  struct TestStride2D<std::layout_left_padded<PaddingValue>>
+  {
+    static constexpr void
+    run()
+    {
+      using Layout = std::layout_left_padded<PaddingValue>;
+      typename Layout::mapping<std::extents<int, 3, 5>> m;
+      size_t effective_pad = (PaddingValue == 0 || PaddingValue == dyn)
+       ? size_t(1) : PaddingValue;
+
+      VERIFY(m.stride(0) == 1);
+
+      // The next multiple of PaddingValue, that's greater or equal
+      // to exts.extent(0) is the unique value in the range:
+      //   [exts.extent(0), exts.extent(0) + PaddingValue)
+      // that is divisible by PaddingValue.
+      VERIFY((m.stride(1) % effective_pad) == 0);
+      VERIFY(3 <= m.stride(1) && std::cmp_less(m.stride(1), 3 + 
effective_pad));
+    }
+  };
+#endif
+
 template<typename Layout>
   constexpr void
   test_stride_2d()
@@ -423,6 +447,32 @@ template<>
     }
   };
 
+#if __glibcxx_padded_layouts
+template<size_t PaddingValue>
+  struct TestStride3D<std::layout_left_padded<PaddingValue>>
+  {
+    static constexpr void
+    run()
+    {
+      using Layout = std::layout_left_padded<PaddingValue>;
+      typename Layout::mapping<std::extents<int, 3, 5, 7>> m;
+      size_t effective_pad = (PaddingValue == 0 || PaddingValue == dyn)
+       ? size_t(1) : PaddingValue;
+
+      VERIFY(m.stride(0) == 1);
+
+      // The next multiple of PaddingValue, that's greater or equal
+      // to exts.extent(0) is the unique value in the range:
+      //   [exts.extent(0), exts.extent(0) + PaddingValue)
+      // that is divisible by PaddingValue.
+      VERIFY((m.stride(1) % effective_pad) == 0);
+      VERIFY(3 <= m.stride(1) && std::cmp_less(m.stride(1), 3 + 
effective_pad));
+
+      VERIFY(m.stride(1) * 5 == m.stride(2));
+    }
+  };
+#endif
+
 template<typename Layout>
   constexpr void
   test_stride_3d()
@@ -451,7 +501,8 @@ template<typename Layout>
   test_has_stride_0d()
   {
     using Mapping = typename Layout::mapping<std::extents<int>>;
-    constexpr bool expected = std::is_same_v<Layout, std::layout_stride>;
+    constexpr bool expected = !(std::is_same_v<Layout, std::layout_left>
+       || std::is_same_v<Layout, std::layout_right>);
     static_assert(has_stride<Mapping> == expected);
   }
 
@@ -601,10 +652,29 @@ main()
   test_all<std::layout_left>();
   test_all<std::layout_right>();
   test_all<std::layout_stride>();
+#ifdef __glibcxx_padded_layouts
+  test_all<std::layout_left_padded<0>>();
+  test_all<std::layout_left_padded<1>>();
+  test_all<std::layout_left_padded<2>>();
+  test_all<std::layout_left_padded<5>>();
+  test_all<std::layout_left_padded<dyn>>();
+#endif
 
   test_has_op_eq<std::layout_right, std::layout_left, false>();
   test_has_op_eq<std::layout_right, std::layout_stride, true>();
   test_has_op_eq<std::layout_left, std::layout_stride, true>();
+#ifdef __glibcxx_padded_layouts
+  test_has_op_eq<std::layout_left, std::layout_left_padded<0>, false>();
+  test_has_op_eq<std::layout_left, std::layout_left_padded<6>, false>();
+  test_has_op_eq<std::layout_left, std::layout_left_padded<dyn>, false>();
+  // The next one looks strange, because it's neither. Somehow, the
+  // conversion rules seem to be playing a critical role again.
+  // test_has_op_eq<std::layout_right, std::layout_left_padded<0>, false>();
+
+  test_has_op_eq<std::layout_left_padded<2>, std::layout_left_padded<6>, 
true>();
+  test_has_op_eq<std::layout_left_padded<2>, std::layout_left_padded<dyn>, 
true>();
+#endif
+
   test_has_op_eq_peculiar();
   return 0;
 }
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded.cc 
b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded.cc
new file mode 100644
index 00000000000..a0cd30c39ff
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded.cc
@@ -0,0 +1,611 @@
+// { dg-do run { target c++26 } }
+#include <mdspan>
+
+#include <cstdint>
+#include "../int_like.h"
+#include <testsuite_hooks.h>
+
+#include <iostream>
+
+constexpr size_t dyn = std::dynamic_extent;
+
+constexpr bool
+test_representable_least_multiple()
+{
+  VERIFY(std::__mdspan::__is_representable_least_multiple<uint8_t>(0, 0));
+  VERIFY(std::__mdspan::__is_representable_least_multiple<uint8_t>(1, 0));
+  VERIFY(std::__mdspan::__is_representable_least_multiple<uint8_t>(0, 255));
+  VERIFY(std::__mdspan::__is_representable_least_multiple<uint8_t>(1, 255));
+  VERIFY(std::__mdspan::__is_representable_least_multiple<uint8_t>(2, 2));
+  VERIFY(std::__mdspan::__is_representable_least_multiple<uint8_t>(5, 254));
+  VERIFY(std::__mdspan::__is_representable_least_multiple<uint8_t>(5, 255));
+  VERIFY(!std::__mdspan::__is_representable_least_multiple<uint8_t>(2, 255));
+  VERIFY(!std::__mdspan::__is_representable_least_multiple<uint8_t>(128, 129));
+  return true;
+}
+
+constexpr bool
+test_representable_padded_size()
+{
+  {
+    using E = std::extents<uint8_t, 64, 2>;
+    [[maybe_unused]] std::layout_left_padded<1>::mapping<E> m1;
+  }
+
+  {
+    using E = std::extents<uint8_t, 0, 2>;
+    [[maybe_unused]] std::layout_left_padded<0>::mapping<E> m1;
+    [[maybe_unused]] std::layout_left_padded<1>::mapping<E> m2;
+    [[maybe_unused]] std::layout_left_padded<128>::mapping<E> m3;
+    [[maybe_unused]] std::layout_left_padded<255>::mapping<E> m4;
+  }
+
+  {
+    using E = std::extents<uint8_t, 0, 2>;
+    [[maybe_unused]] std::layout_left_padded<dyn>::mapping<E> m1(E{}, 128);
+    [[maybe_unused]] std::layout_left_padded<dyn>::mapping<E> m2(E{}, 0);
+    [[maybe_unused]] std::layout_left_padded<dyn>::mapping<E> m3(E{}, 1);
+    [[maybe_unused]] std::layout_left_padded<dyn>::mapping<E> m4(E{}, 128);
+  }
+
+  {
+    using E = std::extents<uint8_t, dyn, 2>;
+    [[maybe_unused]] std::layout_left_padded<0>::mapping<E> m1;
+    [[maybe_unused]] std::layout_left_padded<1>::mapping<E> m2;
+    [[maybe_unused]] std::layout_left_padded<128>::mapping<E> m3;
+    [[maybe_unused]] std::layout_left_padded<255>::mapping<E> m4;
+  }
+  return true;
+}
+
+constexpr bool
+test_default_ctor()
+{
+  {
+    using E = std::extents<size_t, 3, 5>;
+
+    std::layout_left_padded<2>::mapping<E> msta;
+    VERIFY(msta.stride(0) == 1);
+    VERIFY(msta.stride(1) == 4);
+
+    std::layout_left_padded<dyn>::mapping<E> mdyn;
+    VERIFY(mdyn.stride(0) == 1);
+    VERIFY(mdyn.stride(1) == 3);
+  }
+
+  {
+    using E = std::extents<size_t, dyn, 5>;
+
+    std::layout_left_padded<2>::mapping<E> msta;
+    VERIFY(msta.stride(0) == 1);
+    VERIFY(msta.stride(1) == 0);
+
+    std::layout_left_padded<dyn>::mapping<E> mdyn;
+    VERIFY(mdyn.stride(0) == 1);
+    VERIFY(mdyn.stride(1) == 0);
+  }
+  return true;
+}
+
+constexpr bool
+test_from_exts()
+{
+  auto exts = std::dextents<size_t, 2>{3, 5};
+
+  std::layout_left_padded<0>::mapping m0_sta(exts);
+  VERIFY(m0_sta.stride(1) == exts.extent(0));
+
+  std::layout_left_padded<1>::mapping m1_sta(exts);
+  VERIFY(m1_sta.stride(1) == exts.extent(0));
+
+  std::layout_left_padded<2>::mapping m2_sta(exts);
+  VERIFY(m2_sta.stride(1) == 4);
+
+  std::layout_left_padded<dyn>::mapping mdyn(exts);
+  VERIFY(mdyn.stride(1) == exts.extent(0));
+  return true;
+}
+
+template<size_t PaddingValue, typename CustomPadType>
+constexpr bool
+test_from_pad()
+{
+  using Layout = std::layout_left_padded<PaddingValue>;
+  auto pad = 3;
+  auto exts = std::dextents<size_t, 3>{pad + 1, 5, 7};
+  typename Layout::mapping m(exts, CustomPadType{pad});
+  VERIFY(std::cmp_equal(m.stride(1), 2*pad));
+  VERIFY(m.extents() == exts);
+  return true;
+}
+
+template<size_t PaddingValue>
+constexpr void
+test_from_pad_all()
+{
+  test_from_pad<PaddingValue, int>();
+  static_assert(test_from_pad<PaddingValue, int>());
+
+  test_from_pad<PaddingValue, IntLike>();
+  test_from_pad<PaddingValue, MutatingInt>();
+  test_from_pad<PaddingValue, RValueInt>();
+
+  using Layout = std::layout_left_padded<PaddingValue>;
+  using Extents = std::dims<3>;
+  using Mapping = Layout::template mapping<Extents>;
+  static_assert(!std::is_constructible_v<Mapping, Extents, ThrowingInt>);
+  static_assert(!std::is_constructible_v<Mapping, Extents, NotIntLike>);
+}
+
+constexpr bool
+is_same_mapping(const auto& lhs, const auto& rhs)
+{
+  if (lhs.extents().rank() != rhs.extents().rank())
+    return false;
+
+  if (lhs.extents() != rhs.extents())
+    return false;
+
+  for (size_t i = 0; i < lhs.extents().rank(); ++i)
+    if (lhs.stride(i) != rhs.stride(i))
+      return false;
+  return true;
+}
+
+enum class ConversionRule
+{
+  Never,
+  Always,
+  Regular
+};
+
+template<typename To, typename From>
+consteval bool
+should_convert(auto rule)
+{
+  if constexpr (rule == ConversionRule::Never)
+    return false;
+  if constexpr (rule == ConversionRule::Always)
+    return true;
+  else
+    return std::is_convertible_v<typename From::extents_type,
+                                typename To::extents_type>;
+}
+
+template<typename To, typename From>
+  constexpr void
+  check_convertible(const From& m, auto conversion_rule)
+  {
+    VERIFY(is_same_mapping(m, To(m)));
+    constexpr bool expected = should_convert<To, From>(conversion_rule);
+    static_assert(std::is_convertible_v<From, To> == expected);
+  }
+
+template<typename LayoutTo, typename Esta, typename Edyn, typename Ewrong>
+constexpr void
+check_convertible_variants(auto msta, auto conversion_rule)
+{
+  using LayoutFrom = decltype(msta)::layout_type;
+  constexpr auto cregular = std::cw<ConversionRule::Regular>;
+
+  // There's a twist when both mappings are left-padded. There's two distinct
+  // ctors: a defaulted copy ctor and a constrained template that enables
+  // construction from left-padded mappings even if their layout_type is
+  // different. The two ctors have different rules regarding conversion.
+
+  if constexpr (!std::same_as<LayoutTo, LayoutFrom>)
+    check_convertible<typename LayoutTo::mapping<Esta>>(msta, conversion_rule);
+  else
+    check_convertible<typename LayoutTo::mapping<Esta>>(msta, cregular);
+
+  check_convertible<typename LayoutTo::mapping<Edyn>>(msta, conversion_rule);
+
+  auto mdyn = typename LayoutFrom::mapping<Edyn>(msta);
+  check_convertible<typename LayoutTo::mapping<Esta>>(mdyn, conversion_rule);
+  if constexpr (!std::same_as<LayoutTo, LayoutFrom>)
+    check_convertible<typename LayoutTo::mapping<Edyn>>(mdyn, conversion_rule);
+  else
+    check_convertible<typename LayoutTo::mapping<Edyn>>(mdyn, cregular);
+
+  static_assert(!std::is_constructible_v<
+      typename LayoutTo::mapping<Esta>, typename LayoutFrom::mapping<Ewrong>>);
+};
+
+template<typename PaddedLayout>
+  constexpr void
+  test_from_left_1d()
+  {
+    using E1 = std::extents<int, 6>;
+    using E2 = std::extents<int, dyn>;
+    using E3 = std::extents<int, 5>;
+    constexpr auto cr = std::cw<ConversionRule::Regular>;
+
+    auto msta = std::layout_left::mapping(E1{});
+    check_convertible_variants<PaddedLayout, E1, E2, E3>(msta, cr);
+  }
+
+template<typename PaddedLayout>
+  constexpr void
+  test_from_left_2d()
+  {
+    using E1 = std::extents<int, 6, 5>;
+    using E2 = std::extents<int, dyn, 5>;
+    using E3 = std::extents<int, 6, 6>;
+    constexpr auto cr = std::cw<ConversionRule::Regular>;
+
+    auto msta = std::layout_left::mapping(E1{});
+    check_convertible_variants<PaddedLayout, E1, E2, E3>(msta, cr);
+  }
+
+constexpr bool
+test_from_left()
+{
+  auto check = []<typename PaddedLayout>(PaddedLayout)
+  {
+    test_from_left_1d<PaddedLayout>();
+    test_from_left_2d<PaddedLayout>();
+  };
+
+  check(std::layout_left_padded<0>{});
+  check(std::layout_left_padded<1>{});
+  check(std::layout_left_padded<2>{});
+  check(std::layout_left_padded<6>{});
+  check(std::layout_left_padded<dyn>{});
+
+  // rank == 1 is more permissive:
+  test_from_left_1d<std::layout_left_padded<5>>();
+  return true;
+}
+
+constexpr bool
+test_from_stride()
+{
+  using E1 = std::extents<size_t, 6, 5, 7>;
+  using E2 = std::dims<3>;
+  using E3 = std::extents<size_t, 6, 6, 7>;
+
+  auto check = []<typename PaddedLayout>(PaddedLayout)
+  {
+    auto exts = E1{};
+    auto strides = std::array<int, 3>{
+      1, exts.extent(0), exts.extent(0) * exts.extent(1)};
+    constexpr auto cr = std::cw<ConversionRule::Never>;
+
+    auto m = std::layout_stride::mapping(exts, strides);
+    check_convertible_variants<PaddedLayout, E1, E2, E3>(m, cr);
+  };
+
+  check(std::layout_left_padded<0>{});
+  check(std::layout_left_padded<1>{});
+  check(std::layout_left_padded<2>{});
+  check(std::layout_left_padded<6>{});
+  check(std::layout_left_padded<dyn>{});
+  return true;
+}
+
+constexpr void
+test_from_leftpad_0d()
+{
+  using E1 = std::extents<uint16_t>;
+  using E2 = std::extents<uint8_t>;
+  using E3 = std::extents<uint8_t, 1>;
+
+  std::layout_left_padded<6>::mapping<E1> msta{E1{}};
+
+  auto check = []<typename To>(To, auto m)
+  {
+    constexpr auto cr = std::cw<ConversionRule::Always>;
+    check_convertible_variants<To, E1, E2, E3>(m, cr);
+  };
+
+  check(std::layout_left_padded<6>{}, msta);
+  check(std::layout_left_padded<dyn>{}, msta);
+}
+
+constexpr void
+test_from_leftpad_1d()
+{
+  using E1 = std::extents<int, 6>;
+  using E2 = std::extents<int, dyn>;
+  using E3 = std::extents<int, 6, 6>;
+
+  std::layout_left_padded<6>::mapping<E1> msta{E1{}};
+  std::layout_left_padded<dyn>::mapping<E1> mdyn{E1{}};
+
+  auto check = []<typename To>(To, auto m)
+  {
+    constexpr auto cr = std::cw<ConversionRule::Always>;
+    check_convertible_variants<To, E1, E2, E3>(m, cr);
+  };
+
+  // Remember, for rank <= 1 the padding_value is irrelevant.
+  check(std::layout_left_padded<6>{}, msta);
+  check(std::layout_left_padded<6>{}, mdyn);
+  check(std::layout_left_padded<dyn>{}, msta);
+  check(std::layout_left_padded<dyn>{}, mdyn);
+}
+
+constexpr void
+test_from_leftpad_2d()
+{
+  using E1 = std::extents<int, 6, 5>;
+  using E2 = std::extents<int, dyn, 5>;
+  using E3 = std::extents<int, 6, 6>;
+
+  std::layout_left_padded<6>::mapping<E1> msta{E1{}};
+  std::layout_left_padded<dyn>::mapping<E1> mdyn{E1{}};
+
+  constexpr auto calways = std::cw<ConversionRule::Always>;
+  constexpr auto cnever = std::cw<ConversionRule::Never>;
+
+  auto check = []<typename To>(To, auto m, auto cr)
+  { check_convertible_variants<To, E1, E2, E3>(m, cr); };
+
+  check(std::layout_left_padded<6>{}, msta, cnever);
+  check(std::layout_left_padded<6>{}, mdyn, cnever);
+  check(std::layout_left_padded<dyn>{}, msta, calways);
+  check(std::layout_left_padded<dyn>{}, mdyn, cnever);
+}
+
+constexpr bool
+test_from_leftpad()
+{
+  test_from_leftpad_0d();
+  test_from_leftpad_1d();
+  test_from_leftpad_2d();
+  return true;
+}
+
+constexpr bool
+test_from_right()
+{
+  using E1 = std::extents<size_t, 3>;
+  using E2 = std::dims<1>;
+  using E3 = std::extents<size_t, 5>;
+  constexpr auto cr = std::cw<ConversionRule::Regular>;
+
+  auto msta = std::layout_right::mapping(E1{});
+
+  // Remember, the padding_value has no effect for rank <= 1.
+  check_convertible_variants<std::layout_left_padded<0>, E1, E2, E3>(msta, cr);
+  check_convertible_variants<std::layout_left_padded<1>, E1, E2, E3>(msta, cr);
+  check_convertible_variants<std::layout_left_padded<2>, E1, E2, E3>(msta, cr);
+  check_convertible_variants<std::layout_left_padded<5>, E1, E2, E3>(msta, cr);
+  check_convertible_variants<std::layout_left_padded<6>, E1, E2, E3>(msta, cr);
+  check_convertible_variants<std::layout_left_padded<dyn>, E1, E2, E3>(msta, 
cr);
+  return true;
+}
+
+constexpr bool
+test_to_left()
+{
+  using E1 = std::extents<int, 6, 5>;
+  using E2 = std::extents<int, dyn, 5>;
+  using E3 = std::extents<int, 6, 6>;
+
+  auto exts_sta = E1{};
+
+  auto check = [](auto msta)
+  {
+    constexpr auto cr = std::cw<ConversionRule::Regular>;
+    check_convertible_variants<std::layout_left, E1, E2, E3>(msta, cr);
+  };
+
+  check(std::layout_left_padded<0>::mapping(exts_sta));
+  check(std::layout_left_padded<2>::mapping(exts_sta));
+  check(std::layout_left_padded<6>::mapping(exts_sta));
+  check(std::layout_left_padded<dyn>::mapping(exts_sta, 0));
+  check(std::layout_left_padded<dyn>::mapping(exts_sta, 2));
+  check(std::layout_left_padded<dyn>::mapping(exts_sta, 6));
+  return true;
+}
+
+constexpr bool
+test_never_to_right()
+{
+  using E1 = std::extents<size_t, 3>;
+  using E2 = std::dims<1>;
+
+  auto mr_sta = std::layout_right::mapping(E1{});
+  auto mlp_sta = std::layout_left_padded<2>::mapping<E1>{mr_sta};
+  static_assert(!std::is_constructible_v<decltype(mr_sta), decltype(mlp_sta)>);
+
+  auto mr_dyn = std::layout_right::mapping(E2{E1{}});
+  auto mlp_dyn = std::layout_left_padded<2>::mapping<E2>{mr_dyn};
+  static_assert(!std::is_constructible_v<decltype(mr_dyn), decltype(mlp_dyn)>);
+  return true;
+}
+
+template<typename Layout>
+constexpr void
+test_strides()
+{
+  auto check = [](auto exts)
+  {
+    auto m = typename Layout::mapping(exts);
+    using IndexType = typename decltype(m)::index_type;
+    constexpr size_t rank = decltype(m)::extents_type::rank();
+
+    auto strides = m.strides();
+    static_assert(std::same_as<decltype(strides), std::array<IndexType, 
rank>>);
+    VERIFY(strides.size() == rank);
+    for (size_t i = 0; i < strides.size(); ++i)
+      VERIFY(strides[i] == m.stride(i));
+  };
+
+  check(std::extents());
+  check(std::extents(0));
+  check(std::extents(3));
+  check(std::extents(3, 5, 7));
+  check(std::extents(3, 0, 7));
+}
+
+constexpr bool
+test_strides_all()
+{
+  test_strides<std::layout_left_padded<0>>();
+  test_strides<std::layout_left_padded<1>>();
+  test_strides<std::layout_left_padded<3>>();
+  test_strides<std::layout_left_padded<dyn>>();
+  return true;
+}
+
+constexpr void
+test_exhaustive_0d()
+{
+  auto exts = std::extents<int>{};
+
+  auto check = [](auto m)
+  {
+    static_assert(m.is_always_exhaustive());
+    VERIFY(m.is_exhaustive());
+  };
+
+  check(std::layout_left_padded<0>::mapping(exts));
+  check(std::layout_left_padded<1>::mapping(exts));
+  check(std::layout_left_padded<2>::mapping(exts));
+  check(std::layout_left_padded<dyn>::mapping(exts));
+}
+
+constexpr void
+test_exhaustive_1d()
+{
+  auto check_dyn_and_sta = []<typename Layout>(Layout)
+  {
+    auto check = [](auto exts)
+    {
+      auto m = typename Layout::mapping(exts);
+      static_assert(m.is_always_exhaustive());
+      VERIFY(m.is_exhaustive());
+    };
+
+    check(std::extents(4));
+    check(std::extents<int, 4>{});
+  };
+
+  check_dyn_and_sta(std::layout_left_padded<1>{});
+  check_dyn_and_sta(std::layout_left_padded<2>{});
+  check_dyn_and_sta(std::layout_left_padded<6>{});
+  check_dyn_and_sta(std::layout_left_padded<dyn>{});
+}
+
+constexpr void
+test_exhaustive_3d()
+{
+  auto exts_dyn = std::extents(4, 5, 7);
+  auto exts_sta = std::extents<int, 4, 5, 7>{};
+  auto ctrue = std::cw<true>;
+  auto cfalse= std::cw<false>;
+
+  auto check = [](auto m, auto static_expected, auto runtime_expected)
+  {
+    static_assert(m.is_always_exhaustive() == static_expected);
+    VERIFY(m.is_exhaustive() == runtime_expected);
+  };
+
+  check(std::layout_left_padded<0>::mapping(exts_sta), ctrue, true);
+  check(std::layout_left_padded<0>::mapping(exts_dyn), cfalse, true);
+  check(std::layout_left_padded<1>::mapping(exts_sta), ctrue, true);
+  check(std::layout_left_padded<1>::mapping(exts_dyn), cfalse, true);
+  check(std::layout_left_padded<2>::mapping(exts_sta), ctrue, true);
+  check(std::layout_left_padded<2>::mapping(exts_dyn), cfalse, true);
+  check(std::layout_left_padded<6>::mapping(exts_dyn), cfalse, false);
+  check(std::layout_left_padded<6>::mapping(exts_sta), cfalse, false);
+  check(std::layout_left_padded<dyn>::mapping(exts_sta), cfalse, true);
+  check(std::layout_left_padded<dyn>::mapping(exts_dyn, 2), cfalse, true);
+  check(std::layout_left_padded<dyn>::mapping(exts_dyn, 3), cfalse, false);
+}
+
+constexpr bool
+test_exhaustive()
+{
+  test_exhaustive_0d();
+  test_exhaustive_1d();
+  test_exhaustive_3d();
+  return true;
+}
+
+constexpr bool
+test_op_eq()
+{
+  // The generic cases are handled in layouts/mapping.cc. Here we check special
+  // cases related to non exhaustive layouts.
+  using E1 = std::extents<size_t, 6, 5, 7>;
+  using E2 = std::dims<3>;
+  using E3 = std::extents<size_t, 7, 5, 7>;
+
+  auto m1 = std::layout_left_padded<0>::mapping(E1{});
+  auto m2 = std::layout_left_padded<7>::mapping(E1{});
+
+  VERIFY(m1 == std::layout_left_padded<0>::mapping(E1{}));
+  VERIFY(m1 == std::layout_left_padded<1>::mapping(E1{}));
+  VERIFY(m1 == std::layout_left_padded<2>::mapping(E1{}));
+  VERIFY(m1 == std::layout_left_padded<6>::mapping(E1{}));
+  VERIFY(m1 != std::layout_left_padded<7>::mapping(E1{}));
+  VERIFY(m1 == std::layout_left_padded<dyn>::mapping(E1{}));
+  VERIFY(m1 != std::layout_left_padded<dyn>::mapping(E1{}, 7));
+
+  VERIFY(m1 == std::layout_left_padded<0>::mapping(E2{E1{}}));
+  VERIFY(m1 == std::layout_left_padded<1>::mapping(E2{E1{}}));
+  VERIFY(m1 == std::layout_left_padded<2>::mapping(E2{E1{}}));
+  VERIFY(m1 == std::layout_left_padded<6>::mapping(E2{E1{}}));
+  VERIFY(m1 != std::layout_left_padded<7>::mapping(E2{E1{}}));
+  VERIFY(m1 == std::layout_left_padded<dyn>::mapping(E2{E1{}}));
+  VERIFY(m1 != std::layout_left_padded<dyn>::mapping(E2{E1{}}, 7));
+
+  VERIFY(m2 == std::layout_left_padded<7>::mapping(E1{}));
+  VERIFY(m2 == std::layout_left_padded<dyn>::mapping(E1{}, 7));
+  VERIFY(m2 == std::layout_left_padded<7>::mapping(E2{E1{}}));
+  VERIFY(m2 == std::layout_left_padded<dyn>::mapping(E2{E1{}}, 7));
+
+  VERIFY(m2 != std::layout_left_padded<7>::mapping(E3{}));
+  VERIFY(m2 != std::layout_left_padded<dyn>::mapping(E3{}, 7));
+  return true;
+}
+
+int
+main()
+{
+  test_representable_least_multiple();
+  static_assert(test_representable_least_multiple());
+
+  test_representable_padded_size();
+  static_assert(test_representable_padded_size());
+
+  test_default_ctor();
+  static_assert(test_default_ctor());
+
+  test_from_exts();
+  static_assert(test_from_exts());
+
+  test_from_left();
+  static_assert(test_from_left());
+
+  test_from_pad_all<dyn>();
+  test_from_pad_all<3>();
+
+  test_from_stride();
+  static_assert(test_from_stride());
+
+  test_from_leftpad();
+  static_assert(test_from_leftpad());
+
+  test_from_right();
+  static_assert(test_from_right());
+
+  test_to_left();
+  static_assert(test_to_left());
+
+  test_never_to_right();
+  static_assert(test_never_to_right());
+
+  test_strides_all();
+  static_assert(test_strides_all());
+
+  test_exhaustive();
+  static_assert(test_exhaustive());
+
+  test_op_eq();
+  static_assert(test_op_eq());
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded_neg.cc 
b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded_neg.cc
new file mode 100644
index 00000000000..72ef55ea87b
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded_neg.cc
@@ -0,0 +1,280 @@
+// { dg-do compile { target c++26 } }
+#include <mdspan>
+
+#include <cstdint>
+
+constexpr size_t dyn = std::dynamic_extent;
+
+constexpr bool
+test_from_extens_representable_sta()
+{
+  using E1 = std::extents<uint8_t, 8, 128>;
+  auto m = std::layout_left_padded<dyn>::mapping(E1{}); // { dg-error "from 
here" }
+  return true;
+}
+static_assert(test_from_extens_representable_sta());
+
+constexpr bool
+test_from_extents_representable_padded_size()
+{
+  using E1 = std::extents<uint8_t, 8, 128>;
+  using E2 = std::dextents<uint8_t, 2>;
+
+  auto m = std::layout_left_padded<dyn>::mapping(E2{E1{}}); // { dg-error 
"expansion of" }
+  return true;
+}
+static_assert(test_from_extents_representable_padded_size());
+
+constexpr bool
+test_from_extents_representable_stride()
+{
+  using E1 = std::extents<uint8_t, dyn, 1>;
+  auto m = std::layout_left_padded<128>::mapping(E1{129}); // { dg-error 
"expansion of" }
+  return true;
+}
+static_assert(test_from_extents_representable_stride());
+
+constexpr bool
+test_from_pad_representable_stride()
+{
+  using E1 = std::dextents<uint8_t, 2>;
+  auto m = std::layout_left_padded<dyn>::mapping(E1{129, 2}, 128); // { 
dg-error "expansion of" }
+  (void) m;
+  return true;
+}
+static_assert(test_from_pad_representable_stride());
+
+constexpr bool
+test_from_pad_representable_padded_size()
+{
+  using E1 = std::dextents<uint8_t, 2>;
+  auto m = std::layout_left_padded<dyn>::mapping(E1{64, 2}, 128); // { 
dg-error "expansion of" }
+  (void) m;
+  return true;
+}
+static_assert(test_from_pad_representable_padded_size());
+
+constexpr bool
+test_from_left()
+{
+  auto exts = std::extents<uint8_t, 6, dyn>{4};
+  auto ml = std::layout_left::mapping(exts);
+
+  using Layout = std::layout_left_padded<4>;
+  Layout::mapping<decltype(exts)> m(ml); // { dg-error "from here" }
+  return true;
+}
+static_assert(test_from_left());
+
+constexpr bool
+test_from_left_bad_runtime_stride()
+{
+  auto exts = std::extents<uint8_t, dyn, dyn>{6, 4};
+  auto ml = std::layout_left::mapping(exts);
+
+  using Layout = std::layout_left_padded<4>;
+  Layout::mapping<decltype(exts)> m(ml); // { dg-error "expansion of" }
+  return true;
+}
+static_assert(test_from_left_bad_runtime_stride());
+
+constexpr bool
+test_from_left_representable_extents()
+{
+  auto exts = std::extents<uint16_t, dyn, dyn>{8, 128};
+  auto ml = std::layout_left::mapping(exts);
+
+  using Layout = std::layout_left_padded<8>;
+  Layout::mapping<std::extents<uint8_t, dyn, dyn>> m(ml); // { dg-error 
"expansion of" }
+  return true;
+}
+static_assert(test_from_left_representable_extents());
+
+template<size_t PaddingValue>
+  constexpr bool
+  test_pad_overflow()
+  {
+    auto exts = std::extents<uint8_t, dyn>{4};
+    auto n = size_t(1) << 9;
+    auto m = typename std::layout_left_padded<PaddingValue>::mapping(exts, n);
+    (void) m;
+    return true;
+  }
+static_assert(test_pad_overflow<1>());   // { dg-error "expansion of" }
+static_assert(test_pad_overflow<dyn>()); // { dg-error "expansion of" }
+
+template<size_t PaddingValue>
+  constexpr bool
+  test_from_pad_negative()
+  {
+    auto exts = std::extents(4);
+    auto m = typename std::layout_left_padded<PaddingValue>::mapping(exts, -1);
+    (void) m;
+    return true;
+  }
+static_assert(test_from_pad_negative<1>());   // { dg-error "expansion of" }
+static_assert(test_from_pad_negative<dyn>()); // { dg-error "expansion of" }
+
+template<size_t Pad>
+  constexpr bool
+  test_static_pad_same()
+  {
+    using Extents = std::extents<int, dyn>;
+    using Mapping = typename std::layout_left_padded<Pad>::mapping<Extents>;
+    auto exts = Extents{4};
+    auto m = Mapping(exts, Pad + 1);      // { dg-error "expansion of" }
+    (void) m;
+    return true;
+  }
+static_assert(test_static_pad_same<1>()); // { dg-error "expansion of" }
+static_assert(test_static_pad_same<3>()); // { dg-error "expansion of" }
+
+constexpr bool
+test_from_stride_wrong_stride0()
+{
+  using Extents = std::dextents<size_t, 2>;
+  auto e = Extents{3, 5};
+  auto ms = std::layout_stride::mapping(e, std::array<int, 2>{2, 7});
+  auto m = std::layout_left_padded<dyn>::mapping<Extents>(ms); // { dg-error 
"expansion of" }
+  (void) m;
+  return true;
+}
+static_assert(test_from_stride_wrong_stride0());
+
+constexpr bool
+test_from_stride_wrong_stride1()
+{
+  using Extents = std::dextents<size_t, 2>;
+  auto e = Extents{3, 5};
+  auto ms = std::layout_stride::mapping(e, std::array<int, 2>{1, 3});
+  auto m = std::layout_left_padded<2>::mapping<Extents>(ms); // { dg-error 
"expansion of" }
+  (void) m;
+  return true;
+}
+static_assert(test_from_stride_wrong_stride1());
+
+constexpr bool
+test_from_stride_wrong_stride2()
+{
+  using Extents = std::dims<3>;
+  auto e = Extents{3, 5, 7};
+  auto ms = std::layout_stride::mapping(e, std::array<int, 3>{1, 4, 21});
+  auto m = std::layout_left_padded<dyn>::mapping<Extents>(ms); // here (not 
implemented)
+  (void) m;
+  return true;
+}
+static_assert(test_from_stride_wrong_stride2());
+
+constexpr bool
+test_from_stride_oversized()
+{
+  auto exts = std::extents<uint16_t, dyn, dyn>{2, 6};
+  auto ms = std::layout_stride::mapping(exts, std::array<uint16_t, 2>{1, 128});
+
+  using Layout = std::layout_left_padded<dyn>;
+  Layout::mapping<std::extents<uint8_t, dyn, dyn>> m(ms); // { dg-error 
"expansion of" }
+  (void) m;
+  return true;
+}
+static_assert(test_from_stride_oversized());
+
+constexpr bool
+test_from_leftpad_dyn()
+{
+  using Extents = std::dextents<size_t, 2>;
+  auto e = Extents{3, 5};
+  auto mlp = std::layout_left_padded<dyn>::mapping(e);
+  auto m = std::layout_left_padded<2>::mapping<Extents>(mlp); // { dg-error 
"expansion of" }
+  (void) m;
+  return true;
+}
+static_assert(test_from_leftpad_dyn());
+
+constexpr bool
+test_from_leftpad_sta()
+{
+  using Extents = std::dextents<size_t, 2>;
+  auto e = Extents{3, 5};
+  auto mlp = std::layout_left_padded<3>::mapping(e);
+  auto m = std::layout_left_padded<2>::mapping<Extents>(mlp); // { dg-error 
"required from" }
+  (void) m;
+  return true;
+}
+static_assert(test_from_leftpad_sta());
+
+constexpr bool
+test_from_leftpad_oversized()
+{
+  using E1 = std::extents<uint16_t, 8, 128>;
+  using E2 = std::extents<uint8_t, dyn, dyn>;
+  auto mlp = std::layout_left_padded<dyn>::mapping<E1>(E1{});
+  auto m = std::layout_left_padded<dyn>::mapping<E2>(mlp); // { dg-error 
"expansion of" }
+  (void) m;
+  return true;
+}
+static_assert(test_from_leftpad_oversized());
+
+template<size_t RunId>
+  constexpr bool
+  test_to_left_not_exhaustive()
+  {
+    using E1 = std::extents<int, 6, 5>;
+    using E2 = std::extents<int, dyn, 5>;
+
+    [[maybe_unused]] auto msta = std::layout_left_padded<7>::mapping(E1{});
+    if constexpr (RunId == 0)
+      {
+       auto m = std::layout_left::mapping<E1>(msta); // { dg-error "required 
from" }
+       (void) m;
+      }
+    if constexpr (RunId == 1)
+      {
+       auto m = std::layout_left::mapping<E2>(msta); // { dg-error "expansion 
of" }
+       (void) m;
+      }
+
+    [[maybe_unused]] auto mdyn = 
std::layout_left_padded<dyn>::mapping(E2{E1{}}, 7);
+    if constexpr (RunId == 2)
+      {
+       auto m = std::layout_left::mapping<E1>(mdyn); // { dg-error "expansion 
of" }
+       (void) m;
+      }
+    if constexpr (RunId == 3)
+      {
+       auto m = std::layout_left::mapping<E2>(mdyn); // { dg-error "expansion 
of" }
+       (void) m;
+      }
+    return true;
+  }
+static_assert(test_to_left_not_exhaustive<0>());
+static_assert(test_to_left_not_exhaustive<1>());
+static_assert(test_to_left_not_exhaustive<2>());
+static_assert(test_to_left_not_exhaustive<3>());
+
+constexpr bool
+test_statically_bad_padding_value()
+{
+  using Extents = std::extents<uint8_t, 129, 2>;
+  std::layout_left_padded<2>::mapping<Extents> m; // { dg-error "required from 
here" }
+  return true;
+}
+static_assert(test_statically_bad_padding_value());
+
+constexpr bool
+test_statically_oversized()
+{
+  using Extents = std::extents<uint8_t, 64, 2>;
+  std::layout_left_padded<128>::mapping<Extents> m; // { dg-error "required 
from here" }
+  return true;
+}
+static_assert(test_statically_oversized());
+
+// { dg-prune-output "padding_value must be representable as index_type" }
+// { dg-prune-output "non-constant condition for static assertion" }
+// { dg-prune-output "called in a constant expression" }
+// { dg-prune-output "no matching function" }
+// { dg-prune-output "static assertion failed" }
+// { dg-prune-output "__glibcxx_assert_fail()" }
+// { dg-prune-output "must be compatible with other.stride" }
+// { dg-prune-output "padding_value is dynamic_extent" }
+// { dg-prune-output "_S_rank <= 1" }
-- 
2.50.1

Reply via email to