https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93983

--- Comment #7 from Jonathan Wakely <redi at gcc dot gnu.org> ---
(In reply to Lyberta from comment #0)
> #include <concepts>
> #include <filesystem>
> 
> struct Foo
> {
>     Foo(const std::filesystem::path& p);
> };
> 
> static_assert(std::copyable<Foo>);

The problem is that copyable<Foo> considers the Foo(const path&) constructor to
see if it can be called with a const Foo&. That considers this constructor with
Foo substituted for Source:

filesystem::path(Source const&, format = auto_format);

The constraints for Source involve checking whether Source is a
Cpp17InputIterator, which is done with this:

  template<typename _Iter,
           typename _Iter_traits = std::iterator_traits<_Iter>>
    using __is_path_iter_src
      = __and_<__is_encoded_char<typename _Iter_traits::value_type>,
               std::is_base_of<std::input_iterator_tag,
                               typename _Iter_traits::iterator_category>>;

So we instantiate iterator_traits<Foo>.

In C++20 finding the matching specialization for std::iterator_traits<Foo>
checks for concept satisfaction, which includes checking copyable<Foo> which is
recursive.

An even smaller reproducer is:

#include <iterator>

struct X
{
  template<typename T, typename = std::iterator_traits<T>::iterator_category>
    X(const T&);
};

static_assert( std::copyable<X> );

I can fix filesystem::path to avoid using iterator_traits, but this seems like
it's going to cause problems for plenty of other code too.

Reply via email to