[libcxx-commits] [libcxx] [libc++][span] LWG4243: `as_bytes`/`as_writable_bytes` is broken with `span<volatile T>` (PR #200993)

via libcxx-commits libcxx-commits at lists.llvm.org
Tue Jun 2 01:21:35 PDT 2026


https://github.com/eiytoq updated https://github.com/llvm/llvm-project/pull/200993

>From 7299bacfea3f648bcd9fd4eb377fae5a91aa2db8 Mon Sep 17 00:00:00 2001
From: eiytoq <eiytoq at outlook.com>
Date: Tue, 2 Jun 2026 11:12:13 +0800
Subject: [PATCH 1/4] fix

---
 libcxx/include/span                           |  4 +-
 .../span.objectrep/as_bytes.pass.cpp          | 10 +--
 .../span.objectrep/as_bytes.verify.cpp        | 70 +++++++++++++++++++
 .../span.objectrep/as_writable_bytes.pass.cpp | 10 +--
 .../as_writable_bytes.verify.cpp              | 59 ++++++++++++++--
 5 files changed, 137 insertions(+), 16 deletions(-)
 create mode 100644 libcxx/test/std/containers/views/views.span/span.objectrep/as_bytes.verify.cpp

diff --git a/libcxx/include/span b/libcxx/include/span
index 230ae3fa2b198..1a484478e19da 100644
--- a/libcxx/include/span
+++ b/libcxx/include/span
@@ -172,6 +172,7 @@ template<class R>
 #  include <__type_traits/is_convertible.h>
 #  include <__type_traits/is_integral.h>
 #  include <__type_traits/is_same.h>
+#  include <__type_traits/is_volatile.h>
 #  include <__type_traits/remove_const.h>
 #  include <__type_traits/remove_cv.h>
 #  include <__type_traits/remove_cvref.h>
@@ -585,12 +586,13 @@ inline constexpr bool ranges::enable_view<span<_ElementType, _Extent>> = true;
 
 //  as_bytes & as_writable_bytes
 template <class _Tp, size_t _Extent>
+  requires(!is_volatile_v<_Tp>)
 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI auto as_bytes(span<_Tp, _Extent> __s) noexcept {
   return __s.__as_bytes();
 }
 
 template <class _Tp, size_t _Extent>
-  requires(!is_const_v<_Tp>)
+  requires(!is_const_v<_Tp> && !is_volatile_v<_Tp>)
 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI auto as_writable_bytes(span<_Tp, _Extent> __s) noexcept {
   return __s.__as_writable_bytes();
 }
diff --git a/libcxx/test/std/containers/views/views.span/span.objectrep/as_bytes.pass.cpp b/libcxx/test/std/containers/views/views.span/span.objectrep/as_bytes.pass.cpp
index 1b62fb94e9ab2..5c5892bc2567c 100644
--- a/libcxx/test/std/containers/views/views.span/span.objectrep/as_bytes.pass.cpp
+++ b/libcxx/test/std/containers/views/views.span/span.objectrep/as_bytes.pass.cpp
@@ -9,12 +9,12 @@
 
 // <span>
 
-// template <class ElementType, size_t Extent>
-//     span<const byte,
-//          Extent == dynamic_extent
-//              ? dynamic_extent
-//              : sizeof(ElementType) * Extent>
+// template<class ElementType, size_t Extent>
+//   span<const byte, Extent == dynamic_extent ? dynamic_extent : sizeof(ElementType) * Extent>
 //     as_bytes(span<ElementType, Extent> s) noexcept;
+//
+// Constraints:
+//   is_volatile_v<ElementType> is false.
 
 #include <cassert>
 #include <cstddef>
diff --git a/libcxx/test/std/containers/views/views.span/span.objectrep/as_bytes.verify.cpp b/libcxx/test/std/containers/views/views.span/span.objectrep/as_bytes.verify.cpp
new file mode 100644
index 0000000000000..cdc830884f23c
--- /dev/null
+++ b/libcxx/test/std/containers/views/views.span/span.objectrep/as_bytes.verify.cpp
@@ -0,0 +1,70 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// <span>
+
+// template<class ElementType, size_t Extent>
+//   span<const byte, Extent == dynamic_extent ? dynamic_extent : sizeof(ElementType) * Extent>
+//     as_bytes(span<ElementType, Extent> s) noexcept;
+//
+// Constraints:
+//   is_volatile_v<ElementType> is false.
+
+#include <span>
+#include <string>
+
+#include "test_macros.h"
+
+struct A {};
+
+void f() {
+  std::as_bytes(std::span<volatile int>());
+  // expected-error at -1 {{no matching function for call to 'as_bytes'}}
+  std::as_bytes(std::span<volatile long>());
+  // expected-error at -1 {{no matching function for call to 'as_bytes'}}
+  std::as_bytes(std::span<volatile double>());
+  // expected-error at -1 {{no matching function for call to 'as_bytes'}}
+  std::as_bytes(std::span<volatile A>());
+  // expected-error at -1 {{no matching function for call to 'as_bytes'}}
+  std::as_bytes(std::span<volatile std::string>());
+  // expected-error at -1 {{no matching function for call to 'as_bytes'}}
+
+  std::as_bytes(std::span<const volatile int>());
+  // expected-error at -1 {{no matching function for call to 'as_bytes'}}
+  std::as_bytes(std::span<const volatile long>());
+  // expected-error at -1 {{no matching function for call to 'as_bytes'}}
+  std::as_bytes(std::span<const volatile double>());
+  // expected-error at -1 {{no matching function for call to 'as_bytes'}}
+  std::as_bytes(std::span<const volatile A>());
+  // expected-error at -1 {{no matching function for call to 'as_bytes'}}
+  std::as_bytes(std::span<const volatile std::string>());
+  // expected-error at -1 {{no matching function for call to 'as_bytes'}}
+
+  std::as_bytes(std::span<volatile int, 0>());
+  // expected-error at -1 {{no matching function for call to 'as_bytes'}}
+  std::as_bytes(std::span<volatile long, 0>());
+  // expected-error at -1 {{no matching function for call to 'as_bytes'}}
+  std::as_bytes(std::span<volatile double, 0>());
+  // expected-error at -1 {{no matching function for call to 'as_bytes'}}
+  std::as_bytes(std::span<volatile A, 0>());
+  // expected-error at -1 {{no matching function for call to 'as_bytes'}}
+  std::as_bytes(std::span<volatile std::string, (std::size_t)0>());
+  // expected-error at -1 {{no matching function for call to 'as_bytes'}}
+
+  std::as_bytes(std::span<const volatile int, 0>());
+  // expected-error at -1 {{no matching function for call to 'as_bytes'}}
+  std::as_bytes(std::span<const volatile long, 0>());
+  // expected-error at -1 {{no matching function for call to 'as_bytes'}}
+  std::as_bytes(std::span<const volatile double, 0>());
+  // expected-error at -1 {{no matching function for call to 'as_bytes'}}
+  std::as_bytes(std::span<const volatile A, 0>());
+  // expected-error at -1 {{no matching function for call to 'as_bytes'}}
+  std::as_bytes(std::span<const volatile std::string, (std::size_t)0>());
+  // expected-error at -1 {{no matching function for call to 'as_bytes'}}
+}
diff --git a/libcxx/test/std/containers/views/views.span/span.objectrep/as_writable_bytes.pass.cpp b/libcxx/test/std/containers/views/views.span/span.objectrep/as_writable_bytes.pass.cpp
index 40c6a581e9acf..be58e1f39f97b 100644
--- a/libcxx/test/std/containers/views/views.span/span.objectrep/as_writable_bytes.pass.cpp
+++ b/libcxx/test/std/containers/views/views.span/span.objectrep/as_writable_bytes.pass.cpp
@@ -9,12 +9,12 @@
 
 // <span>
 
-// template <class ElementType, size_t Extent>
-//     span<byte,
-//          Extent == dynamic_extent
-//              ? dynamic_extent
-//              : sizeof(ElementType) * Extent>
+// template<class ElementType, size_t Extent>
+//   span<byte, Extent == dynamic_extent ? dynamic_extent : sizeof(ElementType) * Extent>
 //     as_writable_bytes(span<ElementType, Extent> s) noexcept;
+//
+// Constraints:
+//   is_const_v<ElementType> is false and is_volatile_v<ElementType> is false.
 
 #include <cassert>
 #include <cstddef>
diff --git a/libcxx/test/std/containers/views/views.span/span.objectrep/as_writable_bytes.verify.cpp b/libcxx/test/std/containers/views/views.span/span.objectrep/as_writable_bytes.verify.cpp
index 9d22641ab2687..12a2229e130a8 100644
--- a/libcxx/test/std/containers/views/views.span/span.objectrep/as_writable_bytes.verify.cpp
+++ b/libcxx/test/std/containers/views/views.span/span.objectrep/as_writable_bytes.verify.cpp
@@ -9,12 +9,12 @@
 
 // <span>
 
-// template <class ElementType, size_t Extent>
-//     span<byte,
-//          Extent == dynamic_extent
-//              ? dynamic_extent
-//              : sizeof(ElementType) * Extent>
+// template<class ElementType, size_t Extent>
+//   span<byte, Extent == dynamic_extent ? dynamic_extent : sizeof(ElementType) * Extent>
 //     as_writable_bytes(span<ElementType, Extent> s) noexcept;
+//
+// Constraints:
+//   is_const_v<ElementType> is false and is_volatile_v<ElementType> is false.
 
 #include <span>
 #include <string>
@@ -37,6 +37,28 @@ void f() {
   std::as_writable_bytes(std::span<const std::string>());
   // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
 
+  std::as_writable_bytes(std::span<volatile int>());
+  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
+  std::as_writable_bytes(std::span<volatile long>());
+  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
+  std::as_writable_bytes(std::span<volatile double>());
+  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
+  std::as_writable_bytes(std::span<volatile A>());
+  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
+  std::as_writable_bytes(std::span<volatile std::string>());
+  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
+
+  std::as_writable_bytes(std::span<const volatile int>());
+  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
+  std::as_writable_bytes(std::span<const volatile long>());
+  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
+  std::as_writable_bytes(std::span<const volatile double>());
+  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
+  std::as_writable_bytes(std::span<const volatile A>());
+  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
+  std::as_writable_bytes(std::span<const volatile std::string>());
+  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
+
   std::as_writable_bytes(std::span<const int, 0>());
   // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
   std::as_writable_bytes(std::span<const long, 0>());
@@ -48,8 +70,35 @@ void f() {
   std::as_writable_bytes(std::span<const std::string, (std::size_t)0>());
   // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
 
+  std::as_writable_bytes(std::span<volatile int, 0>());
+  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
+  std::as_writable_bytes(std::span<volatile long, 0>());
+  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
+  std::as_writable_bytes(std::span<volatile double, 0>());
+  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
+  std::as_writable_bytes(std::span<volatile A, 0>());
+  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
+  std::as_writable_bytes(std::span<volatile std::string, (std::size_t)0>());
+  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
+
+  std::as_writable_bytes(std::span<const volatile int, 0>());
+  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
+  std::as_writable_bytes(std::span<const volatile long, 0>());
+  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
+  std::as_writable_bytes(std::span<const volatile double, 0>());
+  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
+  std::as_writable_bytes(std::span<const volatile A, 0>());
+  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
+  std::as_writable_bytes(std::span<const volatile std::string, (std::size_t)0>());
+  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
+
   std::as_writable_bytes(std::span<const int>(iArr2, 1));
   // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
   std::as_writable_bytes(std::span<const int, 1>(iArr2 + 5, 1));
   // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
+
+  std::as_writable_bytes(std::span<const volatile int>(iArr2, 1));
+  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
+  std::as_writable_bytes(std::span<const volatile int, 1>(iArr2 + 5, 1));
+  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
 }

>From afa1b1c352f22fd917c06dfe0f53938be02e2808 Mon Sep 17 00:00:00 2001
From: eiytoq <eiytoq at outlook.com>
Date: Tue, 2 Jun 2026 11:22:11 +0800
Subject: [PATCH 2/4] upd Cxx2cIssues.csv

---
 libcxx/docs/Status/Cxx2cIssues.csv | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/docs/Status/Cxx2cIssues.csv b/libcxx/docs/Status/Cxx2cIssues.csv
index 20b0b93eff753..6a836c0491bb6 100644
--- a/libcxx/docs/Status/Cxx2cIssues.csv
+++ b/libcxx/docs/Status/Cxx2cIssues.csv
@@ -157,7 +157,7 @@
 "`LWG4137 <https://wg21.link/LWG4137>`__","Fix *Mandates*, *Preconditions*, and *Complexity* elements of [linalg] algorithms","2025-11 (Kona)","","","`#171313 <https://github.com/llvm/llvm-project/issues/171313>`__",""
 "`LWG4166 <https://wg21.link/LWG4166>`__","``concat_view::end()`` should be more constrained in order to support noncopyable iterators","2025-11 (Kona)","|Complete|","23","`#171314 <https://github.com/llvm/llvm-project/issues/171314>`__",""
 "`LWG4230 <https://wg21.link/LWG4230>`__","``simd<complex>::real/imag`` is overconstrained","2025-11 (Kona)","","","`#171316 <https://github.com/llvm/llvm-project/issues/171316>`__",""
-"`LWG4243 <https://wg21.link/LWG4243>`__","``as_bytes``/``as_writable_bytes`` is broken with ``span<volatile T>``","2025-11 (Kona)","","","`#171317 <https://github.com/llvm/llvm-project/issues/171317>`__",""
+"`LWG4243 <https://wg21.link/LWG4243>`__","``as_bytes``/``as_writable_bytes`` is broken with ``span<volatile T>``","2025-11 (Kona)","|Complete|","23","`#171317 <https://github.com/llvm/llvm-project/issues/171317>`__",""
 "`LWG4251 <https://wg21.link/LWG4251>`__","Move assignment for ``indirect`` unnecessarily requires copy construction","2025-11 (Kona)","","","`#171318 <https://github.com/llvm/llvm-project/issues/171318>`__",""
 "`LWG4253 <https://wg21.link/LWG4253>`__","``basic_const_iterator`` should provide ``iterator_type``","2025-11 (Kona)","","","`#171319 <https://github.com/llvm/llvm-project/issues/171319>`__",""
 "`LWG4255 <https://wg21.link/LWG4255>`__","``move_only_function`` constructor should recognize empty ``copyable_function``\s","2025-11 (Kona)","","","`#171320 <https://github.com/llvm/llvm-project/issues/171320>`__",""

>From 6d647fac9e0d49e1049570f363205b20ff1540b5 Mon Sep 17 00:00:00 2001
From: eiytoq <eiytoq at outlook.com>
Date: Tue, 2 Jun 2026 12:24:42 +0800
Subject: [PATCH 3/4] test

---
 .../span.objectrep/as_bytes.pass.cpp          | 29 +++++++++++++++++++
 .../span.objectrep/as_writable_bytes.pass.cpp | 11 +++++++
 2 files changed, 40 insertions(+)

diff --git a/libcxx/test/std/containers/views/views.span/span.objectrep/as_bytes.pass.cpp b/libcxx/test/std/containers/views/views.span/span.objectrep/as_bytes.pass.cpp
index 5c5892bc2567c..f5ab1d46d4c85 100644
--- a/libcxx/test/std/containers/views/views.span/span.objectrep/as_bytes.pass.cpp
+++ b/libcxx/test/std/containers/views/views.span/span.objectrep/as_bytes.pass.cpp
@@ -23,6 +23,11 @@
 
 #include "test_macros.h"
 
+template <class T, std::size_t Extent = std::dynamic_extent>
+constexpr bool hasAsBytes() {
+  return requires(std::span<T, Extent> s) { std::as_bytes(s); };
+}
+
 template <typename Span>
 void testRuntimeSpan(Span sp) {
   ASSERT_NOEXCEPT(std::as_bytes(sp));
@@ -44,6 +49,30 @@ struct A {};
 int iArr2[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
 
 int main(int, char**) {
+  static_assert(hasAsBytes<int>());
+  static_assert(hasAsBytes<long>());
+  static_assert(hasAsBytes<double>());
+  static_assert(hasAsBytes<A>());
+  static_assert(hasAsBytes<std::string>());
+
+  static_assert(hasAsBytes<const int>());
+  static_assert(hasAsBytes<const long>());
+  static_assert(hasAsBytes<const double>());
+  static_assert(hasAsBytes<const A>());
+  static_assert(hasAsBytes<const std::string>());
+
+  static_assert(hasAsBytes<int, 0>());
+  static_assert(hasAsBytes<long, 0>());
+  static_assert(hasAsBytes<double, 0>());
+  static_assert(hasAsBytes<A, 0>());
+  static_assert(hasAsBytes<std::string, 0>());
+
+  static_assert(hasAsBytes<const int, 0>());
+  static_assert(hasAsBytes<const long, 0>());
+  static_assert(hasAsBytes<const double, 0>());
+  static_assert(hasAsBytes<const A, 0>());
+  static_assert(hasAsBytes<const std::string, 0>());
+
   testRuntimeSpan(std::span<int>());
   testRuntimeSpan(std::span<long>());
   testRuntimeSpan(std::span<double>());
diff --git a/libcxx/test/std/containers/views/views.span/span.objectrep/as_writable_bytes.pass.cpp b/libcxx/test/std/containers/views/views.span/span.objectrep/as_writable_bytes.pass.cpp
index be58e1f39f97b..4dd7b5f51af49 100644
--- a/libcxx/test/std/containers/views/views.span/span.objectrep/as_writable_bytes.pass.cpp
+++ b/libcxx/test/std/containers/views/views.span/span.objectrep/as_writable_bytes.pass.cpp
@@ -23,6 +23,11 @@
 
 #include "test_macros.h"
 
+template <class T, std::size_t Extent = std::dynamic_extent>
+constexpr bool hasAsWritableBytes() {
+  return requires(std::span<T, Extent> s) { std::as_writable_bytes(s); };
+}
+
 template <typename Span>
 void testRuntimeSpan(Span sp) {
   ASSERT_NOEXCEPT(std::as_writable_bytes(sp));
@@ -44,6 +49,12 @@ struct A {};
 int iArr2[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
 
 int main(int, char**) {
+  static_assert(hasAsWritableBytes<int>());
+  static_assert(hasAsWritableBytes<long>());
+  static_assert(hasAsWritableBytes<double>());
+  static_assert(hasAsWritableBytes<A>());
+  static_assert(hasAsWritableBytes<std::string>());
+
   testRuntimeSpan(std::span<int>());
   testRuntimeSpan(std::span<long>());
   testRuntimeSpan(std::span<double>());

>From 806c5623d47ce0f5e36506a9cadbcf42e2a494d0 Mon Sep 17 00:00:00 2001
From: eiytoq <eiytoq at outlook.com>
Date: Tue, 2 Jun 2026 16:21:18 +0800
Subject: [PATCH 4/4] test

---
 .../span.objectrep/as_bytes.pass.cpp          |  78 ++++++++-----
 .../span.objectrep/as_bytes.verify.cpp        |  70 ------------
 .../span.objectrep/as_writable_bytes.pass.cpp |  60 ++++++++--
 .../as_writable_bytes.verify.cpp              | 104 ------------------
 4 files changed, 104 insertions(+), 208 deletions(-)
 delete mode 100644 libcxx/test/std/containers/views/views.span/span.objectrep/as_bytes.verify.cpp
 delete mode 100644 libcxx/test/std/containers/views/views.span/span.objectrep/as_writable_bytes.verify.cpp

diff --git a/libcxx/test/std/containers/views/views.span/span.objectrep/as_bytes.pass.cpp b/libcxx/test/std/containers/views/views.span/span.objectrep/as_bytes.pass.cpp
index f5ab1d46d4c85..89eda480df688 100644
--- a/libcxx/test/std/containers/views/views.span/span.objectrep/as_bytes.pass.cpp
+++ b/libcxx/test/std/containers/views/views.span/span.objectrep/as_bytes.pass.cpp
@@ -24,9 +24,7 @@
 #include "test_macros.h"
 
 template <class T, std::size_t Extent = std::dynamic_extent>
-constexpr bool hasAsBytes() {
-  return requires(std::span<T, Extent> s) { std::as_bytes(s); };
-}
+concept hasAsBytes = requires(std::span<T, Extent> s) { std::as_bytes(s); };
 
 template <typename Span>
 void testRuntimeSpan(Span sp) {
@@ -48,30 +46,58 @@ void testRuntimeSpan(Span sp) {
 struct A {};
 int iArr2[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
 
+void test_constraints() {
+  static_assert(hasAsBytes<int>);
+  static_assert(hasAsBytes<long>);
+  static_assert(hasAsBytes<double>);
+  static_assert(hasAsBytes<A>);
+  static_assert(hasAsBytes<std::string>);
+
+  static_assert(hasAsBytes<const int>);
+  static_assert(hasAsBytes<const long>);
+  static_assert(hasAsBytes<const double>);
+  static_assert(hasAsBytes<const A>);
+  static_assert(hasAsBytes<const std::string>);
+
+  static_assert(!hasAsBytes<volatile int>);
+  static_assert(!hasAsBytes<volatile long>);
+  static_assert(!hasAsBytes<volatile double>);
+  static_assert(!hasAsBytes<volatile A>);
+  static_assert(!hasAsBytes<volatile std::string>);
+
+  static_assert(!hasAsBytes<const volatile int>);
+  static_assert(!hasAsBytes<const volatile long>);
+  static_assert(!hasAsBytes<const volatile double>);
+  static_assert(!hasAsBytes<const volatile A>);
+  static_assert(!hasAsBytes<const volatile std::string>);
+
+  static_assert(hasAsBytes<int, 0>);
+  static_assert(hasAsBytes<long, 0>);
+  static_assert(hasAsBytes<double, 0>);
+  static_assert(hasAsBytes<A, 0>);
+  static_assert(hasAsBytes<std::string, 0>);
+
+  static_assert(hasAsBytes<const int, 0>);
+  static_assert(hasAsBytes<const long, 0>);
+  static_assert(hasAsBytes<const double, 0>);
+  static_assert(hasAsBytes<const A, 0>);
+  static_assert(hasAsBytes<const std::string, 0>);
+
+  static_assert(!hasAsBytes<volatile int, 0>);
+  static_assert(!hasAsBytes<volatile long, 0>);
+  static_assert(!hasAsBytes<volatile double, 0>);
+  static_assert(!hasAsBytes<volatile A, 0>);
+  static_assert(!hasAsBytes<volatile std::string, 0>);
+
+  static_assert(!hasAsBytes<const volatile int, 0>);
+  static_assert(!hasAsBytes<const volatile long, 0>);
+  static_assert(!hasAsBytes<const volatile double, 0>);
+  static_assert(!hasAsBytes<const volatile A, 0>);
+  static_assert(!hasAsBytes<const volatile std::string, 0>);
+}
+
 int main(int, char**) {
-  static_assert(hasAsBytes<int>());
-  static_assert(hasAsBytes<long>());
-  static_assert(hasAsBytes<double>());
-  static_assert(hasAsBytes<A>());
-  static_assert(hasAsBytes<std::string>());
-
-  static_assert(hasAsBytes<const int>());
-  static_assert(hasAsBytes<const long>());
-  static_assert(hasAsBytes<const double>());
-  static_assert(hasAsBytes<const A>());
-  static_assert(hasAsBytes<const std::string>());
-
-  static_assert(hasAsBytes<int, 0>());
-  static_assert(hasAsBytes<long, 0>());
-  static_assert(hasAsBytes<double, 0>());
-  static_assert(hasAsBytes<A, 0>());
-  static_assert(hasAsBytes<std::string, 0>());
-
-  static_assert(hasAsBytes<const int, 0>());
-  static_assert(hasAsBytes<const long, 0>());
-  static_assert(hasAsBytes<const double, 0>());
-  static_assert(hasAsBytes<const A, 0>());
-  static_assert(hasAsBytes<const std::string, 0>());
+  test_constraints();
 
   testRuntimeSpan(std::span<int>());
   testRuntimeSpan(std::span<long>());
diff --git a/libcxx/test/std/containers/views/views.span/span.objectrep/as_bytes.verify.cpp b/libcxx/test/std/containers/views/views.span/span.objectrep/as_bytes.verify.cpp
deleted file mode 100644
index cdc830884f23c..0000000000000
--- a/libcxx/test/std/containers/views/views.span/span.objectrep/as_bytes.verify.cpp
+++ /dev/null
@@ -1,70 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// 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
-
-// <span>
-
-// template<class ElementType, size_t Extent>
-//   span<const byte, Extent == dynamic_extent ? dynamic_extent : sizeof(ElementType) * Extent>
-//     as_bytes(span<ElementType, Extent> s) noexcept;
-//
-// Constraints:
-//   is_volatile_v<ElementType> is false.
-
-#include <span>
-#include <string>
-
-#include "test_macros.h"
-
-struct A {};
-
-void f() {
-  std::as_bytes(std::span<volatile int>());
-  // expected-error at -1 {{no matching function for call to 'as_bytes'}}
-  std::as_bytes(std::span<volatile long>());
-  // expected-error at -1 {{no matching function for call to 'as_bytes'}}
-  std::as_bytes(std::span<volatile double>());
-  // expected-error at -1 {{no matching function for call to 'as_bytes'}}
-  std::as_bytes(std::span<volatile A>());
-  // expected-error at -1 {{no matching function for call to 'as_bytes'}}
-  std::as_bytes(std::span<volatile std::string>());
-  // expected-error at -1 {{no matching function for call to 'as_bytes'}}
-
-  std::as_bytes(std::span<const volatile int>());
-  // expected-error at -1 {{no matching function for call to 'as_bytes'}}
-  std::as_bytes(std::span<const volatile long>());
-  // expected-error at -1 {{no matching function for call to 'as_bytes'}}
-  std::as_bytes(std::span<const volatile double>());
-  // expected-error at -1 {{no matching function for call to 'as_bytes'}}
-  std::as_bytes(std::span<const volatile A>());
-  // expected-error at -1 {{no matching function for call to 'as_bytes'}}
-  std::as_bytes(std::span<const volatile std::string>());
-  // expected-error at -1 {{no matching function for call to 'as_bytes'}}
-
-  std::as_bytes(std::span<volatile int, 0>());
-  // expected-error at -1 {{no matching function for call to 'as_bytes'}}
-  std::as_bytes(std::span<volatile long, 0>());
-  // expected-error at -1 {{no matching function for call to 'as_bytes'}}
-  std::as_bytes(std::span<volatile double, 0>());
-  // expected-error at -1 {{no matching function for call to 'as_bytes'}}
-  std::as_bytes(std::span<volatile A, 0>());
-  // expected-error at -1 {{no matching function for call to 'as_bytes'}}
-  std::as_bytes(std::span<volatile std::string, (std::size_t)0>());
-  // expected-error at -1 {{no matching function for call to 'as_bytes'}}
-
-  std::as_bytes(std::span<const volatile int, 0>());
-  // expected-error at -1 {{no matching function for call to 'as_bytes'}}
-  std::as_bytes(std::span<const volatile long, 0>());
-  // expected-error at -1 {{no matching function for call to 'as_bytes'}}
-  std::as_bytes(std::span<const volatile double, 0>());
-  // expected-error at -1 {{no matching function for call to 'as_bytes'}}
-  std::as_bytes(std::span<const volatile A, 0>());
-  // expected-error at -1 {{no matching function for call to 'as_bytes'}}
-  std::as_bytes(std::span<const volatile std::string, (std::size_t)0>());
-  // expected-error at -1 {{no matching function for call to 'as_bytes'}}
-}
diff --git a/libcxx/test/std/containers/views/views.span/span.objectrep/as_writable_bytes.pass.cpp b/libcxx/test/std/containers/views/views.span/span.objectrep/as_writable_bytes.pass.cpp
index 4dd7b5f51af49..3ad7cf754049a 100644
--- a/libcxx/test/std/containers/views/views.span/span.objectrep/as_writable_bytes.pass.cpp
+++ b/libcxx/test/std/containers/views/views.span/span.objectrep/as_writable_bytes.pass.cpp
@@ -24,9 +24,7 @@
 #include "test_macros.h"
 
 template <class T, std::size_t Extent = std::dynamic_extent>
-constexpr bool hasAsWritableBytes() {
-  return requires(std::span<T, Extent> s) { std::as_writable_bytes(s); };
-}
+concept hasAsWritableBytes = requires(std::span<T, Extent> s) { std::as_writable_bytes(s); };
 
 template <typename Span>
 void testRuntimeSpan(Span sp) {
@@ -48,12 +46,58 @@ void testRuntimeSpan(Span sp) {
 struct A {};
 int iArr2[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
 
+void test_constraints() {
+  static_assert(hasAsWritableBytes<int>);
+  static_assert(hasAsWritableBytes<long>);
+  static_assert(hasAsWritableBytes<double>);
+  static_assert(hasAsWritableBytes<A>);
+  static_assert(hasAsWritableBytes<std::string>);
+
+  static_assert(!hasAsWritableBytes<const int>);
+  static_assert(!hasAsWritableBytes<const long>);
+  static_assert(!hasAsWritableBytes<const double>);
+  static_assert(!hasAsWritableBytes<const A>);
+  static_assert(!hasAsWritableBytes<const std::string>);
+
+  static_assert(!hasAsWritableBytes<volatile int>);
+  static_assert(!hasAsWritableBytes<volatile long>);
+  static_assert(!hasAsWritableBytes<volatile double>);
+  static_assert(!hasAsWritableBytes<volatile A>);
+  static_assert(!hasAsWritableBytes<volatile std::string>);
+
+  static_assert(!hasAsWritableBytes<const volatile int>);
+  static_assert(!hasAsWritableBytes<const volatile long>);
+  static_assert(!hasAsWritableBytes<const volatile double>);
+  static_assert(!hasAsWritableBytes<const volatile A>);
+  static_assert(!hasAsWritableBytes<const volatile std::string>);
+
+  static_assert(hasAsWritableBytes<int, 0>);
+  static_assert(hasAsWritableBytes<long, 0>);
+  static_assert(hasAsWritableBytes<double, 0>);
+  static_assert(hasAsWritableBytes<A, 0>);
+  static_assert(hasAsWritableBytes<std::string, 0>);
+
+  static_assert(!hasAsWritableBytes<const int, 0>);
+  static_assert(!hasAsWritableBytes<const long, 0>);
+  static_assert(!hasAsWritableBytes<const double, 0>);
+  static_assert(!hasAsWritableBytes<const A, 0>);
+  static_assert(!hasAsWritableBytes<const std::string, 0>);
+
+  static_assert(!hasAsWritableBytes<volatile int, 0>);
+  static_assert(!hasAsWritableBytes<volatile long, 0>);
+  static_assert(!hasAsWritableBytes<volatile double, 0>);
+  static_assert(!hasAsWritableBytes<volatile A, 0>);
+  static_assert(!hasAsWritableBytes<volatile std::string, 0>);
+
+  static_assert(!hasAsWritableBytes<const volatile int, 0>);
+  static_assert(!hasAsWritableBytes<const volatile long, 0>);
+  static_assert(!hasAsWritableBytes<const volatile double, 0>);
+  static_assert(!hasAsWritableBytes<const volatile A, 0>);
+  static_assert(!hasAsWritableBytes<const volatile std::string, 0>);
+}
+
 int main(int, char**) {
-  static_assert(hasAsWritableBytes<int>());
-  static_assert(hasAsWritableBytes<long>());
-  static_assert(hasAsWritableBytes<double>());
-  static_assert(hasAsWritableBytes<A>());
-  static_assert(hasAsWritableBytes<std::string>());
+  test_constraints();
 
   testRuntimeSpan(std::span<int>());
   testRuntimeSpan(std::span<long>());
diff --git a/libcxx/test/std/containers/views/views.span/span.objectrep/as_writable_bytes.verify.cpp b/libcxx/test/std/containers/views/views.span/span.objectrep/as_writable_bytes.verify.cpp
deleted file mode 100644
index 12a2229e130a8..0000000000000
--- a/libcxx/test/std/containers/views/views.span/span.objectrep/as_writable_bytes.verify.cpp
+++ /dev/null
@@ -1,104 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// 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
-
-// <span>
-
-// template<class ElementType, size_t Extent>
-//   span<byte, Extent == dynamic_extent ? dynamic_extent : sizeof(ElementType) * Extent>
-//     as_writable_bytes(span<ElementType, Extent> s) noexcept;
-//
-// Constraints:
-//   is_const_v<ElementType> is false and is_volatile_v<ElementType> is false.
-
-#include <span>
-#include <string>
-
-#include "test_macros.h"
-
-const int iArr2[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
-
-struct A {};
-
-void f() {
-  std::as_writable_bytes(std::span<const int>());
-  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
-  std::as_writable_bytes(std::span<const long>());
-  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
-  std::as_writable_bytes(std::span<const double>());
-  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
-  std::as_writable_bytes(std::span<const A>());
-  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
-  std::as_writable_bytes(std::span<const std::string>());
-  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
-
-  std::as_writable_bytes(std::span<volatile int>());
-  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
-  std::as_writable_bytes(std::span<volatile long>());
-  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
-  std::as_writable_bytes(std::span<volatile double>());
-  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
-  std::as_writable_bytes(std::span<volatile A>());
-  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
-  std::as_writable_bytes(std::span<volatile std::string>());
-  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
-
-  std::as_writable_bytes(std::span<const volatile int>());
-  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
-  std::as_writable_bytes(std::span<const volatile long>());
-  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
-  std::as_writable_bytes(std::span<const volatile double>());
-  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
-  std::as_writable_bytes(std::span<const volatile A>());
-  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
-  std::as_writable_bytes(std::span<const volatile std::string>());
-  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
-
-  std::as_writable_bytes(std::span<const int, 0>());
-  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
-  std::as_writable_bytes(std::span<const long, 0>());
-  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
-  std::as_writable_bytes(std::span<const double, 0>());
-  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
-  std::as_writable_bytes(std::span<const A, 0>());
-  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
-  std::as_writable_bytes(std::span<const std::string, (std::size_t)0>());
-  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
-
-  std::as_writable_bytes(std::span<volatile int, 0>());
-  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
-  std::as_writable_bytes(std::span<volatile long, 0>());
-  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
-  std::as_writable_bytes(std::span<volatile double, 0>());
-  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
-  std::as_writable_bytes(std::span<volatile A, 0>());
-  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
-  std::as_writable_bytes(std::span<volatile std::string, (std::size_t)0>());
-  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
-
-  std::as_writable_bytes(std::span<const volatile int, 0>());
-  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
-  std::as_writable_bytes(std::span<const volatile long, 0>());
-  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
-  std::as_writable_bytes(std::span<const volatile double, 0>());
-  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
-  std::as_writable_bytes(std::span<const volatile A, 0>());
-  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
-  std::as_writable_bytes(std::span<const volatile std::string, (std::size_t)0>());
-  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
-
-  std::as_writable_bytes(std::span<const int>(iArr2, 1));
-  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
-  std::as_writable_bytes(std::span<const int, 1>(iArr2 + 5, 1));
-  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
-
-  std::as_writable_bytes(std::span<const volatile int>(iArr2, 1));
-  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
-  std::as_writable_bytes(std::span<const volatile int, 1>(iArr2 + 5, 1));
-  // expected-error at -1 {{no matching function for call to 'as_writable_bytes'}}
-}



More information about the libcxx-commits mailing list