[libcxx-commits] [libcxx] [libc++] Use static_asserts for span::front() and span::back() when possible (PR #119381)
via libcxx-commits
libcxx-commits at lists.llvm.org
Tue Dec 10 05:57:24 PST 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libcxx
Author: Louis Dionne (ldionne)
<details>
<summary>Changes</summary>
When accessing a statically-sized std::span using front() and back(), we can use
static assertions to ensure bounds correctness instead of relying on a runtime
assertion. We already do that for other methods like subspan(), but it wasn't
done for front() and back().
---
Full diff: https://github.com/llvm/llvm-project/pull/119381.diff
5 Files Affected:
- (modified) libcxx/include/span (+2-2)
- (modified) libcxx/test/libcxx/containers/views/views.span/span.elem/assert.back.pass.cpp (+10-13)
- (modified) libcxx/test/libcxx/containers/views/views.span/span.elem/assert.front.pass.cpp (+10-13)
- (added) libcxx/test/libcxx/containers/views/views.span/span.elem/back.verify.cpp (+33)
- (added) libcxx/test/libcxx/containers/views/views.span/span.elem/front.verify.cpp (+33)
``````````diff
diff --git a/libcxx/include/span b/libcxx/include/span
index 097efbd50a00fd..08ddc5330b4e54 100644
--- a/libcxx/include/span
+++ b/libcxx/include/span
@@ -367,12 +367,12 @@ public:
# endif
_LIBCPP_HIDE_FROM_ABI constexpr reference front() const noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "span<T, N>::front() on empty span");
+ static_assert(_Extent >= 1, "span<T, N>::front() on empty span");
return __data_[0];
}
_LIBCPP_HIDE_FROM_ABI constexpr reference back() const noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "span<T, N>::back() on empty span");
+ static_assert(_Extent >= 1, "span<T, N>::back() on empty span");
return __data_[size() - 1];
}
diff --git a/libcxx/test/libcxx/containers/views/views.span/span.elem/assert.back.pass.cpp b/libcxx/test/libcxx/containers/views/views.span/span.elem/assert.back.pass.cpp
index ea98fe81ee2f8a..8d30f9659afe2a 100644
--- a/libcxx/test/libcxx/containers/views/views.span/span.elem/assert.back.pass.cpp
+++ b/libcxx/test/libcxx/containers/views/views.span/span.elem/assert.back.pass.cpp
@@ -5,6 +5,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
+
// UNSUPPORTED: c++03, c++11, c++14, c++17
// <span>
@@ -23,17 +24,13 @@
#include "check_assertion.h"
int main(int, char**) {
- {
- std::array<int, 3> array{0, 1, 2};
- std::span<int> const s(array.data(), 0);
- TEST_LIBCPP_ASSERT_FAILURE(s.back(), "span<T>::back() on empty span");
- }
-
- {
- std::array<int, 3> array{0, 1, 2};
- std::span<int, 0> const s(array.data(), 0);
- TEST_LIBCPP_ASSERT_FAILURE(s.back(), "span<T, N>::back() on empty span");
- }
-
- return 0;
+ {
+ std::array<int, 3> array{0, 1, 2};
+ std::span<int> const s(array.data(), 0);
+ TEST_LIBCPP_ASSERT_FAILURE(s.back(), "span<T>::back() on empty span");
+ }
+
+ // back() on a span with a static extent is caught statically and tested in front.verify.cpp
+
+ return 0;
}
diff --git a/libcxx/test/libcxx/containers/views/views.span/span.elem/assert.front.pass.cpp b/libcxx/test/libcxx/containers/views/views.span/span.elem/assert.front.pass.cpp
index 2660ca1f90c141..6e5a4157ba6df2 100644
--- a/libcxx/test/libcxx/containers/views/views.span/span.elem/assert.front.pass.cpp
+++ b/libcxx/test/libcxx/containers/views/views.span/span.elem/assert.front.pass.cpp
@@ -5,6 +5,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
+
// UNSUPPORTED: c++03, c++11, c++14, c++17
// <span>
@@ -23,17 +24,13 @@
#include "check_assertion.h"
int main(int, char**) {
- {
- std::array<int, 3> array{0, 1, 2};
- std::span<int> const s(array.data(), 0);
- TEST_LIBCPP_ASSERT_FAILURE(s.front(), "span<T>::front() on empty span");
- }
-
- {
- std::array<int, 3> array{0, 1, 2};
- std::span<int, 0> const s(array.data(), 0);
- TEST_LIBCPP_ASSERT_FAILURE(s.front(), "span<T, N>::front() on empty span");
- }
-
- return 0;
+ {
+ std::array<int, 3> array{0, 1, 2};
+ std::span<int> const s(array.data(), 0);
+ TEST_LIBCPP_ASSERT_FAILURE(s.front(), "span<T>::front() on empty span");
+ }
+
+ // front() on a span with a static extent is caught statically and tested in front.verify.cpp
+
+ return 0;
}
diff --git a/libcxx/test/libcxx/containers/views/views.span/span.elem/back.verify.cpp b/libcxx/test/libcxx/containers/views/views.span/span.elem/back.verify.cpp
new file mode 100644
index 00000000000000..3060db0402a5b8
--- /dev/null
+++ b/libcxx/test/libcxx/containers/views/views.span/span.elem/back.verify.cpp
@@ -0,0 +1,33 @@
+//===----------------------------------------------------------------------===//
+//
+// 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>
+//
+// constexpr reference back() const noexcept;
+
+// Make sure that accessing a statically-sized span out-of-bounds triggers a
+// compile-time error.
+
+#include <array>
+#include <span>
+
+int main(int, char**) {
+ std::array<int, 3> array{0, 1, 2};
+ {
+ std::span<int, 0> const s(array.data(), 0);
+ s.back(); // expected-error at span:* {{span<T, N>::back() on empty span}}
+ }
+ {
+ std::span<int, 3> const s(array.data(), 3);
+ s.back(); // nothing
+ }
+
+ return 0;
+}
diff --git a/libcxx/test/libcxx/containers/views/views.span/span.elem/front.verify.cpp b/libcxx/test/libcxx/containers/views/views.span/span.elem/front.verify.cpp
new file mode 100644
index 00000000000000..793eb70259f70a
--- /dev/null
+++ b/libcxx/test/libcxx/containers/views/views.span/span.elem/front.verify.cpp
@@ -0,0 +1,33 @@
+//===----------------------------------------------------------------------===//
+//
+// 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>
+//
+// constexpr reference front() const noexcept;
+
+// Make sure that accessing a statically-sized span out-of-bounds triggers a
+// compile-time error.
+
+#include <array>
+#include <span>
+
+int main(int, char**) {
+ std::array<int, 3> array{0, 1, 2};
+ {
+ std::span<int, 0> const s(array.data(), 0);
+ s.front(); // expected-error at span:* {{span<T, N>::front() on empty span}}
+ }
+ {
+ std::span<int, 3> const s(array.data(), 3);
+ s.front(); // nothing
+ }
+
+ return 0;
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/119381
More information about the libcxx-commits
mailing list