GCC 13 reports as ill-formed code that evaluates a concept C more than once

with the same template parameters, when the value of C changes between the
evaluations.  This is correct, but no other implementation checks this.  Move
all the hidden friends out of the v2::iterator_interface to fix these kinds of
errors.
This commit is contained in:
Zach Laine
2023-05-29 15:21:37 -05:00
parent cb96522275
commit d61867d8be

View File

@@ -623,11 +623,11 @@ namespace boost { namespace stl_interfaces { BOOST_STL_INTERFACES_NAMESPACE_V2 {
concept plus_eq = requires (D d) { d += DifferenceType(1); };
// clang-format on
template<typename D>
template<typename D, typename D2 = D>
// clang-format off
concept base_3way =
#if defined(__cpp_impl_three_way_comparison)
requires (D d) { access::base(d) <=> access::base(d); };
requires (D d, D2 d2) { access::base(d) <=> access::base(d2); };
#else
false;
#endif
@@ -639,11 +639,11 @@ namespace boost { namespace stl_interfaces { BOOST_STL_INTERFACES_NAMESPACE_V2 {
requires (D1 d1, D2 d2) { access::base(d1) == access::base(d2); };
// clang-format on
template<typename D>
template<typename D, typename D2 = D>
// clang-format off
concept iter_sub = requires (D d) {
concept iter_sub = requires (D d, D2 d2) {
typename D::difference_type;
{d - d} -> std::convertible_to<typename D::difference_type>;
{d - d2} -> std::convertible_to<typename D::difference_type>;
};
// clang-format on
@@ -788,14 +788,6 @@ namespace boost { namespace stl_interfaces { BOOST_STL_INTERFACES_NAMESPACE_V2 {
access::base(derived()) += n;
return derived();
}
friend constexpr auto operator+(D it, difference_type n)
requires requires { it += n; } {
return it += n;
}
friend constexpr auto operator+(difference_type n, D it)
requires requires { it += n; } {
return it += n;
}
constexpr decltype(auto) operator--()
requires requires (D d) { --access::base(d); } &&
@@ -816,44 +808,6 @@ namespace boost { namespace stl_interfaces { BOOST_STL_INTERFACES_NAMESPACE_V2 {
requires requires (D d) { d += -n; } {
return derived() += -n;
}
friend constexpr auto operator-(D lhs, D rhs)
requires requires { access::base(lhs) - access::base(rhs); } {
return access::base(lhs) - access::base(rhs);
}
friend constexpr auto operator-(D it, difference_type n)
requires requires { it += -n; } {
return it += -n;
}
#if defined(__cpp_lib_three_way_comparison)
friend constexpr auto operator<=>(D lhs, D rhs)
requires v2_dtl::base_3way<D> || v2_dtl::iter_sub<D> {
if constexpr (v2_dtl::base_3way<D>) {
return access::base(lhs) <=> access::base(rhs);
} else {
difference_type const diff = rhs - lhs;
return diff < difference_type(0) ? std::strong_ordering::less :
difference_type(0) < diff ? std::strong_ordering::greater :
std::strong_ordering::equal;
}
}
#endif
friend constexpr bool operator<(D lhs, D rhs)
requires v2_dtl::iter_sub<D> {
return (lhs - rhs) < difference_type(0);
}
friend constexpr bool operator<=(D lhs, D rhs)
requires v2_dtl::iter_sub<D> {
return (lhs - rhs) <= difference_type(0);
}
friend constexpr bool operator>(D lhs, D rhs)
requires v2_dtl::iter_sub<D> {
return (lhs - rhs) > difference_type(0);
}
friend constexpr bool operator>=(D lhs, D rhs)
requires v2_dtl::iter_sub<D> {
return (lhs - rhs) >= difference_type(0);
}
};
namespace v2_dtl {
@@ -876,17 +830,69 @@ namespace boost { namespace stl_interfaces { BOOST_STL_INTERFACES_NAMESPACE_V2 {
concept derived_iter = requires (D d) { v2_dtl::derived_iterator(d); };
}
template<typename D>
constexpr auto operator+(D it, typename D::difference_type n)
requires v2_dtl::derived_iter<D> && requires { it += n; }
{ return it += n; }
template<typename D>
constexpr auto operator+(typename D::difference_type n, D it)
requires v2_dtl::derived_iter<D> && requires { it += n; }
{ return it += n; }
template<typename D1, typename D2>
constexpr bool operator==(D1 lhs, D2 rhs)
requires v2_dtl::derived_iter<D1> && v2_dtl::derived_iter<D2> &&
detail::interoperable<D1, D2>::value &&
(v2_dtl::base_eq<D1, D2> || v2_dtl::iter_sub<D1>) {
if constexpr (v2_dtl::base_eq<D1, D2>) {
return (access::base(lhs) == access::base(rhs));
} else if constexpr (v2_dtl::iter_sub<D1>) {
return (lhs - rhs) == typename D1::difference_type(0);
constexpr auto operator-(D1 lhs, D2 rhs)
requires v2_dtl::derived_iter<D1> && v2_dtl::derived_iter<D2> &&
requires { access::base(lhs) - access::base(rhs); }
{ return access::base(lhs) - access::base(rhs); }
template<typename D>
constexpr auto operator-(D it, typename D::difference_type n)
requires v2_dtl::derived_iter<D> && requires { it += -n; }
{ return it += -n; }
#if defined(__cpp_lib_three_way_comparison)
template<typename D1, typename D2>
constexpr auto operator<=>(D1 lhs, D2 rhs)
requires v2_dtl::derived_iter<D1> && v2_dtl::derived_iter<D2> &&
(v2_dtl::base_3way<D1, D2> || v2_dtl::iter_sub<D1, D2>) {
if constexpr (v2_dtl::base_3way<D1, D2>) {
return access::base(lhs) <=> access::base(rhs);
} else {
using diff_type = typename D1::difference_type;
diff_type const diff = rhs - lhs;
return diff < diff_type(0) ? std::strong_ordering::less :
diff_type(0) < diff ? std::strong_ordering::greater :
std::strong_ordering::equal;
}
}
#endif
template<typename D1, typename D2>
constexpr bool operator<(D1 lhs, D2 rhs)
requires v2_dtl::derived_iter<D1> && v2_dtl::derived_iter<D2> && v2_dtl::iter_sub<D1, D2>
{ return (lhs - rhs) < typename D1::difference_type(0); }
template<typename D1, typename D2>
constexpr bool operator<=(D1 lhs, D2 rhs)
requires v2_dtl::derived_iter<D1> && v2_dtl::derived_iter<D2> && v2_dtl::iter_sub<D1, D2>
{ return (lhs - rhs) <= typename D1::difference_type(0); }
template<typename D1, typename D2>
constexpr bool operator>(D1 lhs, D2 rhs)
requires v2_dtl::derived_iter<D1> && v2_dtl::derived_iter<D2> && v2_dtl::iter_sub<D1, D2>
{ return (lhs - rhs) > typename D1::difference_type(0); }
template<typename D1, typename D2>
constexpr bool operator>=(D1 lhs, D2 rhs)
requires v2_dtl::derived_iter<D1> && v2_dtl::derived_iter<D2> && v2_dtl::iter_sub<D1, D2>
{ return (lhs - rhs) >= typename D1::difference_type(0); }
template<typename D1, typename D2>
constexpr bool operator==(D1 lhs, D2 rhs)
requires v2_dtl::derived_iter<D1> && v2_dtl::derived_iter<D2> &&
detail::interoperable<D1, D2>::value &&
(v2_dtl::base_eq<D1, D2> || v2_dtl::iter_sub<D1, D2>) {
if constexpr (v2_dtl::base_eq<D1, D2>) {
return (access::base(lhs) == access::base(rhs));
} else if constexpr (v2_dtl::iter_sub<D1, D2>) {
return (lhs - rhs) == typename D1::difference_type(0);
}
}
}
template<typename D1, typename D2>
constexpr auto operator!=(D1 lhs, D2 rhs) -> decltype(!(lhs == rhs))