Open Quuxplusone opened 3 years ago
Bugzilla Link | PR47509 |
Status | NEW |
Importance | P normal |
Reported by | Avi Kivity (avi@scylladb.com) |
Reported on | 2020-09-13 07:35:14 -0700 |
Last modified on | 2021-11-23 09:04:52 -0800 |
Version | trunk |
Hardware | PC Linux |
CC | blitzrakete@gmail.com, erik.pilkington@gmail.com, johelegp@gmail.com, llvm-bugs@lists.llvm.org, mikhail.matrosov@gmail.com, rafael@espindo.la, raffael@casagrande.ch, richard-llvm@metafoo.co.uk, victor@westerhu.is, zilla@kayari.org |
Fixed by commit(s) | |
Attachments | |
Blocks | |
Blocked by | |
See also |
I narrowed it down to eager evaluation of constraints:
1. view_interface<iota_view> is instantiated as a base class of iota_view.
Clearly iota_view isn't defined at this stage, it's just a forward-declared
name.
2. view_interface instantiates iterator_t, which is an alias to
std::__detail::__range_iter_t.
3. __range_iter_t instantiates __ranges_begin.
4. __ranges_begin requires that its template parameter is a __member_begin<>
(among other options, but this is the valid one here).
5. __member_begin requires that the type (iota_view) have a begin() function.
But the type isn't defined yet.
According to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97120#c1, evaluation
should be lazy.
This reduces to something interesting:
Clang accepts:
----------------------------------------------
template <typename _Tp>
concept __member_begin = requires(_Tp __t) {
{__t.begin()};
};
template <typename _Tp>
concept nothing = requires(_Tp __t) {
{42};
};
template <typename _Tp>
requires __member_begin<_Tp> void __ranges_begin() {}
template <typename _Derived>
struct view_interface {
void foo() requires __member_begin<_Derived> {}
// void bar() requires nothing<decltype(__ranges_begin<_Derived>())> {}
};
struct drop_view : public view_interface<drop_view> {};
------------------------------------------------
Uncomment the declaration of bar and clang rejects this. gcc is OK with both.
If I understand it correctly, both gcc and clang agree that the direct use of a
unsatisfied requires should just disable foo. The disagreement is about an
indirect one, like in bar(). With gcc bar() is just disabled, but clang
produces an error. Note that gcc rejects:
-------------------------------------------------
template <typename _Tp>
concept __member_begin = requires(_Tp __t) {
{__t.begin()};
};
template <typename _Tp>
concept nothing = requires(_Tp __t) {
{42};
};
template <typename _Tp>
requires __member_begin<_Tp> void __ranges_begin() {}
template <typename _Derived>
struct view_interface {
void foo() requires __member_begin<_Derived> {}
void bar() requires nothing<decltype(__ranges_begin<_Derived>())> {}
};
struct drop_view : public view_interface<drop_view> {
void zed() {
this->bar();
}
};
-------------------------------------------------
This is indeed clang's bug: https://bugs.llvm.org/show_bug.cgi?id=50864
(In reply to Mikhail Matrosov from comment #3)
> This is indeed clang's bug: https://bugs.llvm.org/show_bug.cgi?id=50864
And this one and that are both dups of Bug 44833