Skip to content

Commit 67c4033

Browse files
[libc++] LWG-4021 "mdspan::is_always_meow() should be noexcept", use LIBCPP_STATIC_ASSERT for noexcept strengthening (#74254)
Found while running libc++'s test suite with MSVC's STL. * I've filed [LWG-4021](https://cplusplus.github.io/LWG/issue4021) "`mdspan::is_always_meow()` should be `noexcept`" and implemented this in libc++'s product and test code. * Use `LIBCPP_STATIC_ASSERT` to avoid issues with `noexcept` strengthening in MSVC's STL. + As permitted by the Standard, MSVC's STL conditionally strengthens `mdspan` construction/`is_meow`/`stride` and `elements_view` iterator `base() &&`, and always strengthens `basic_stringbuf` `swap`. + In `mdspan/properties.pass.cpp`, this also upgrades runtime `assert`s to `static_assert`s. * Improvement: Upgrade `assert` to `static_assert` when inspecting the `noexcept`ness of `std::ranges::iter_move`. (These `!noexcept` tests weren't causing issues for MSVC's STL, so I didn't change them to be libc++-specific.)
1 parent 78623b0 commit 67c4033

File tree

12 files changed

+38
-30
lines changed

12 files changed

+38
-30
lines changed

libcxx/include/__mdspan/mdspan.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -244,9 +244,14 @@ class mdspan {
244244
_LIBCPP_HIDE_FROM_ABI constexpr const mapping_type& mapping() const noexcept { return __map_; };
245245
_LIBCPP_HIDE_FROM_ABI constexpr const accessor_type& accessor() const noexcept { return __acc_; };
246246

247-
_LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_unique() { return mapping_type::is_always_unique(); };
248-
_LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_exhaustive() { return mapping_type::is_always_exhaustive(); };
249-
_LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_strided() { return mapping_type::is_always_strided(); };
247+
// per LWG-4021 "mdspan::is_always_meow() should be noexcept"
248+
_LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_unique() noexcept { return mapping_type::is_always_unique(); };
249+
_LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_exhaustive() noexcept {
250+
return mapping_type::is_always_exhaustive();
251+
};
252+
_LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_strided() noexcept {
253+
return mapping_type::is_always_strided();
254+
};
250255

251256
_LIBCPP_HIDE_FROM_ABI constexpr bool is_unique() const { return __map_.is_unique(); };
252257
_LIBCPP_HIDE_FROM_ABI constexpr bool is_exhaustive() const { return __map_.is_exhaustive(); };

libcxx/include/mdspan

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -334,11 +334,12 @@ namespace std {
334334
constexpr const mapping_type& mapping() const noexcept { return map_; }
335335
constexpr const accessor_type& accessor() const noexcept { return acc_; }
336336
337-
static constexpr bool is_always_unique()
337+
// per LWG-4021 "mdspan::is_always_meow() should be noexcept"
338+
static constexpr bool is_always_unique() noexcept
338339
{ return mapping_type::is_always_unique(); }
339-
static constexpr bool is_always_exhaustive()
340+
static constexpr bool is_always_exhaustive() noexcept
340341
{ return mapping_type::is_always_exhaustive(); }
341-
static constexpr bool is_always_strided()
342+
static constexpr bool is_always_strided() noexcept
342343
{ return mapping_type::is_always_strided(); }
343344
344345
constexpr bool is_unique() const

libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_array.pass.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ test_mdspan_ctor_array(const H& handle, const M& map, const A&, std::array<typen
6565
}
6666
}
6767

68-
static_assert(!noexcept(MDS(handle, exts)));
68+
LIBCPP_STATIC_ASSERT(!noexcept(MDS(handle, exts)));
6969

7070
static_assert(check_mdspan_ctor_implicit<MDS, decltype(exts)> == (N == MDS::rank_dynamic()));
7171

libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_extents.pass.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ constexpr void test_mdspan_types(const H& handle, const M& map, const A&) {
5151
assert((H::move_counter() == 1));
5252
}
5353
}
54-
static_assert(!noexcept(MDS(handle, map.extents())));
54+
LIBCPP_STATIC_ASSERT(!noexcept(MDS(handle, map.extents())));
5555
assert(m.extents() == map.extents());
5656
if constexpr (std::equality_comparable<H>)
5757
assert(m.data_handle() == handle);

libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_map.pass.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ constexpr void test_mdspan_types(const H& handle, const M& map, const A&) {
4848
assert((H::move_counter() == 1));
4949
}
5050
}
51-
static_assert(!noexcept(MDS(handle, map)));
51+
LIBCPP_STATIC_ASSERT(!noexcept(MDS(handle, map)));
5252
assert(m.extents() == map.extents());
5353
if constexpr (std::equality_comparable<H>)
5454
assert(m.data_handle() == handle);

libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_map_acc.pass.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ constexpr void test_mdspan_types(const H& handle, const M& map, const A& acc) {
4343
assert((H::move_counter() == 1));
4444
}
4545
}
46-
static_assert(!noexcept(MDS(handle, map, acc)));
46+
LIBCPP_STATIC_ASSERT(!noexcept(MDS(handle, map, acc)));
4747
assert(m.extents() == map.extents());
4848
if constexpr (std::equality_comparable<H>)
4949
assert(m.data_handle() == handle);

libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_span.pass.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ test_mdspan_ctor_span(const H& handle, const M& map, const A&, std::span<typenam
6565
}
6666
}
6767

68-
static_assert(!noexcept(MDS(handle, exts)));
68+
LIBCPP_STATIC_ASSERT(!noexcept(MDS(handle, exts)));
6969

7070
static_assert(check_mdspan_ctor_implicit<MDS, decltype(exts)> == (N == MDS::rank_dynamic()));
7171

libcxx/test/std/containers/views/mdspan/mdspan/properties.pass.cpp

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,12 @@
2727
// constexpr const data_handle_type& data_handle() const noexcept { return ptr_; }
2828
// constexpr const mapping_type& mapping() const noexcept { return map_; }
2929
// constexpr const accessor_type& accessor() const noexcept { return acc_; }
30-
// static constexpr bool is_always_unique()
30+
// /* per LWG-4021 "mdspan::is_always_meow() should be noexcept" */
31+
// static constexpr bool is_always_unique() noexcept
3132
// { return mapping_type::is_always_unique(); }
32-
// static constexpr bool is_always_exhaustive()
33+
// static constexpr bool is_always_exhaustive() noexcept
3334
// { return mapping_type::is_always_exhaustive(); }
34-
// static constexpr bool is_always_strided()
35+
// static constexpr bool is_always_strided() noexcept
3536
// { return mapping_type::is_always_strided(); }
3637
//
3738
// constexpr bool is_unique() const
@@ -141,15 +142,16 @@ constexpr void test_mdspan_types(const H& handle, const M& map, const A& acc) {
141142
ASSERT_SAME_TYPE(decltype(m.is_unique()), bool);
142143
ASSERT_SAME_TYPE(decltype(m.is_exhaustive()), bool);
143144
ASSERT_SAME_TYPE(decltype(m.is_strided()), bool);
144-
assert(!noexcept(MDS::is_always_unique()));
145-
assert(!noexcept(MDS::is_always_exhaustive()));
146-
assert(!noexcept(MDS::is_always_strided()));
147-
assert(!noexcept(m.is_unique()));
148-
assert(!noexcept(m.is_exhaustive()));
149-
assert(!noexcept(m.is_strided()));
150-
assert(MDS::is_always_unique() == M::is_always_unique());
151-
assert(MDS::is_always_exhaustive() == M::is_always_exhaustive());
152-
assert(MDS::is_always_strided() == M::is_always_strided());
145+
// per LWG-4021 "mdspan::is_always_meow() should be noexcept"
146+
static_assert(noexcept(MDS::is_always_unique()));
147+
static_assert(noexcept(MDS::is_always_exhaustive()));
148+
static_assert(noexcept(MDS::is_always_strided()));
149+
LIBCPP_STATIC_ASSERT(!noexcept(m.is_unique()));
150+
LIBCPP_STATIC_ASSERT(!noexcept(m.is_exhaustive()));
151+
LIBCPP_STATIC_ASSERT(!noexcept(m.is_strided()));
152+
static_assert(MDS::is_always_unique() == M::is_always_unique());
153+
static_assert(MDS::is_always_exhaustive() == M::is_always_exhaustive());
154+
static_assert(MDS::is_always_strided() == M::is_always_strided());
153155
assert(m.is_unique() == map.is_unique());
154156
assert(m.is_exhaustive() == map.is_exhaustive());
155157
assert(m.is_strided() == map.is_strided());
@@ -159,7 +161,7 @@ constexpr void test_mdspan_types(const H& handle, const M& map, const A& acc) {
159161
if (m.is_strided()) {
160162
for (typename MDS::rank_type r = 0; r < MDS::rank(); r++) {
161163
ASSERT_SAME_TYPE(decltype(m.stride(r)), typename MDS::index_type);
162-
assert(!noexcept(m.stride(r)));
164+
LIBCPP_STATIC_ASSERT(!noexcept(m.stride(r)));
163165
assert(m.stride(r) == map.stride(r));
164166
}
165167
}

libcxx/test/std/input.output/string.streams/stringbuf/stringbuf.assign/member_swap_noexcept.pass.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ static void test() {
8484
{
8585
std::basic_stringbuf<CharT, std::char_traits<CharT>, test_alloc_not_empty<CharT>> buf1;
8686
std::basic_stringbuf<CharT, std::char_traits<CharT>, test_alloc_not_empty<CharT>> buf;
87-
static_assert(!noexcept(buf.swap(buf1)));
87+
LIBCPP_STATIC_ASSERT(!noexcept(buf.swap(buf1)));
8888
}
8989
{
9090
std::basic_stringbuf<CharT, std::char_traits<CharT>, test_alloc_propagate_on_container_swap_not_empty<CharT>> buf1;

libcxx/test/std/input.output/string.streams/stringbuf/stringbuf.assign/nonmember_swap_noexcept.pass.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ static void test() {
8383
{
8484
std::basic_stringbuf<CharT, std::char_traits<CharT>, test_alloc_not_empty<CharT>> buf1;
8585
std::basic_stringbuf<CharT, std::char_traits<CharT>, test_alloc_not_empty<CharT>> buf;
86-
static_assert(!noexcept(swap(buf, buf1)));
86+
LIBCPP_STATIC_ASSERT(!noexcept(swap(buf, buf1)));
8787
}
8888
{
8989
std::basic_stringbuf<CharT, std::char_traits<CharT>, test_alloc_propagate_on_container_swap_not_empty<CharT>> buf1;

libcxx/test/std/iterators/iterator.requirements/iterator.cust/iterator.cust.move/iter_move.pass.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -158,15 +158,15 @@ constexpr bool test() {
158158

159159
auto unscoped = check_unqualified_lookup::unscoped_enum::a;
160160
assert(std::ranges::iter_move(unscoped) == check_unqualified_lookup::unscoped_enum::a);
161-
assert(!noexcept(std::ranges::iter_move(unscoped)));
161+
static_assert(!noexcept(std::ranges::iter_move(unscoped)));
162162

163163
auto scoped = check_unqualified_lookup::scoped_enum::a;
164164
assert(std::ranges::iter_move(scoped) == nullptr);
165-
assert(noexcept(std::ranges::iter_move(scoped)));
165+
static_assert(noexcept(std::ranges::iter_move(scoped)));
166166

167167
auto some_union = check_unqualified_lookup::some_union{0};
168168
assert(std::ranges::iter_move(some_union) == 0);
169-
assert(!noexcept(std::ranges::iter_move(some_union)));
169+
static_assert(!noexcept(std::ranges::iter_move(some_union)));
170170

171171
// Check noexcept-correctness
172172
static_assert(noexcept(std::ranges::iter_move(std::declval<WithADL<true>>())));

libcxx/test/std/ranges/range.adaptors/range.elements/iterator/base.pass.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ using ElementsIter = std::ranges::iterator_t<std::ranges::elements_view<BaseView
3333
static_assert(IsBaseNoexcept<const ElementsIter&>);
3434
static_assert(IsBaseNoexcept<ElementsIter&>);
3535
static_assert(IsBaseNoexcept<const ElementsIter&&>);
36-
static_assert(!IsBaseNoexcept<ElementsIter&&>);
36+
LIBCPP_STATIC_ASSERT(!IsBaseNoexcept<ElementsIter&&>);
3737

3838
constexpr bool test() {
3939
std::tuple<int> t{5};

0 commit comments

Comments
 (0)