* [committed] libstdc++: Add noexcept specifiers to some range adaptors
@ 2021-06-15 18:28 Jonathan Wakely
2021-06-16 13:40 ` Jonathan Wakely
0 siblings, 1 reply; 2+ messages in thread
From: Jonathan Wakely @ 2021-06-15 18:28 UTC (permalink / raw)
To: libstdc++, gcc-patches
[-- Attachment #1: Type: text/plain, Size: 508 bytes --]
Signed-off-by: Jonathan Wakely <jwakely@redhat.com>
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.
Tested powerpc64le-linux. Committed to trunk.
[-- Attachment #2: patch.txt --]
[-- Type: text/plain, Size: 10623 bytes --]
commit 9245b0e84c262cc5fd8373e94de3d23a3807b122
Author: Jonathan Wakely <jwakely@redhat.com>
Date: Tue Jun 15 16:36:12 2021
libstdc++: Add noexcept specifiers to some range adaptors
Signed-off-by: Jonathan Wakely <jwakely@redhat.com>
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 --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<const _Derived&>(*this);
}
+ static constexpr bool
+ _S_bool(bool) noexcept; // not defined
+
+ template<typename _Tp>
+ 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<typename _Tp>
+ 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<const _Derived>
- { return ranges::begin(_M_derived()) == ranges::end(_M_derived()); }
+ empty() const
+ noexcept(noexcept(_S_empty(_M_derived())))
+ requires forward_range<const _Derived>
+ { 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<iterator_t<_Derived>>
- { return to_address(ranges::begin(_M_derived())); }
+ data() noexcept(noexcept(ranges::begin(_M_derived())))
+ requires contiguous_iterator<iterator_t<_Derived>>
+ { return std::to_address(ranges::begin(_M_derived())); }
constexpr auto
- data() const
+ data() const noexcept(noexcept(ranges::begin(_M_derived())))
requires range<const _Derived>
&& contiguous_iterator<iterator_t<const _Derived>>
- { 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<sentinel_t<_Derived>, 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<const _Derived>
&& sized_sentinel_for<sentinel_t<const _Derived>,
iterator_t<const _Derived>>
- { 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<iterator_t<_Rng>, _It>
&& convertible_to<sentinel_t<_Rng>, _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<iterator_t<_Rng>, _It>
&& convertible_to<sentinel_t<_Rng>, _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<sentinel_t<_Rng>, _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<typename _Tp>
constexpr auto
operator()(_Tp&& __e) const
+ noexcept(noexcept(single_view<decay_t<_Tp>>(std::forward<_Tp>(__e))))
{ return single_view<decay_t<_Tp>>(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<typename _Range>
+ static constexpr bool
+ _S_noexcept()
+ {
+ if constexpr (view<decay_t<_Range>>)
+ return is_nothrow_constructible_v<decay_t<_Range>, _Range>;
+ else if constexpr (__detail::__can_ref_view<_Range>)
+ return true;
+ else
+ return noexcept(subrange{std::declval<_Range>()});
+ }
+
template<viewable_range _Range>
requires view<decay_t<_Range>>
|| __detail::__can_ref_view<_Range>
|| __detail::__can_subrange<_Range>
constexpr auto
operator()(_Range&& __r) const
+ noexcept(_S_noexcept<_Range>())
{
if constexpr (view<decay_t<_Range>>)
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<bool B1, bool B2>
+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<bool B1, bool B2>
+const bool std::ranges::enable_borrowed_range<BorrowedRange<B1, B2>> = 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<true, true>(x))));
+ static_assert(!noexcept(views::all(BorrowedRange<true, false>(x))));
+ static_assert(!noexcept(views::all(BorrowedRange<false, true>(x))));
+ static_assert(!noexcept(views::all(BorrowedRange<false, false>(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<int>()));
+ static_assert(noexcept(std::ranges::single_view<int>(i)));
+ static_assert(noexcept(std::ranges::single_view<int>(1)));
+ static_assert(noexcept(std::ranges::single_view<int>(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();
}
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: [committed] libstdc++: Add noexcept specifiers to some range adaptors
2021-06-15 18:28 [committed] libstdc++: Add noexcept specifiers to some range adaptors Jonathan Wakely
@ 2021-06-16 13:40 ` Jonathan Wakely
0 siblings, 0 replies; 2+ messages in thread
From: Jonathan Wakely @ 2021-06-16 13:40 UTC (permalink / raw)
To: Jonathan Wakely; +Cc: libstdc++, gcc Patches
On Tue, 15 Jun 2021 at 19:32, Jonathan Wakely wrote:
>
> Signed-off-by: Jonathan Wakely <jwakely@redhat.com>
>
> 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.
>
> Tested powerpc64le-linux. Committed to trunk.
This one also breaks modules, but seems to be a bug:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101095
If the compiler bug isn't fixed quickly I'll probably have to remove
the new noexcept-specifiers from the subrange constructors.
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2021-06-16 13:40 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-06-15 18:28 [committed] libstdc++: Add noexcept specifiers to some range adaptors Jonathan Wakely
2021-06-16 13:40 ` Jonathan Wakely
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).