* [Bug c++/112490] infinite meta error in reverse_iterator<basic_const_iterator<vector<int>::iterator>>
2023-11-12 11:33 [Bug c++/112490] New: infinite meta error in reverse_iterator<basic_const_iterator<vector<int>::iterator>> hewillk at gmail dot com
2023-11-13 0:20 ` [Bug c++/112490] " pinskia at gcc dot gnu.org
2023-11-13 0:21 ` pinskia at gcc dot gnu.org
@ 2024-04-05 17:45 ` barry.revzin at gmail dot com
2 siblings, 0 replies; 4+ messages in thread
From: barry.revzin at gmail dot com @ 2024-04-05 17:45 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=112490
Barry Revzin <barry.revzin at gmail dot com> changed:
What |Removed |Added
----------------------------------------------------------------------------
CC| |barry.revzin at gmail dot com
--- Comment #3 from Barry Revzin <barry.revzin at gmail dot com> ---
I ran into this also in a different direction, have been trying to reduce:
#include <compare>
template <class T, class U> concept my_partially_ordered_with = requires (T t,
U u) { t < u; };
template <class T> concept my_totally_ordered = my_partially_ordered_with<T,
T>;
template <class T, class U> concept my_totally_ordered_with =
my_totally_ordered<T> && my_totally_ordered<U> && my_partially_ordered_with<T,
U>;
template<class _It> class basic_const_iterator;
namespace __detail
{
template<typename _Tp>
inline constexpr bool __is_const_iterator = false;
template<typename _It>
inline constexpr bool __is_const_iterator<basic_const_iterator<_It>> =
true;
template<typename _Tp>
concept __not_a_const_iterator = !__is_const_iterator<_Tp>;
} // namespace detail
template<class _It>
class basic_const_iterator
{
#ifdef MAKE_THIS_PUBLIC
public:
#endif
int m;
public:
template <__detail::__not_a_const_iterator _It2>
friend bool operator<(const _It2& __x, const basic_const_iterator& __y)
requires my_totally_ordered_with<_It, _It2> { return true; }
};
template <class Iter>
struct wrapped
{
Iter iter;
constexpr std::strong_ordering operator<=>(const wrapped& rhs) const
noexcept;
};
bool check(wrapped<basic_const_iterator<int*>> x) {
return x < x;
}
gcc rejects this with constraint recursion. clang and MSVC accept. Oddly, if
you make _M_current public, gcc trunk accepts (even though no code even
references this) while gcc 13.2 still rejects. On compiler explorer:
https://godbolt.org/z/zfvxdGneK
Trunk's rejection message is also incomplete:
<source>: In substitution of 'template<class _It2> requires
__not_a_const_iterator<_It2> bool operator<(const _It2&, const
basic_const_iterator<int*>&) requires my_totally_ordered_with<_It, _It2> [with
_It2 = int*]':
<source>:3:89: required by substitution of 'template<class _It2> requires
__not_a_const_iterator<_It2> bool operator<(const _It2&, const
basic_const_iterator<int*>&) requires my_totally_ordered_with<_It, _It2> [with
_It2 = int*]'
3 | template <class T, class U> concept my_partially_ordered_with =
requires (T t, U u) { t < u; };
|
~~^~~
<source>:43:16: required from here
43 | return x < x;
| ^
It tells you _It2=int*, but not what _It is.
In this case, we're comparing two objects of type
wrapped<basic_const_iterator<int*>> with <, so we should have two candidates:
1. wrapped's <=>, which has no constraints
2. basic_const_iterator<int*>'s friend operator<, which we start instantiating
with _It=int* and _It2=wrapped<basic_const_iterator<int*>>.
(2) requires checking if _It and _It2 can be ordered, which I think recursively
instantiates itself.
Assuming that's correct (hopefully?), I think CWG 2369 should actually cause
this to be accepted - since wrapped<basic_const_iterator<int*>> is not
convertible to basic_const_iterator<int*>, that should cause (2) to be rejected
before we even consider constraints since it's not viable.
I have no idea what the public-ness of the member changes.
^ permalink raw reply [flat|nested] 4+ messages in thread