https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106538
Patrick Palka <ppalka at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- Status|UNCONFIRMED |RESOLVED CC| |ppalka at gcc dot gnu.org Resolution|--- |DUPLICATE --- Comment #1 from Patrick Palka <ppalka at gcc dot gnu.org> --- Thanks for the bug report. It's somewhat unintuitive, but I believe GCC is correct to reject this testcase. I think other compilers accept it because they don't fully implement wg21.link/cwg2369 which moved the constraint satisfaction check during template argument deduction to _before_ checking non-dependent conversions. This means that during overload resolution for the call tag_invoke(sync_wait_t{}, sch, s) we need to check satisfaction of the receiver<Recv> constraint on the candidate template <receiver Recv> friend constexpr auto tag_invoke(connect_t, Sender, Recv &&) despite the type sync_wait_t of the first argument not being convertible to connect_t, and it's during satisfaction that we encounter the hard error. Before CWG2369 we'd check non-dependent conversions first, and then check constraints, so we'd discard this candidate without having to check its constraints and avoid the hard error. One way to work around this is to encode the non-dependent conversion as an additional constraint that's checked first: #ifdef ADD_CONSTRAINED_OVERLOAD template <std::convertible_to<connect_t> T, receiver Recv> friend constexpr auto tag_invoke(T, Sender, Recv &&) { return Op{}; } #endif Another workaround is to make set_done_t::operator() more SFINAE-friendly by giving it a non-deduced return type, so that ill-formed calls to it don't end up being a hard error: template <typename Recv> auto operator()(Recv &&r) const noexcept -> decltype(tag_invoke(*this, (Recv&&)r)); See also PR99599 / PR97704. *** This bug has been marked as a duplicate of bug 99599 ***