[libc++] Remove conditional noexcepts from view_interface.

As suggested in D117966.
These conditional noexcepts are *permitted* by the Standard (as long
as there were no mistakes in them, I guess); but not *mandated*.
The Standard doesn't put any noexcept-specifications on these member functions.
The same logic would apply to `transform_view::iterator::operator*`
and `transform_view::iterator::operator[]`, but the Standard mandates
conditional noexcept on `iter_move(transform_view::iterator)`, and
I think it doesn't make much sense to say "moving from this iterator
is conditionally noexcept but not-moving from it is noexcept(false),"
so I'm leaving transform_view alone for now.

Differential Revision: https://reviews.llvm.org/D119374
This commit is contained in:
Arthur O'Dwyer 2022-02-09 14:31:21 -05:00
parent c9c9307301
commit 7bdf41653c
2 changed files with 18 additions and 43 deletions

View File

@ -9,6 +9,8 @@
#ifndef _LIBCPP___RANGES_VIEW_INTERFACE_H
#define _LIBCPP___RANGES_VIEW_INTERFACE_H
#include <__concepts/derived_from.h>
#include <__concepts/same_as.h>
#include <__config>
#include <__debug>
#include <__iterator/concepts.h>
@ -18,7 +20,6 @@
#include <__ranges/access.h>
#include <__ranges/concepts.h>
#include <__ranges/empty.h>
#include <concepts>
#include <type_traits>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@ -31,12 +32,6 @@ _LIBCPP_BEGIN_NAMESPACE_STD
namespace ranges {
template<class _Tp>
concept __can_empty = requires(_Tp __t) { ranges::empty(__t); };
template<class _Tp>
void __implicitly_convert_to(type_identity_t<_Tp>) noexcept;
template<class _Derived>
requires is_class_v<_Derived> && same_as<_Derived, remove_cv_t<_Derived>>
class view_interface {
@ -55,7 +50,6 @@ class view_interface {
public:
template<class _D2 = _Derived>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool empty()
noexcept(noexcept(__implicitly_convert_to<bool>(ranges::begin(__derived()) == ranges::end(__derived()))))
requires forward_range<_D2>
{
return ranges::begin(__derived()) == ranges::end(__derived());
@ -63,7 +57,6 @@ public:
template<class _D2 = _Derived>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool empty() const
noexcept(noexcept(__implicitly_convert_to<bool>(ranges::begin(__derived()) == ranges::end(__derived()))))
requires forward_range<const _D2>
{
return ranges::begin(__derived()) == ranges::end(__derived());
@ -72,8 +65,7 @@ public:
template<class _D2 = _Derived>
_LIBCPP_HIDE_FROM_ABI
constexpr explicit operator bool()
noexcept(noexcept(ranges::empty(declval<_D2>())))
requires __can_empty<_D2>
requires requires (_D2& __t) { ranges::empty(__t); }
{
return !ranges::empty(__derived());
}
@ -81,8 +73,7 @@ public:
template<class _D2 = _Derived>
_LIBCPP_HIDE_FROM_ABI
constexpr explicit operator bool() const
noexcept(noexcept(ranges::empty(declval<const _D2>())))
requires __can_empty<const _D2>
requires requires (const _D2& __t) { ranges::empty(__t); }
{
return !ranges::empty(__derived());
}
@ -90,7 +81,6 @@ public:
template<class _D2 = _Derived>
_LIBCPP_HIDE_FROM_ABI
constexpr auto data()
noexcept(noexcept(std::to_address(ranges::begin(__derived()))))
requires contiguous_iterator<iterator_t<_D2>>
{
return std::to_address(ranges::begin(__derived()));
@ -99,7 +89,6 @@ public:
template<class _D2 = _Derived>
_LIBCPP_HIDE_FROM_ABI
constexpr auto data() const
noexcept(noexcept(std::to_address(ranges::begin(__derived()))))
requires range<const _D2> && contiguous_iterator<iterator_t<const _D2>>
{
return std::to_address(ranges::begin(__derived()));
@ -108,9 +97,7 @@ public:
template<class _D2 = _Derived>
_LIBCPP_HIDE_FROM_ABI
constexpr auto size()
noexcept(noexcept(ranges::end(__derived()) - ranges::begin(__derived())))
requires forward_range<_D2>
&& sized_sentinel_for<sentinel_t<_D2>, iterator_t<_D2>>
requires forward_range<_D2> && sized_sentinel_for<sentinel_t<_D2>, iterator_t<_D2>>
{
return ranges::end(__derived()) - ranges::begin(__derived());
}
@ -118,9 +105,7 @@ public:
template<class _D2 = _Derived>
_LIBCPP_HIDE_FROM_ABI
constexpr auto size() const
noexcept(noexcept(ranges::end(__derived()) - ranges::begin(__derived())))
requires forward_range<const _D2>
&& sized_sentinel_for<sentinel_t<const _D2>, iterator_t<const _D2>>
requires forward_range<const _D2> && sized_sentinel_for<sentinel_t<const _D2>, iterator_t<const _D2>>
{
return ranges::end(__derived()) - ranges::begin(__derived());
}
@ -128,7 +113,6 @@ public:
template<class _D2 = _Derived>
_LIBCPP_HIDE_FROM_ABI
constexpr decltype(auto) front()
noexcept(noexcept(*ranges::begin(__derived())))
requires forward_range<_D2>
{
_LIBCPP_ASSERT(!empty(),
@ -139,7 +123,6 @@ public:
template<class _D2 = _Derived>
_LIBCPP_HIDE_FROM_ABI
constexpr decltype(auto) front() const
noexcept(noexcept(*ranges::begin(__derived())))
requires forward_range<const _D2>
{
_LIBCPP_ASSERT(!empty(),
@ -150,7 +133,6 @@ public:
template<class _D2 = _Derived>
_LIBCPP_HIDE_FROM_ABI
constexpr decltype(auto) back()
noexcept(noexcept(*ranges::prev(ranges::end(__derived()))))
requires bidirectional_range<_D2> && common_range<_D2>
{
_LIBCPP_ASSERT(!empty(),
@ -161,7 +143,6 @@ public:
template<class _D2 = _Derived>
_LIBCPP_HIDE_FROM_ABI
constexpr decltype(auto) back() const
noexcept(noexcept(*ranges::prev(ranges::end(__derived()))))
requires bidirectional_range<const _D2> && common_range<const _D2>
{
_LIBCPP_ASSERT(!empty(),
@ -172,7 +153,6 @@ public:
template<random_access_range _RARange = _Derived>
_LIBCPP_HIDE_FROM_ABI
constexpr decltype(auto) operator[](range_difference_t<_RARange> __index)
noexcept(noexcept(ranges::begin(__derived())[__index]))
{
return ranges::begin(__derived())[__index];
}
@ -180,7 +160,6 @@ public:
template<random_access_range _RARange = const _Derived>
_LIBCPP_HIDE_FROM_ABI
constexpr decltype(auto) operator[](range_difference_t<_RARange> __index) const
noexcept(noexcept(ranges::begin(__derived())[__index]))
{
return ranges::begin(__derived())[__index];
}

View File

@ -126,17 +126,16 @@ struct DataIsNull : std::ranges::view_interface<DataIsNull> {
};
static_assert(std::ranges::view<DataIsNull>);
template<bool IsNoexcept>
struct BoolConvertibleComparison : std::ranges::view_interface<BoolConvertibleComparison<IsNoexcept>> {
struct BoolConvertibleComparison : std::ranges::view_interface<BoolConvertibleComparison> {
struct ResultType {
bool value;
constexpr operator bool() const noexcept(IsNoexcept) { return value; }
constexpr operator bool() const { return value; }
};
struct SentinelType {
int *base_;
SentinelType() = default;
explicit constexpr SentinelType(int *base) : base_(base) {}
explicit SentinelType() = default;
constexpr explicit SentinelType(int *base) : base_(base) {}
friend constexpr ResultType operator==(ForwardIter const& iter, SentinelType const& sent) noexcept { return {iter.base() == sent.base_}; }
friend constexpr ResultType operator==(SentinelType const& sent, ForwardIter const& iter) noexcept { return {iter.base() == sent.base_}; }
friend constexpr ResultType operator!=(ForwardIter const& iter, SentinelType const& sent) noexcept { return {iter.base() != sent.base_}; }
@ -144,11 +143,10 @@ struct BoolConvertibleComparison : std::ranges::view_interface<BoolConvertibleCo
};
int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7};
constexpr ForwardIter begin() const noexcept { return ForwardIter(const_cast<int*>(buff)); }
constexpr SentinelType end() const noexcept { return SentinelType(const_cast<int*>(buff) + 8); }
constexpr ForwardIter begin() const { return ForwardIter(const_cast<int*>(buff)); }
constexpr SentinelType end() const { return SentinelType(const_cast<int*>(buff) + 8); }
};
static_assert(std::ranges::view<BoolConvertibleComparison<true>>);
static_assert(std::ranges::view<BoolConvertibleComparison<false>>);
static_assert(std::ranges::view<BoolConvertibleComparison>);
template<class T>
concept EmptyInvocable = requires (T const& obj) { obj.empty(); };
@ -189,19 +187,17 @@ constexpr bool testEmpty() {
MoveOnlyForwardRange moveOnly;
assert(!std::move(moveOnly).empty());
BoolConvertibleComparison<true> boolConv;
BoolConvertibleComparison<false> boolConv2;
LIBCPP_ASSERT_NOEXCEPT(boolConv.empty());
ASSERT_NOT_NOEXCEPT(boolConv2.empty());
BoolConvertibleComparison boolConv;
ASSERT_NOT_NOEXCEPT(boolConv.empty());
assert(!boolConv.empty());
assert(!static_cast<BoolConvertibleComparison<true> const&>(boolConv).empty());
assert(!static_cast<const BoolConvertibleComparison&>(boolConv).empty());
assert(boolConv);
assert(static_cast<BoolConvertibleComparison<true> const&>(boolConv));
assert(static_cast<const BoolConvertibleComparison&>(boolConv));
assert(!std::ranges::empty(boolConv));
assert(!std::ranges::empty(static_cast<BoolConvertibleComparison<true> const&>(boolConv)));
assert(!std::ranges::empty(static_cast<const BoolConvertibleComparison&>(boolConv)));
return true;
}