From 37ecdf7e917cc92b5d14031f459487b086214348 Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Tue, 10 Dec 2024 08:51:38 -0500 Subject: [PATCH] [libc++] Use static_asserts for span::front() and span::back() when possible --- libcxx/include/span | 4 +-- .../views.span/span.elem/assert.back.pass.cpp | 23 ++++++------- .../span.elem/assert.front.pass.cpp | 23 ++++++------- .../views.span/span.elem/back.verify.cpp | 33 +++++++++++++++++++ .../views.span/span.elem/front.verify.cpp | 33 +++++++++++++++++++ 5 files changed, 88 insertions(+), 28 deletions(-) create mode 100644 libcxx/test/libcxx/containers/views/views.span/span.elem/back.verify.cpp create mode 100644 libcxx/test/libcxx/containers/views/views.span/span.elem/front.verify.cpp diff --git a/libcxx/include/span b/libcxx/include/span index 2d43d1d1079e4..f05a0383a3c6a 100644 --- a/libcxx/include/span +++ b/libcxx/include/span @@ -369,12 +369,12 @@ public: # endif _LIBCPP_HIDE_FROM_ABI constexpr reference front() const noexcept { - _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "span::front() on empty span"); + static_assert(_Extent >= 1, "span::front() on empty span"); return __data_[0]; } _LIBCPP_HIDE_FROM_ABI constexpr reference back() const noexcept { - _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "span::back() on empty span"); + static_assert(_Extent >= 1, "span::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 ea98fe81ee2f8..8d30f9659afe2 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 // @@ -23,17 +24,13 @@ #include "check_assertion.h" int main(int, char**) { - { - std::array array{0, 1, 2}; - std::span const s(array.data(), 0); - TEST_LIBCPP_ASSERT_FAILURE(s.back(), "span::back() on empty span"); - } - - { - std::array array{0, 1, 2}; - std::span const s(array.data(), 0); - TEST_LIBCPP_ASSERT_FAILURE(s.back(), "span::back() on empty span"); - } - - return 0; + { + std::array array{0, 1, 2}; + std::span const s(array.data(), 0); + TEST_LIBCPP_ASSERT_FAILURE(s.back(), "span::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 2660ca1f90c14..6e5a4157ba6df 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 // @@ -23,17 +24,13 @@ #include "check_assertion.h" int main(int, char**) { - { - std::array array{0, 1, 2}; - std::span const s(array.data(), 0); - TEST_LIBCPP_ASSERT_FAILURE(s.front(), "span::front() on empty span"); - } - - { - std::array array{0, 1, 2}; - std::span const s(array.data(), 0); - TEST_LIBCPP_ASSERT_FAILURE(s.front(), "span::front() on empty span"); - } - - return 0; + { + std::array array{0, 1, 2}; + std::span const s(array.data(), 0); + TEST_LIBCPP_ASSERT_FAILURE(s.front(), "span::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 0000000000000..3060db0402a5b --- /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 + +// +// +// constexpr reference back() const noexcept; + +// Make sure that accessing a statically-sized span out-of-bounds triggers a +// compile-time error. + +#include +#include + +int main(int, char**) { + std::array array{0, 1, 2}; + { + std::span const s(array.data(), 0); + s.back(); // expected-error@span:* {{span::back() on empty span}} + } + { + std::span 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 0000000000000..793eb70259f70 --- /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 + +// +// +// constexpr reference front() const noexcept; + +// Make sure that accessing a statically-sized span out-of-bounds triggers a +// compile-time error. + +#include +#include + +int main(int, char**) { + std::array array{0, 1, 2}; + { + std::span const s(array.data(), 0); + s.front(); // expected-error@span:* {{span::front() on empty span}} + } + { + std::span const s(array.data(), 3); + s.front(); // nothing + } + + return 0; +}