[Bug c++/106538] Reject-valid: Substitution failure causes error with unsatisfied constraint

ppalka at gcc dot gnu.org gcc-bugzilla@gcc.gnu.org
Mon Aug 8 15:06:55 GMT 2022


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 ***


More information about the Gcc-bugs mailing list