[libcxx-commits] [libcxx] 508b451 - [libc++] Addresses LWG3358
Mark de Wever via libcxx-commits
libcxx-commits at lists.llvm.org
Tue Mar 7 10:36:44 PST 2023
Author: Mark de Wever
Date: 2023-03-07T19:36:34+01:00
New Revision: 508b4510de123c4cccc9440546da1f71a23cbb83
URL: https://github.com/llvm/llvm-project/commit/508b4510de123c4cccc9440546da1f71a23cbb83
DIFF: https://github.com/llvm/llvm-project/commit/508b4510de123c4cccc9440546da1f71a23cbb83.diff
LOG: [libc++] Addresses LWG3358
LWG3358 ยง[span.cons] is mistaken that to_address can throw
Since last - first has to throw tests are added to make sure this always
happens.
Depends on D142808
Reviewed By: #libc, ldionne
Differential Revision: https://reviews.llvm.org/D142843
Added:
Modified:
libcxx/docs/Status/Cxx20Issues.csv
libcxx/include/span
libcxx/test/std/containers/views/views.span/span.cons/iterator_sentinel.pass.cpp
Removed:
################################################################################
diff --git a/libcxx/docs/Status/Cxx20Issues.csv b/libcxx/docs/Status/Cxx20Issues.csv
index 062eb769f34cd..c0143931be018 100644
--- a/libcxx/docs/Status/Cxx20Issues.csv
+++ b/libcxx/docs/Status/Cxx20Issues.csv
@@ -268,7 +268,7 @@
"`3354 <https://wg21.link/LWG3354>`__","``has_strong_structural_equality``\ has a meaningless definition","Prague","|Nothing To Do|","","|spaceship|"
"`3355 <https://wg21.link/LWG3355>`__","The memory algorithms should support move-only input iterators introduced by P1207","Prague","|Complete|","15.0","|ranges|"
"`3356 <https://wg21.link/LWG3356>`__","``__cpp_lib_nothrow_convertible``\ should be ``__cpp_lib_is_nothrow_convertible``\ ","Prague","|Complete|","12.0"
-"`3358 <https://wg21.link/LWG3358>`__","|sect|\ [span.cons] is mistaken that ``to_address``\ can throw","Prague","",""
+"`3358 <https://wg21.link/LWG3358>`__","|sect|\ [span.cons] is mistaken that ``to_address``\ can throw","Prague","|Complete|","17.0"
"`3359 <https://wg21.link/LWG3359>`__","``<chrono>``\ leap second support should allow for negative leap seconds","Prague","","","|chrono|"
"`3360 <https://wg21.link/LWG3360>`__","``three_way_comparable_with``\ is inconsistent with similar concepts","Prague","|Nothing To Do|","","|spaceship|"
"`3362 <https://wg21.link/LWG3362>`__","Strike ``stop_source``\ 's ``operator!=``\ ","Prague","",""
diff --git a/libcxx/include/span b/libcxx/include/span
index 381404fe3a047..e961823565372 100644
--- a/libcxx/include/span
+++ b/libcxx/include/span
@@ -238,10 +238,12 @@ public:
template <__span_compatible_iterator<element_type> _It, __span_compatible_sentinel_for<_It> _End>
_LIBCPP_INLINE_VISIBILITY
constexpr explicit span(_It __first, _End __last) : __data_{_VSTD::to_address(__first)} {
- (void)__last;
- _LIBCPP_ASSERT((__last - __first >= 0), "invalid range in span's constructor (iterator, sentinel)");
- _LIBCPP_ASSERT(__last - __first == _Extent,
- "invalid range in span's constructor (iterator, sentinel): last - first != extent");
+ // [span.cons]/10
+ // Throws: When and what last - first throws.
+ [[maybe_unused]] auto __dist = __last - __first;
+ _LIBCPP_ASSERT(__dist >= 0, "invalid range in span's constructor (iterator, sentinel)");
+ _LIBCPP_ASSERT(
+ __dist == _Extent, "invalid range in span's constructor (iterator, sentinel): last - first != extent");
}
_LIBCPP_INLINE_VISIBILITY constexpr span(type_identity_t<element_type> (&__arr)[_Extent]) noexcept : __data_{__arr} {}
diff --git a/libcxx/test/std/containers/views/views.span/span.cons/iterator_sentinel.pass.cpp b/libcxx/test/std/containers/views/views.span/span.cons/iterator_sentinel.pass.cpp
index f744af789a8c7..335d2b850f6df 100644
--- a/libcxx/test/std/containers/views/views.span/span.cons/iterator_sentinel.pass.cpp
+++ b/libcxx/test/std/containers/views/views.span/span.cons/iterator_sentinel.pass.cpp
@@ -13,18 +13,22 @@
// constexpr explicit(Extent != dynamic_extent) span(It first, End last);
// Requires: [first, last) shall be a valid range.
// If Extent is not equal to dynamic_extent, then last - first shall be equal to Extent.
-//
+// Throws: When and what last - first throws.
+#include <array>
#include <span>
#include <cassert>
+#include <utility>
+#include "assert_macros.h"
#include "test_iterators.h"
+#include "test_macros.h"
template <class T, class Sentinel>
constexpr bool test_ctor() {
T val[2] = {};
- auto s1 = std::span<T>(std::begin(val), Sentinel(std::end(val)));
- auto s2 = std::span<T, 2>(std::begin(val), Sentinel(std::end(val)));
+ auto s1 = std::span<T>(std::begin(val), Sentinel(std::end(val)));
+ auto s2 = std::span<T, 2>(std::begin(val), Sentinel(std::end(val)));
assert(s1.data() == std::data(val) && s1.size() == std::size(val));
assert(s2.data() == std::data(val) && s2.size() == std::size(val));
return true;
@@ -55,8 +59,85 @@ constexpr bool test() {
return true;
}
+#ifndef TEST_HAS_NO_EXCEPTIONS
+// A stripped down contiguous iterator that throws when using operator-.
+template <class It>
+class throw_operator_minus {
+ It it_;
+
+public:
+ typedef std::contiguous_iterator_tag iterator_category;
+ typedef typename std::iterator_traits<It>::value_type value_type;
+ typedef typename std::iterator_traits<It>::
diff erence_type
diff erence_type;
+ typedef It pointer;
+ typedef typename std::iterator_traits<It>::reference reference;
+ typedef typename std::remove_pointer<It>::type element_type;
+
+ throw_operator_minus() : it_() {}
+ explicit throw_operator_minus(It it) : it_(it) {}
+
+ reference operator*() const { return *it_; }
+ pointer operator->() const { return it_; }
+ reference operator[](
diff erence_type n) const { return it_[n]; }
+
+ throw_operator_minus& operator++() {
+ ++it_;
+ return *this;
+ }
+ throw_operator_minus& operator--() {
+ --it_;
+ return *this;
+ }
+ throw_operator_minus operator++(int) { return throw_operator_minus(it_++); }
+ throw_operator_minus operator--(int) { return throw_operator_minus(it_--); }
+
+ throw_operator_minus& operator+=(
diff erence_type n) {
+ it_ += n;
+ return *this;
+ }
+ throw_operator_minus& operator-=(
diff erence_type n) {
+ it_ -= n;
+ return *this;
+ }
+ friend throw_operator_minus operator+(throw_operator_minus x,
diff erence_type n) {
+ x += n;
+ return x;
+ }
+ friend throw_operator_minus operator+(
diff erence_type n, throw_operator_minus x) {
+ x += n;
+ return x;
+ }
+ friend throw_operator_minus operator-(throw_operator_minus x,
diff erence_type n) {
+ x -= n;
+ return x;
+ }
+ friend
diff erence_type operator-(throw_operator_minus, throw_operator_minus) { throw 42; };
+
+ friend bool operator==(const throw_operator_minus& x, const throw_operator_minus& y) { return x.it_ == y.it_; }
+ friend bool operator<=>(const throw_operator_minus& x, const throw_operator_minus& y) { return x.it_ <=> y.it_; }
+};
+
+template <class It>
+throw_operator_minus(It) -> throw_operator_minus<It>;
+
+void test_exceptions() {
+ std::array a{42};
+ TEST_VALIDATE_EXCEPTION(
+ int,
+ [](int i) { assert(i == 42); },
+ (std::span<int>{throw_operator_minus{a.begin()}, throw_operator_minus{a.end()}}));
+ TEST_VALIDATE_EXCEPTION(
+ int,
+ [](int i) { assert(i == 42); },
+ (std::span<int, 1>{throw_operator_minus{a.begin()}, throw_operator_minus{a.end()}}));
+}
+#endif // TEST_HAS_NO_EXCEPTIONS
+
int main(int, char**) {
test();
+#ifndef TEST_HAS_NO_EXCEPTIONS
+ test_exceptions();
+#endif
static_assert(test());
return 0;
More information about the libcxx-commits
mailing list