On Thu, 18 Dec 2025 at 10:07, Luc Grosheintz <[email protected]> wrote:
>
>
>
> On 12/17/25 22:11, Jonathan Wakely wrote:
> > On Wed, 17 Dec 2025 at 21:10, Jonathan Wakely <[email protected]> wrote:
> >>
> >> On Wed, 17 Dec 2025 at 20:52, Luc Grosheintz <[email protected]>
> >> wrote:
> >>>
> >>> On Solaris, same_as<int8_t, char> is true. Therefore, int8_t isn't a
> >>> valid IndexType, because char is neither a signed nor an unsigned
> >>> integer type.
> >>>
> >>> This commit fixes the tests by avoiding int8_t (and uint8_t) by using
> >>> 'signed char' (and 'unsigned char').
> >>>
> >>> PR libstdc++/123176
> >>>
> >>> libstdc++-v3/ChangeLog:
> >>>
> >>> *
> >>> testsuite/23_containers/mdspan/submdspan/submdspan_canonicalize_slices_neg.cc:
> >>> Avoid
> >>> int8_t with signed char.
> >>>
> >>> Signed-off-by: Luc Grosheintz <[email protected]>
> >>> ---
> >>>
> >>> This fix is purely based on a theoretical understanding of the compiler
> >>> messages reported in the bug report. Unfortunately, I don't have access
> >>> to a Solaris machine; and therefore am not able to test on Solaris. I
> >>> have tested on linux-x86_64.
> >>>
> >>> I've CC'ed Rainer Orth who reported the issue, maybe Rainer's willing
> >>> and has time to test it on Solaris.
> >>>
> >>> .../submdspan_canonicalize_slices_neg.cc | 32 +++++++++++--------
> >>> 1 file changed, 18 insertions(+), 14 deletions(-)
> >>>
> >>> diff --git
> >>> a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_canonicalize_slices_neg.cc
> >>>
> >>> b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_canonicalize_slices_neg.cc
> >>> index 94bca183aa3..0098547d750 100644
> >>> ---
> >>> a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_canonicalize_slices_neg.cc
> >>> +++
> >>> b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_canonicalize_slices_neg.cc
> >>> @@ -8,9 +8,12 @@ constexpr size_t dyn = std::dynamic_extent;
> >>> constexpr auto dyn_empty = std::extents<int32_t, dyn>{0};
> >>> constexpr auto sta_empty = std::extents<uint32_t, 0>{};
> >>>
> >>> -constexpr auto dyn_uexts = std::extents<uint8_t, dyn>{5};
> >>> +// On Solaris same_as<int8_t, char> is true. Therefore, int8_t is not a
> >>> signed
> >>> +// or unsigned integer type and hence not a valid IndexType. We'll use
> >>> signed
> >>> +// char and unsigned char for int8_t throughout.
> >>> +constexpr auto dyn_uexts = std::extents<unsigned char, dyn>{5};
> >>> constexpr auto sta_uexts = std::extents<uint16_t, 5>{5};
> >>> -constexpr auto dyn_sexts = std::extents<int8_t, dyn>{5};
> >>> +constexpr auto dyn_sexts = std::extents<signed char, dyn>{5};
> >>> constexpr auto sta_sexts = std::extents<int16_t, 5>{5};
> >>>
> >>> constexpr bool
> >>> @@ -69,7 +72,7 @@ template<typename Offset, typename Extent, typename
> >>> Stride, typename Extents>
> >>> return true;
> >>> }
> >>>
> >>> -constexpr auto i8_1 = int8_t{1};
> >>> +constexpr auto i8_1 = (signed char){1};
> >>>
> >>> static_assert(test_under2(-i8_1, 0, 1, dyn_uexts)); // { dg-error
> >>> "expansion of" }
> >>> static_assert(test_under2(0, -i8_1, 1, dyn_uexts)); // { dg-error
> >>> "expansion of" }
> >>> @@ -84,7 +87,7 @@ static_assert(test_under2(-i8_1, 0, 1, sta_sexts));
> >>> // { dg-error "expansion o
> >>> static_assert(test_under2(0, -i8_1, 1, sta_sexts)); // { dg-error
> >>> "expansion of" }
> >>> static_assert(test_under2(0, 1, -i8_1, sta_sexts)); // { dg-error
> >>> "expansion of" }
> >>>
> >>> -constexpr auto c_i8_m1 = std::cw<int8_t{-1}>;
> >>> +constexpr auto c_i8_m1 = std::cw<(signed char){-1}>;
> >>> constexpr auto c_i16_m1 = std::cw<int16_t{-1}>;
> >>> constexpr auto c_i64_m1 = std::cw<int64_t{-1}>;
> >>>
> >>> @@ -109,8 +112,8 @@ template<typename Offset, typename Extent, typename
> >>> Stride, typename Extents>
> >>> return true;
> >>> }
> >>>
> >>> -constexpr auto i8_6 = int8_t{6};
> >>> -constexpr auto c_i8_6 = std::cw<int8_t{6}>;
> >>> +constexpr auto i8_6 = (signed char){6};
> >>> +constexpr auto c_i8_6 = std::cw<(signed char){6}>;
> >>
> >> Actually all these braces should be removed, so just:
> >>
> >> (signed char){6} not (signed char){6}, otherwise it's a C99 compound
> >> literal, which is not valid in C++ and will warn with -pedantic.
> >
> > Gah, pasted the wrong thing. I mean:
> > (signed char)6 not (signed char){6}
> >
>
> I had to remove `-pedantic` due to:
>
> libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints.cc:20: warning:
> ISO C++ does not support '__int128' for 'type name' [-Wpedantic]
>
> --------------------
>
> Regarding your comment about fixing `int8_t` on Solaris. If we only fix the
> testsuite, then code that uses
>
> std::extents<int8_t>
>
> will fail to compile on Solaris. On the one hand: that's correct, because
> int8_t on Solaris isn't a signed or unsigned integer type. On the other
> hand it's wrong because the standard states that int8_t is.
>
> What we could consider is implementing the requirement that something
> is a valid IndexType in mdspan as:
>
> __is_signed_or_unsigned_integer<_IndexType>::value
> || same_as<_IndexType, int8_t>
> || same_as<_IndexType, uint8_t>;
>
> we'd need to be more careful, because we can't blindly assume that
> int8_t exists.
It always does for GCC, because all supported targets have CHAR_BIT == 8.
> The idea is that I can't remember anything in the
> standard that requires us to fail if index_type == char and I can't
> remember anything that would make 'char' problematic. Hence, we could
> be lenient and allow char or int8_t.
I like this, as it only affects the "is valid IndexType" check, and
doesn't have any wider repercussions elsewhere. There are some places
where we really want to treat plain 'char' as a character and *not* an
integer, but for mdspan it's harmless to allow char here.
>
> I don't know if this is a good idea.
>
> >
> >>
> >>
> >>> constexpr auto c2 = std::cw<2>;
> >>> constexpr auto c4 = std::cw<4>;
> >>>
> >>> @@ -155,21 +158,22 @@ static_assert(test_over2(c2, c4, 1, sta_sexts));
> >>> // { dg-error "expansion of
> >>> constexpr bool
> >>> test_overflow1(auto o, auto e)
> >>> {
> >>> - auto exts = std::extents<uint8_t, dyn>{255};
> >>> + auto exts = std::extents<unsigned char,
> >>> dyn>{std::numeric_limits<unsigned char>::max()};
> >>> auto slice = std::strided_slice{o, e, 1};
> >>> std::submdspan_canonicalize_slices(exts, slice);
> >>> return true;
> >>> }
> >>>
> >>> -static_assert(test_overflow1(128, 128)); // {
> >>> dg-error "expansion of" }
> >>> -static_assert(test_overflow1(std::cw<128>, 128)); // {
> >>> dg-error "expansion of" }
> >>> -static_assert(test_overflow1(128, std::cw<128>)); // {
> >>> dg-error "expansion of" }
> >>> -static_assert(test_overflow1(std::cw<128>, std::cw<128>)); // {
> >>> dg-error "expansion of" }
> >>> +constexpr int half_max = std::numeric_limits<unsigned char>::max() / 2 +
> >>> 1;
> >>> +static_assert(test_overflow1(half_max, half_max)); //
> >>> { dg-error "expansion of" }
> >>> +static_assert(test_overflow1(std::cw<half_max>, half_max)); //
> >>> { dg-error "expansion of" }
> >>> +static_assert(test_overflow1(half_max, std::cw<half_max>)); //
> >>> { dg-error "expansion of" }
> >>> +static_assert(test_overflow1(std::cw<half_max>, std::cw<half_max>)); //
> >>> { dg-error "expansion of" }
> >>>
> >>> constexpr bool
> >>> test_overflow2(auto b, auto e)
> >>> {
> >>> - auto exts = std::extents<uint8_t, dyn>{255};
> >>> + auto exts = std::extents<unsigned char,
> >>> dyn>{std::numeric_limits<unsigned char>::max()};
> >>> auto slice = std::pair{b, e};
> >>> std::submdspan_canonicalize_slices(exts, slice);
> >>> return true;
> >>> @@ -180,8 +184,8 @@ static_assert(test_overflow2(std::cw<5>, 4));
> >>> // { dg-error "expansion
> >>> static_assert(test_overflow2(5, std::cw<4>)); // { dg-error
> >>> "expansion of" }
> >>> static_assert(test_overflow2(std::cw<5>, std::cw<4>)); // { dg-error
> >>> "expansion of" }
> >>>
> >>> -constexpr auto u8_4 = uint8_t{4};
> >>> -constexpr auto u8_5 = uint8_t{5};
> >>> +constexpr auto u8_4 = (unsigned char){4};
> >>> +constexpr auto u8_5 = (unsigned char){5};
> >>> static_assert(test_overflow2(u8_5, u8_4)); // {
> >>> dg-error "expansion of" }
> >>> static_assert(test_overflow2(std::cw<u8_5>, u8_4)); // {
> >>> dg-error "expansion of" }
> >>> static_assert(test_overflow2(u8_5, std::cw<u8_4>)); // {
> >>> dg-error "expansion of" }
> >>> --
> >>> 2.52.0
> >>>
>