On Tue, Mar 10, 2026 at 5:37 PM Jonathan Wakely <[email protected]> wrote:
> Implement the accepted resolution of LWG 4243.
>
> libstdc++-v3/ChangeLog:
>
> * include/std/span (as_bytes, as_writable_bytes): Add
> constraints to disallow volatile elements, as per LWG 4243.
> * testsuite/23_containers/span/lwg4243.cc: New test.
> ---
>
> v2: fix the test - I had the fixes added to the index with 'git add' but
> not committed. This is what I actually tested!
>
> Tested x86_64-linux.
>
> libstdc++-v3/include/std/span | 5 ++-
> .../testsuite/23_containers/span/lwg4243.cc | 31 +++++++++++++++++++
> 2 files changed, 35 insertions(+), 1 deletion(-)
> create mode 100644 libstdc++-v3/testsuite/23_containers/span/lwg4243.cc
>
> diff --git a/libstdc++-v3/include/std/span b/libstdc++-v3/include/std/span
> index 8f525d009ff5..a2f338449c8a 100644
> --- a/libstdc++-v3/include/std/span
> +++ b/libstdc++-v3/include/std/span
> @@ -517,7 +517,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> span(_Range &&)
> -> span<remove_reference_t<ranges::range_reference_t<_Range&>>>;
>
> + // _GLIBCXX_RESOLVE_LIB_DEFECTS
> + // 4243. as_bytes/as_writable_bytes is broken with span<volatile T>
> template<typename _Type, size_t _Extent>
> + requires (!is_volatile_v<_Type>)
> [[nodiscard]]
> inline
> span<const byte, _Extent == dynamic_extent
> @@ -532,7 +535,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> }
>
> template<typename _Type, size_t _Extent>
> - requires (!is_const_v<_Type>)
> + requires (!is_const_v<_Type> && !is_volatile_v<_Type>)
>
These changes still look good. The last time, I just skimmed that we test
various configurations, not actual values.
> inline
> span<byte, _Extent == dynamic_extent
> ? dynamic_extent : _Extent * sizeof(_Type)>
> diff --git a/libstdc++-v3/testsuite/23_containers/span/lwg4243.cc
> b/libstdc++-v3/testsuite/23_containers/span/lwg4243.cc
> new file mode 100644
> index 000000000000..26bb53d8739b
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/23_containers/span/lwg4243.cc
> @@ -0,0 +1,31 @@
> +// { dg-do compile { target c++20 } }
> +
> +// LWG 4243. as_bytes/as_writable_bytes is broken with span<volatile T>
> +
> +#include <span>
> +
> +template<typename ElementType, std::size_t Extent = std::dynamic_extent>
> +concept can_call_as_bytes
> + = requires (std::span<ElementType, Extent> s) { std::as_bytes(s); };
> +
> +static_assert( can_call_as_bytes<int> );
> +static_assert( can_call_as_bytes<int, 10> );
> +static_assert( can_call_as_bytes<const int> );
> +static_assert( can_call_as_bytes<const int, 10> );
> +static_assert( ! can_call_as_bytes<volatile int> );
> +static_assert( ! can_call_as_bytes<volatile int, 10> );
> +static_assert( ! can_call_as_bytes<const volatile int> );
> +static_assert( ! can_call_as_bytes<const volatile int, 10> );
>
The results look correct.
> +
> +template<typename ElementType, std::size_t Extent = std::dynamic_extent>
> +concept can_call_as_writable_bytes
> + = requires (std::span<ElementType, Extent> s) {
> std::as_writable_bytes(s); };
>
Same here.
> +
> +static_assert( can_call_as_writable_bytes<int> );
> +static_assert( can_call_as_writable_bytes<int, 10> );
> +static_assert( ! can_call_as_writable_bytes<const int> );
> +static_assert( ! can_call_as_writable_bytes<const int, 10> );
> +static_assert( ! can_call_as_writable_bytes<volatile int> );
> +static_assert( ! can_call_as_writable_bytes<volatile int, 10> );
> +static_assert( ! can_call_as_writable_bytes<const volatile int> );
> +static_assert( ! can_call_as_writable_bytes<const volatile int, 10> )
--
> 2.53.0
>
>