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.