From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2181) id 46F9B383B80E; Tue, 15 Jun 2021 18:27:48 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 46F9B383B80E MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Jonathan Wakely To: gcc-cvs@gcc.gnu.org, libstdc++-cvs@gcc.gnu.org Subject: [gcc r12-1488] libstdc++: Add noexcept specifiers to some range adaptors X-Act-Checkin: gcc X-Git-Author: Jonathan Wakely X-Git-Refname: refs/heads/master X-Git-Oldrev: a88fc03ba7e52d9a072f25d42bb9619fedb7892e X-Git-Newrev: 9245b0e84c262cc5fd8373e94de3d23a3807b122 Message-Id: <20210615182748.46F9B383B80E@sourceware.org> Date: Tue, 15 Jun 2021 18:27:48 +0000 (GMT) X-BeenThere: libstdc++-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libstdc++-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 15 Jun 2021 18:27:48 -0000 https://gcc.gnu.org/g:9245b0e84c262cc5fd8373e94de3d23a3807b122 commit r12-1488-g9245b0e84c262cc5fd8373e94de3d23a3807b122 Author: Jonathan Wakely Date: Tue Jun 15 16:36:12 2021 +0100 libstdc++: Add noexcept specifiers to some range adaptors Signed-off-by: Jonathan Wakely libstdc++-v3/ChangeLog: * include/bits/ranges_util.h (view_interface): Add noexcept to empty, operator bool, data and size members. (subrange): Add noexcept to constructors. * include/std/ranges (single_view, ref_view): Add noexcept to constructors. (views::single, views::all): Add noexcept. * testsuite/std/ranges/adaptors/all.cc: Check noexcept. * testsuite/std/ranges/single_view.cc: Likewise. Diff: --- libstdc++-v3/include/bits/ranges_util.h | 63 +++++++++++++++++------ libstdc++-v3/include/std/ranges | 18 +++++++ libstdc++-v3/testsuite/std/ranges/adaptors/all.cc | 30 +++++++++++ libstdc++-v3/testsuite/std/ranges/single_view.cc | 24 +++++++++ 4 files changed, 119 insertions(+), 16 deletions(-) diff --git a/libstdc++-v3/include/bits/ranges_util.h b/libstdc++-v3/include/bits/ranges_util.h index 02561ee63f9..dd829ed957f 100644 --- a/libstdc++-v3/include/bits/ranges_util.h +++ b/libstdc++-v3/include/bits/ranges_util.h @@ -77,45 +77,67 @@ namespace ranges return static_cast(*this); } + static constexpr bool + _S_bool(bool) noexcept; // not defined + + template + static constexpr bool + _S_empty(_Tp& __t) + noexcept(noexcept(_S_bool(ranges::begin(__t) == ranges::end(__t)))) + { return ranges::begin(__t) == ranges::end(__t); } + + template + static constexpr auto + _S_size(_Tp& __t) + noexcept(noexcept(ranges::end(__t) - ranges::begin(__t))) + { return ranges::end(__t) - ranges::begin(__t); } + public: constexpr bool - empty() requires forward_range<_Derived> - { return ranges::begin(_M_derived()) == ranges::end(_M_derived()); } + empty() + noexcept(noexcept(_S_empty(_M_derived()))) + requires forward_range<_Derived> + { return _S_empty(_M_derived()); } constexpr bool - empty() const requires forward_range - { return ranges::begin(_M_derived()) == ranges::end(_M_derived()); } + empty() const + noexcept(noexcept(_S_empty(_M_derived()))) + requires forward_range + { return _S_empty(_M_derived()); } constexpr explicit - operator bool() requires requires { ranges::empty(_M_derived()); } + operator bool() noexcept(noexcept(ranges::empty(_M_derived()))) + requires requires { ranges::empty(_M_derived()); } { return !ranges::empty(_M_derived()); } constexpr explicit - operator bool() const requires requires { ranges::empty(_M_derived()); } + operator bool() const noexcept(noexcept(ranges::empty(_M_derived()))) + requires requires { ranges::empty(_M_derived()); } { return !ranges::empty(_M_derived()); } constexpr auto - data() requires contiguous_iterator> - { return to_address(ranges::begin(_M_derived())); } + data() noexcept(noexcept(ranges::begin(_M_derived()))) + requires contiguous_iterator> + { return std::to_address(ranges::begin(_M_derived())); } constexpr auto - data() const + data() const noexcept(noexcept(ranges::begin(_M_derived()))) requires range && contiguous_iterator> - { return to_address(ranges::begin(_M_derived())); } + { return std::to_address(ranges::begin(_M_derived())); } constexpr auto - size() + size() noexcept(noexcept(_S_size(_M_derived()))) requires forward_range<_Derived> && sized_sentinel_for, iterator_t<_Derived>> - { return ranges::end(_M_derived()) - ranges::begin(_M_derived()); } + { return _S_size(_M_derived()); } constexpr auto - size() const + size() const noexcept(noexcept(_S_size(_M_derived()))) requires forward_range && sized_sentinel_for, iterator_t> - { return ranges::end(_M_derived()) - ranges::begin(_M_derived()); } + { return _S_size(_M_derived()); } constexpr decltype(auto) front() requires forward_range<_Derived> @@ -223,6 +245,8 @@ namespace ranges constexpr subrange(__detail::__convertible_to_non_slicing<_It> auto __i, _Sent __s) + noexcept(is_nothrow_constructible_v<_It, decltype(__i)> + && is_nothrow_constructible_v<_Sent, _Sent&>) requires (!_S_store_size) : _M_begin(std::move(__i)), _M_end(__s) { } @@ -230,6 +254,8 @@ namespace ranges constexpr subrange(__detail::__convertible_to_non_slicing<_It> auto __i, _Sent __s, __size_type __n) + noexcept(is_nothrow_constructible_v<_It, decltype(__i)> + && is_nothrow_constructible_v<_Sent, _Sent&>) requires (_Kind == subrange_kind::sized) : _M_begin(std::move(__i)), _M_end(__s) { @@ -242,7 +268,9 @@ namespace ranges && __detail::__convertible_to_non_slicing, _It> && convertible_to, _Sent> constexpr - subrange(_Rng&& __r) requires _S_store_size && sized_range<_Rng> + subrange(_Rng&& __r) + noexcept(noexcept(subrange(__r, ranges::size(__r)))) + requires _S_store_size && sized_range<_Rng> : subrange(__r, ranges::size(__r)) { } @@ -251,7 +279,9 @@ namespace ranges && __detail::__convertible_to_non_slicing, _It> && convertible_to, _Sent> constexpr - subrange(_Rng&& __r) requires (!_S_store_size) + subrange(_Rng&& __r) + noexcept(noexcept(subrange(ranges::begin(__r), ranges::end(__r)))) + requires (!_S_store_size) : subrange(ranges::begin(__r), ranges::end(__r)) { } @@ -260,6 +290,7 @@ namespace ranges && convertible_to, _Sent> constexpr subrange(_Rng&& __r, __size_type __n) + noexcept(noexcept(subrange(ranges::begin(__r), ranges::end(__r), __n))) requires (_Kind == subrange_kind::sized) : subrange{ranges::begin(__r), ranges::end(__r), __n} { } diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges index 220a44e11a8..b2943490e31 100644 --- a/libstdc++-v3/include/std/ranges +++ b/libstdc++-v3/include/std/ranges @@ -197,11 +197,13 @@ namespace ranges constexpr explicit single_view(const _Tp& __t) + noexcept(is_nothrow_copy_constructible_v<_Tp>) : _M_value(__t) { } constexpr explicit single_view(_Tp&& __t) + noexcept(is_nothrow_move_constructible_v<_Tp>) : _M_value(std::move(__t)) { } @@ -211,6 +213,7 @@ namespace ranges requires constructible_from<_Tp, _Args...> constexpr explicit single_view(in_place_t, _Args&&... __args) + noexcept(is_nothrow_constructible_v<_Tp, _Args...>) : _M_value{in_place, std::forward<_Args>(__args)...} { } @@ -604,6 +607,7 @@ namespace views template constexpr auto operator()(_Tp&& __e) const + noexcept(noexcept(single_view>(std::forward<_Tp>(__e)))) { return single_view>(std::forward<_Tp>(__e)); } }; @@ -1022,6 +1026,7 @@ namespace views::__adaptor && requires { _S_fun(declval<_Tp>()); } constexpr ref_view(_Tp&& __t) + noexcept(noexcept(static_cast<_Range&>(std::declval<_Tp>()))) : _M_r(std::__addressof(static_cast<_Range&>(std::forward<_Tp>(__t)))) { } @@ -1069,12 +1074,25 @@ namespace views::__adaptor struct _All : __adaptor::_RangeAdaptorClosure { + template + static constexpr bool + _S_noexcept() + { + if constexpr (view>) + return is_nothrow_constructible_v, _Range>; + else if constexpr (__detail::__can_ref_view<_Range>) + return true; + else + return noexcept(subrange{std::declval<_Range>()}); + } + template requires view> || __detail::__can_ref_view<_Range> || __detail::__can_subrange<_Range> constexpr auto operator()(_Range&& __r) const + noexcept(_S_noexcept<_Range>()) { if constexpr (view>) return std::forward<_Range>(__r); diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/all.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/all.cc index 42913ad38a3..9a6a31e6cb4 100644 --- a/libstdc++-v3/testsuite/std/ranges/adaptors/all.cc +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/all.cc @@ -130,6 +130,35 @@ test05() static_assert(!requires { 0 | all; }); } +template +struct BorrowedRange +{ + int* ptr = nullptr; + + BorrowedRange(int (&arr)[3]) noexcept : ptr(arr) { } + + int* begin() const noexcept(B1) { return ptr; } + int* end() const noexcept(B2) { return ptr + 3; } +}; + +template +const bool std::ranges::enable_borrowed_range> = true; + +void +test06() +{ + int x[] { 1, 2, 3 }; + + // Using ref_view: + static_assert(noexcept(views::all(x))); + + // Using subrange: + static_assert(noexcept(views::all(BorrowedRange(x)))); + static_assert(!noexcept(views::all(BorrowedRange(x)))); + static_assert(!noexcept(views::all(BorrowedRange(x)))); + static_assert(!noexcept(views::all(BorrowedRange(x)))); +} + int main() { @@ -138,4 +167,5 @@ main() static_assert(test03()); static_assert(test04()); test05(); + test06(); } diff --git a/libstdc++-v3/testsuite/std/ranges/single_view.cc b/libstdc++-v3/testsuite/std/ranges/single_view.cc index f530cc07565..c036fc8976a 100644 --- a/libstdc++-v3/testsuite/std/ranges/single_view.cc +++ b/libstdc++-v3/testsuite/std/ranges/single_view.cc @@ -73,10 +73,34 @@ test04() std::as_const(s).data(); } +void +test05() +{ + int i = 0; + static_assert(noexcept(std::ranges::single_view())); + static_assert(noexcept(std::ranges::single_view(i))); + static_assert(noexcept(std::ranges::single_view(1))); + static_assert(noexcept(std::ranges::single_view(std::in_place, 2))); + static_assert(noexcept(std::ranges::views::single(i))); + auto s = std::ranges::views::single(i); + static_assert(noexcept(s.begin())); + static_assert(noexcept(s.end())); + static_assert(noexcept(s.size())); + static_assert(noexcept(s.data())); + static_assert(noexcept(s.empty())); // view_interface::empty() + const auto cs = s; + static_assert(noexcept(cs.begin())); + static_assert(noexcept(cs.end())); + static_assert(noexcept(cs.size())); + static_assert(noexcept(cs.data())); + static_assert(noexcept(cs.empty())); // view_interface::empty() +} + int main() { test01(); test02(); test03(); test04(); + test05(); }