libstdc++: Make ranges CPOs final and not addressable

This restricts the API of the CPOs and other function objects so they
cannot be misused by deriving from them or taking their addresses.

Signed-off-by: Jonathan Wakely <jwakely@redhat.com>

libstdc++-v3/ChangeLog:

	* include/bits/ranges_base.h (ranges::begin, ranges::end)
	(ranges::cbegin, ranges::cend, ranges::rbeing, ranges::rend)
	(ranges::crbegin, ranges::crend, ranges::size, ranges::ssize)
	(ranges::empty, ranges::data, ranges::cdata): Make types final.
	Add deleted operator& overloads.
	(ranges::advance, ranges::distance, ranges::next, ranges::prev):
	Likewise.
	* testsuite/std/ranges/headers/ranges/synopsis.cc: Replace
	ill-formed & expressions with using-declarations. Add checks for
	other function objects.
This commit is contained in:
Jonathan Wakely 2021-06-15 17:54:53 +01:00
parent 9245b0e84c
commit 8b93548778
2 changed files with 69 additions and 25 deletions

View file

@ -91,7 +91,7 @@ namespace ranges
using std::ranges::__detail::__maybe_borrowed_range;
using std::__detail::__range_iter_t;
struct _Begin
struct _Begin final
{
private:
template<typename _Tp>
@ -106,6 +106,8 @@ namespace ranges
return noexcept(__decay_copy(begin(std::declval<_Tp&>())));
}
void operator&() const = delete;
public:
template<__maybe_borrowed_range _Tp>
requires is_array_v<remove_reference_t<_Tp>> || __member_begin<_Tp>
@ -142,7 +144,7 @@ namespace ranges
{ __decay_copy(end(__t)) } -> sentinel_for<__range_iter_t<_Tp>>;
};
struct _End
struct _End final
{
private:
template<typename _Tp>
@ -157,6 +159,8 @@ namespace ranges
return noexcept(__decay_copy(end(std::declval<_Tp&>())));
}
void operator&() const = delete;
public:
template<__maybe_borrowed_range _Tp>
requires is_bounded_array_v<remove_reference_t<_Tp>>
@ -189,7 +193,7 @@ namespace ranges
return static_cast<const _Tp&&>(__t);
}
struct _CBegin
struct _CBegin final
{
template<typename _Tp>
constexpr auto
@ -199,9 +203,11 @@ namespace ranges
{
return _Begin{}(__cust_access::__as_const<_Tp>(__e));
}
void operator&() const = delete;
};
struct _CEnd
struct _CEnd final
{
template<typename _Tp>
constexpr auto
@ -211,6 +217,8 @@ namespace ranges
{
return _End{}(__cust_access::__as_const<_Tp>(__e));
}
void operator&() const = delete;
};
template<typename _Tp>
@ -236,7 +244,7 @@ namespace ranges
{ _End{}(__t) } -> same_as<decltype(_Begin{}(__t))>;
};
struct _RBegin
struct _RBegin final
{
private:
template<typename _Tp>
@ -260,6 +268,8 @@ namespace ranges
}
}
void operator&() const = delete;
public:
template<__maybe_borrowed_range _Tp>
requires __member_rbegin<_Tp> || __adl_rbegin<_Tp> || __reversable<_Tp>
@ -294,7 +304,7 @@ namespace ranges
-> sentinel_for<decltype(_RBegin{}(std::forward<_Tp>(__t)))>;
};
struct _REnd
struct _REnd final
{
private:
template<typename _Tp>
@ -318,6 +328,8 @@ namespace ranges
}
}
void operator&() const = delete;
public:
template<__maybe_borrowed_range _Tp>
requires __member_rend<_Tp> || __adl_rend<_Tp> || __reversable<_Tp>
@ -334,7 +346,7 @@ namespace ranges
}
};
struct _CRBegin
struct _CRBegin final
{
template<typename _Tp>
constexpr auto
@ -344,9 +356,11 @@ namespace ranges
{
return _RBegin{}(__cust_access::__as_const<_Tp>(__e));
}
void operator&() const = delete;
};
struct _CREnd
struct _CREnd final
{
template<typename _Tp>
constexpr auto
@ -356,6 +370,8 @@ namespace ranges
{
return _REnd{}(__cust_access::__as_const<_Tp>(__e));
}
void operator&() const = delete;
};
template<typename _Tp>
@ -386,7 +402,7 @@ namespace ranges
__detail::__to_unsigned_like(_End{}(__t) - _Begin{}(__t));
};
struct _Size
struct _Size final
{
private:
template<typename _Tp>
@ -404,6 +420,8 @@ namespace ranges
- _Begin{}(std::declval<_Tp&>()));
}
void operator&() const = delete;
public:
template<typename _Tp>
requires is_bounded_array_v<remove_reference_t<_Tp>>
@ -422,7 +440,7 @@ namespace ranges
}
};
struct _SSize
struct _SSize final
{
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 3403. Domain of ranges::ssize(E) doesn't match ranges::size(E)
@ -451,6 +469,8 @@ namespace ranges
else // Must be one of __max_diff_type or __max_size_type.
return __detail::__max_diff_type(__size);
}
void operator&() const = delete;
};
template<typename _Tp>
@ -467,7 +487,7 @@ namespace ranges
bool(_Begin{}(__t) == _End{}(__t));
};
struct _Empty
struct _Empty final
{
private:
template<typename _Tp>
@ -483,6 +503,8 @@ namespace ranges
== _End{}(std::declval<_Tp&>())));
}
void operator&() const = delete;
public:
template<typename _Tp>
requires __member_empty<_Tp> || __size0_empty<_Tp>
@ -512,7 +534,7 @@ namespace ranges
template<typename _Tp>
concept __begin_data = contiguous_iterator<__range_iter_t<_Tp>>;
struct _Data
struct _Data final
{
private:
template<typename _Tp>
@ -525,6 +547,8 @@ namespace ranges
return noexcept(_Begin{}(std::declval<_Tp&>()));
}
void operator&() const = delete;
public:
template<__maybe_borrowed_range _Tp>
requires __member_data<_Tp> || __begin_data<_Tp>
@ -538,7 +562,7 @@ namespace ranges
}
};
struct _CData
struct _CData final
{
template<typename _Tp>
constexpr auto
@ -548,6 +572,8 @@ namespace ranges
{
return _Data{}(__cust_access::__as_const<_Tp>(__e));
}
void operator&() const = delete;
};
} // namespace __cust_access
@ -669,7 +695,7 @@ namespace ranges
// [range.iter.ops] range iterator operations
struct __advance_fn
struct __advance_fn final
{
template<input_or_output_iterator _It>
constexpr void
@ -774,11 +800,13 @@ namespace ranges
return __n;
}
}
void operator&() const = delete;
};
inline constexpr __advance_fn advance{};
struct __distance_fn
struct __distance_fn final
{
template<input_or_output_iterator _It, sentinel_for<_It> _Sent>
constexpr iter_difference_t<_It>
@ -807,11 +835,13 @@ namespace ranges
else
return (*this)(ranges::begin(__r), ranges::end(__r));
}
void operator&() const = delete;
};
inline constexpr __distance_fn distance{};
struct __next_fn
struct __next_fn final
{
template<input_or_output_iterator _It>
constexpr _It
@ -844,11 +874,13 @@ namespace ranges
ranges::advance(__x, __n, __bound);
return __x;
}
void operator&() const = delete;
};
inline constexpr __next_fn next{};
struct __prev_fn
struct __prev_fn final
{
template<bidirectional_iterator _It>
constexpr _It
@ -873,6 +905,8 @@ namespace ranges
ranges::advance(__x, -__n, __bound);
return __x;
}
void operator&() const = delete;
};
inline constexpr __prev_fn prev{};

View file

@ -33,12 +33,22 @@ namespace __gnu_test
{
constexpr const bool* disable_sized_range
= &std::ranges::disable_sized_range<void>;
constexpr auto* begin = &std::ranges::begin;
constexpr auto* end = &std::ranges::end;
constexpr auto* cbegin = &std::ranges::cbegin;
constexpr auto* cend = &std::ranges::cend;
constexpr auto* rbegin = &std::ranges::rbegin;
constexpr auto* rend = &std::ranges::rend;
constexpr auto* crbegin = &std::ranges::crbegin;
constexpr auto* crend = &std::ranges::crend;
using std::ranges::begin;
using std::ranges::end;
using std::ranges::cbegin;
using std::ranges::cend;
using std::ranges::rbegin;
using std::ranges::rend;
using std::ranges::crbegin;
using std::ranges::crend;
using std::ranges::size;
using std::ranges::ssize;
using std::ranges::empty;
using std::ranges::data;
using std::ranges::cdata;
using std::ranges::advance;
using std::ranges::distance;
using std::ranges::next;
using std::ranges::prev;
}