Skip to content

Commit e202047

Browse files
authored
[libc++][span] LWG4243: as_bytes/as_writable_bytes is broken with span<volatile T> (llvm#200993)
Closes llvm#171317
1 parent 74bf9b5 commit e202047

5 files changed

Lines changed: 124 additions & 67 deletions

File tree

libcxx/docs/Status/Cxx2cIssues.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@
157157
"`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>`__",""
158158
"`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>`__",""
159159
"`LWG4230 <https://wg21.link/LWG4230>`__","``simd<complex>::real/imag`` is overconstrained","2025-11 (Kona)","","","`#171316 <https://github.com/llvm/llvm-project/issues/171316>`__",""
160-
"`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>`__",""
160+
"`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>`__",""
161161
"`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>`__",""
162162
"`LWG4253 <https://wg21.link/LWG4253>`__","``basic_const_iterator`` should provide ``iterator_type``","2025-11 (Kona)","","","`#171319 <https://github.com/llvm/llvm-project/issues/171319>`__",""
163163
"`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>`__",""

libcxx/include/span

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ template<class R>
172172
# include <__type_traits/is_convertible.h>
173173
# include <__type_traits/is_integral.h>
174174
# include <__type_traits/is_same.h>
175+
# include <__type_traits/is_volatile.h>
175176
# include <__type_traits/remove_const.h>
176177
# include <__type_traits/remove_cv.h>
177178
# include <__type_traits/remove_cvref.h>
@@ -585,12 +586,13 @@ inline constexpr bool ranges::enable_view<span<_ElementType, _Extent>> = true;
585586

586587
// as_bytes & as_writable_bytes
587588
template <class _Tp, size_t _Extent>
589+
requires(!is_volatile_v<_Tp>)
588590
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI auto as_bytes(span<_Tp, _Extent> __s) noexcept {
589591
return __s.__as_bytes();
590592
}
591593

592594
template <class _Tp, size_t _Extent>
593-
requires(!is_const_v<_Tp>)
595+
requires(!is_const_v<_Tp> && !is_volatile_v<_Tp>)
594596
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI auto as_writable_bytes(span<_Tp, _Extent> __s) noexcept {
595597
return __s.__as_writable_bytes();
596598
}

libcxx/test/std/containers/views/views.span/span.objectrep/as_bytes.pass.cpp

Lines changed: 60 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@
99

1010
// <span>
1111

12-
// template <class ElementType, size_t Extent>
13-
// span<const byte,
14-
// Extent == dynamic_extent
15-
// ? dynamic_extent
16-
// : sizeof(ElementType) * Extent>
12+
// template<class ElementType, size_t Extent>
13+
// span<const byte, Extent == dynamic_extent ? dynamic_extent : sizeof(ElementType) * Extent>
1714
// as_bytes(span<ElementType, Extent> s) noexcept;
15+
//
16+
// Constraints:
17+
// is_volatile_v<ElementType> is false.
1818

1919
#include <cassert>
2020
#include <cstddef>
@@ -23,6 +23,9 @@
2323

2424
#include "test_macros.h"
2525

26+
template <class T, std::size_t Extent = std::dynamic_extent>
27+
concept hasAsBytes = requires(std::span<T, Extent> s) { std::as_bytes(s); };
28+
2629
template <typename Span>
2730
void testRuntimeSpan(Span sp) {
2831
ASSERT_NOEXCEPT(std::as_bytes(sp));
@@ -43,7 +46,59 @@ void testRuntimeSpan(Span sp) {
4346
struct A {};
4447
int iArr2[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
4548

49+
void test_constraints() {
50+
static_assert(hasAsBytes<int>);
51+
static_assert(hasAsBytes<long>);
52+
static_assert(hasAsBytes<double>);
53+
static_assert(hasAsBytes<A>);
54+
static_assert(hasAsBytes<std::string>);
55+
56+
static_assert(hasAsBytes<const int>);
57+
static_assert(hasAsBytes<const long>);
58+
static_assert(hasAsBytes<const double>);
59+
static_assert(hasAsBytes<const A>);
60+
static_assert(hasAsBytes<const std::string>);
61+
62+
static_assert(!hasAsBytes<volatile int>);
63+
static_assert(!hasAsBytes<volatile long>);
64+
static_assert(!hasAsBytes<volatile double>);
65+
static_assert(!hasAsBytes<volatile A>);
66+
static_assert(!hasAsBytes<volatile std::string>);
67+
68+
static_assert(!hasAsBytes<const volatile int>);
69+
static_assert(!hasAsBytes<const volatile long>);
70+
static_assert(!hasAsBytes<const volatile double>);
71+
static_assert(!hasAsBytes<const volatile A>);
72+
static_assert(!hasAsBytes<const volatile std::string>);
73+
74+
static_assert(hasAsBytes<int, 0>);
75+
static_assert(hasAsBytes<long, 0>);
76+
static_assert(hasAsBytes<double, 0>);
77+
static_assert(hasAsBytes<A, 0>);
78+
static_assert(hasAsBytes<std::string, 0>);
79+
80+
static_assert(hasAsBytes<const int, 0>);
81+
static_assert(hasAsBytes<const long, 0>);
82+
static_assert(hasAsBytes<const double, 0>);
83+
static_assert(hasAsBytes<const A, 0>);
84+
static_assert(hasAsBytes<const std::string, 0>);
85+
86+
static_assert(!hasAsBytes<volatile int, 0>);
87+
static_assert(!hasAsBytes<volatile long, 0>);
88+
static_assert(!hasAsBytes<volatile double, 0>);
89+
static_assert(!hasAsBytes<volatile A, 0>);
90+
static_assert(!hasAsBytes<volatile std::string, 0>);
91+
92+
static_assert(!hasAsBytes<const volatile int, 0>);
93+
static_assert(!hasAsBytes<const volatile long, 0>);
94+
static_assert(!hasAsBytes<const volatile double, 0>);
95+
static_assert(!hasAsBytes<const volatile A, 0>);
96+
static_assert(!hasAsBytes<const volatile std::string, 0>);
97+
}
98+
4699
int main(int, char**) {
100+
test_constraints();
101+
47102
testRuntimeSpan(std::span<int>());
48103
testRuntimeSpan(std::span<long>());
49104
testRuntimeSpan(std::span<double>());

libcxx/test/std/containers/views/views.span/span.objectrep/as_writable_bytes.pass.cpp

Lines changed: 60 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@
99

1010
// <span>
1111

12-
// template <class ElementType, size_t Extent>
13-
// span<byte,
14-
// Extent == dynamic_extent
15-
// ? dynamic_extent
16-
// : sizeof(ElementType) * Extent>
12+
// template<class ElementType, size_t Extent>
13+
// span<byte, Extent == dynamic_extent ? dynamic_extent : sizeof(ElementType) * Extent>
1714
// as_writable_bytes(span<ElementType, Extent> s) noexcept;
15+
//
16+
// Constraints:
17+
// is_const_v<ElementType> is false and is_volatile_v<ElementType> is false.
1818

1919
#include <cassert>
2020
#include <cstddef>
@@ -23,6 +23,9 @@
2323

2424
#include "test_macros.h"
2525

26+
template <class T, std::size_t Extent = std::dynamic_extent>
27+
concept hasAsWritableBytes = requires(std::span<T, Extent> s) { std::as_writable_bytes(s); };
28+
2629
template <typename Span>
2730
void testRuntimeSpan(Span sp) {
2831
ASSERT_NOEXCEPT(std::as_writable_bytes(sp));
@@ -43,7 +46,59 @@ void testRuntimeSpan(Span sp) {
4346
struct A {};
4447
int iArr2[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
4548

49+
void test_constraints() {
50+
static_assert(hasAsWritableBytes<int>);
51+
static_assert(hasAsWritableBytes<long>);
52+
static_assert(hasAsWritableBytes<double>);
53+
static_assert(hasAsWritableBytes<A>);
54+
static_assert(hasAsWritableBytes<std::string>);
55+
56+
static_assert(!hasAsWritableBytes<const int>);
57+
static_assert(!hasAsWritableBytes<const long>);
58+
static_assert(!hasAsWritableBytes<const double>);
59+
static_assert(!hasAsWritableBytes<const A>);
60+
static_assert(!hasAsWritableBytes<const std::string>);
61+
62+
static_assert(!hasAsWritableBytes<volatile int>);
63+
static_assert(!hasAsWritableBytes<volatile long>);
64+
static_assert(!hasAsWritableBytes<volatile double>);
65+
static_assert(!hasAsWritableBytes<volatile A>);
66+
static_assert(!hasAsWritableBytes<volatile std::string>);
67+
68+
static_assert(!hasAsWritableBytes<const volatile int>);
69+
static_assert(!hasAsWritableBytes<const volatile long>);
70+
static_assert(!hasAsWritableBytes<const volatile double>);
71+
static_assert(!hasAsWritableBytes<const volatile A>);
72+
static_assert(!hasAsWritableBytes<const volatile std::string>);
73+
74+
static_assert(hasAsWritableBytes<int, 0>);
75+
static_assert(hasAsWritableBytes<long, 0>);
76+
static_assert(hasAsWritableBytes<double, 0>);
77+
static_assert(hasAsWritableBytes<A, 0>);
78+
static_assert(hasAsWritableBytes<std::string, 0>);
79+
80+
static_assert(!hasAsWritableBytes<const int, 0>);
81+
static_assert(!hasAsWritableBytes<const long, 0>);
82+
static_assert(!hasAsWritableBytes<const double, 0>);
83+
static_assert(!hasAsWritableBytes<const A, 0>);
84+
static_assert(!hasAsWritableBytes<const std::string, 0>);
85+
86+
static_assert(!hasAsWritableBytes<volatile int, 0>);
87+
static_assert(!hasAsWritableBytes<volatile long, 0>);
88+
static_assert(!hasAsWritableBytes<volatile double, 0>);
89+
static_assert(!hasAsWritableBytes<volatile A, 0>);
90+
static_assert(!hasAsWritableBytes<volatile std::string, 0>);
91+
92+
static_assert(!hasAsWritableBytes<const volatile int, 0>);
93+
static_assert(!hasAsWritableBytes<const volatile long, 0>);
94+
static_assert(!hasAsWritableBytes<const volatile double, 0>);
95+
static_assert(!hasAsWritableBytes<const volatile A, 0>);
96+
static_assert(!hasAsWritableBytes<const volatile std::string, 0>);
97+
}
98+
4699
int main(int, char**) {
100+
test_constraints();
101+
47102
testRuntimeSpan(std::span<int>());
48103
testRuntimeSpan(std::span<long>());
49104
testRuntimeSpan(std::span<double>());

libcxx/test/std/containers/views/views.span/span.objectrep/as_writable_bytes.verify.cpp

Lines changed: 0 additions & 55 deletions
This file was deleted.

0 commit comments

Comments
 (0)