Bug 93983 - std::filesystem::path is not concept-friendly
Summary: std::filesystem::path is not concept-friendly
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: libstdc++ (show other bugs)
Version: 10.0
: P3 normal
Target Milestone: 10.2
Assignee: Jonathan Wakely
URL:
Keywords: rejects-valid
: 95233 (view as bug list)
Depends on:
Blocks: concepts
  Show dependency treegraph
 
Reported: 2020-02-29 18:42 UTC by Lyberta
Modified: 2020-05-21 07:05 UTC (History)
5 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2020-05-12 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Lyberta 2020-02-29 18:42:20 UTC
#include <concepts>
#include <filesystem>

struct Foo
{
    Foo(const std::filesystem::path& p);
};

static_assert(std::copyable<Foo>);

Error:
In file included from <source>:1:

/opt/compiler-explorer/gcc-trunk-20200229/include/c++/10.0.1/bits/stl_iterator_base_types.h: In instantiation of 'struct std::iterator_traits<Foo>':

/opt/compiler-explorer/gcc-trunk-20200229/include/c++/10.0.1/bits/fs_path.h:84:11:   required by substitution of 'template<class _Iter, class _Iter_traits> using __is_path_iter_src = std::__and_<std::__or_<std::is_same<typename std::remove_const<typename _Iter_traits::value_type>::type, char>, std::is_same<typename std::remove_const<typename _Iter_traits::value_type>::type, char8_t>, std::is_same<typename std::remove_const<typename _Iter_traits::value_type>::type, wchar_t>, std::is_same<typename std::remove_const<typename _Iter_traits::value_type>::type, char16_t>, std::is_same<typename std::remove_const<typename _Iter_traits::value_type>::type, char32_t> >, std::is_base_of<std::input_iterator_tag, typename _Iter_traits::iterator_category> > [with _Iter = Foo; _Iter_traits = std::iterator_traits<Foo>]'

/opt/compiler-explorer/gcc-trunk-20200229/include/c++/10.0.1/bits/fs_path.h:91:5:   required by substitution of 'template<class _Iter> std::filesystem::__cxx11::__detail::__is_path_iter_src<_Iter> std::filesystem::__cxx11::__detail::__is_path_src(_Iter, int) [with _Iter = Foo]'

/opt/compiler-explorer/gcc-trunk-20200229/include/c++/10.0.1/bits/fs_path.h:115:29:   required from 'struct std::filesystem::__cxx11::__detail::__constructible_from<Foo, void>'

/opt/compiler-explorer/gcc-trunk-20200229/include/c++/10.0.1/type_traits:138:12:   required from 'struct std::__and_<std::__not_<std::is_void<Foo> >, std::filesystem::__cxx11::__detail::__constructible_from<Foo, void> >'

/opt/compiler-explorer/gcc-trunk-20200229/include/c++/10.0.1/type_traits:143:12:   required from 'struct std::__and_<std::__not_<std::is_same<Foo, std::filesystem::__cxx11::path> >, std::__not_<std::is_void<Foo> >, std::filesystem::__cxx11::__detail::__constructible_from<Foo, void> >'

/opt/compiler-explorer/gcc-trunk-20200229/include/c++/10.0.1/bits/fs_path.h:119:11:   required by substitution of 'template<class _Tp1, class _Tp2> using _Path = typename std::enable_if<std::__and_<std::__not_<std::is_same<typename std::remove_cv< <template-parameter-1-1> >::type, std::filesystem::__cxx11::path> >, std::__not_<std::is_void<typename std::remove_pointer<_Tp>::type> >, std::filesystem::__cxx11::__detail::__constructible_from<_Tp1, _Tp2> >::value, std::filesystem::__cxx11::path>::type [with _Tp1 = Foo; _Tp2 = void]'

/opt/compiler-explorer/gcc-trunk-20200229/include/c++/10.0.1/bits/fs_path.h:219:7:   required by substitution of 'template<class _Source, class _Require> std::filesystem::__cxx11::path::path(const _Source&, std::filesystem::__cxx11::path::format) [with _Source = Foo; _Require = <missing>]'

/opt/compiler-explorer/gcc-trunk-20200229/include/c++/10.0.1/type_traits:901:30:   required from 'struct std::__is_constructible_impl<Foo, Foo>'

/opt/compiler-explorer/gcc-trunk-20200229/include/c++/10.0.1/type_traits:906:12:   required from 'struct std::is_constructible<Foo, Foo>'

/opt/compiler-explorer/gcc-trunk-20200229/include/c++/10.0.1/type_traits:3107:25:   required from 'constexpr const bool std::is_constructible_v<Foo, Foo>'

/opt/compiler-explorer/gcc-trunk-20200229/include/c++/10.0.1/concepts:139:30:   required from here

/opt/compiler-explorer/gcc-trunk-20200229/include/c++/10.0.1/concepts:139:30: error: the value of 'std::is_constructible_v<Foo, Foo>' is not usable in a constant expression

  139 |       = destructible<_Tp> && is_constructible_v<_Tp, _Args...>;

      |                              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

In file included from /opt/compiler-explorer/gcc-trunk-20200229/include/c++/10.0.1/concepts:44,

                 from <source>:1:

/opt/compiler-explorer/gcc-trunk-20200229/include/c++/10.0.1/type_traits:3107:25: note: 'std::is_constructible_v<Foo, Foo>' used in its own initializer

 3107 |   inline constexpr bool is_constructible_v =

      |                         ^~~~~~~~~~~~~~~~~~
Comment 1 Barry Revzin 2020-02-29 19:04:37 UTC
Here's a shorter reproduction without filesystem:

#include <concepts>
#include <iterator>

struct path {
    template <typename Source,
        typename = std::enable_if_t<
            std::is_same_v<
                std::iterator_traits<Source>::value_type,
                char>>
        >
    path(Source const&);
};

struct Bar
{
    Bar(const path& p);
};

#ifdef ADD_THIS
static_assert(!std::constructible_from<path, Bar>);
#endif
static_assert(std::copyable<Bar>);

If ADD_THIS isn't defined, the copyable check is a hard error. If it is defined, compiles fine.

https://godbolt.org/z/FEoiwA
Comment 2 Barry Revzin 2020-02-29 19:15:46 UTC
(From Tim) This is LWG 3244.
Comment 3 Jonathan Wakely 2020-03-01 21:29:19 UTC
This is nothing to do with concepts:

#include <iterator>

struct path {
    template <typename Source,
        typename = std::enable_if_t<
            std::is_same_v<
                std::iterator_traits<Source>::value_type,
                char>>
        >
    path(Source const&);
};

struct Bar
{
    Bar(const path& p);
};

#ifdef ADD_THIS
static_assert(!std::is_constructible_v<path, Bar>);
#endif
static_assert(std::is_copy_constructible_v<Bar>);


See also PR 93923.
Comment 4 Paco Arjonilla 2020-03-21 14:17:40 UTC
I got this error too. This is the code:



#include <filesystem>
#include <concepts>
struct A {
    A() = default;
    A(A const&) = default;
    A & operator = (A const&) = default;

    A(std::filesystem::path); // This line triggers the error.
};
static_assert(std::semiregular<A>);



There is no reason why an extra constructor would affect the semiregularity of a type.



$> g++ -std=c++20

In file included from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/compare:39,

                 from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/stl_pair.h:65,

                 from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/stl_algobase.h:64,

                 from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/char_traits.h:39,

                 from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/string:40,

                 from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/stdexcept:39,

                 from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/system_error:41,

                 from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/fs_fwd.h:35,

                 from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/filesystem:44,

                 from <source>:1:

/opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/stl_iterator_base_types.h: In instantiation of 'struct std::iterator_traits<A>':

/opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/fs_path.h:84:11:   required by substitution of 'template<class _Iter, class _Iter_traits> using __is_path_iter_src = std::__and_<std::__or_<std::is_same<typename std::remove_const<typename _Iter_traits::value_type>::type, char>, std::is_same<typename std::remove_const<typename _Iter_traits::value_type>::type, char8_t>, std::is_same<typename std::remove_const<typename _Iter_traits::value_type>::type, wchar_t>, std::is_same<typename std::remove_const<typename _Iter_traits::value_type>::type, char16_t>, std::is_same<typename std::remove_const<typename _Iter_traits::value_type>::type, char32_t> >, std::is_base_of<std::input_iterator_tag, typename _Iter_traits::iterator_category> > [with _Iter = A; _Iter_traits = std::iterator_traits<A>]'

/opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/fs_path.h:91:5:   required by substitution of 'template<class _Iter> std::filesystem::__cxx11::__detail::__is_path_iter_src<_Iter> std::filesystem::__cxx11::__detail::__is_path_src(_Iter, int) [with _Iter = A]'

/opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/fs_path.h:115:29:   required from 'struct std::filesystem::__cxx11::__detail::__constructible_from<A, void>'

/opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/type_traits:138:12:   required from 'struct std::__and_<std::__not_<std::is_void<A> >, std::filesystem::__cxx11::__detail::__constructible_from<A, void> >'

/opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/type_traits:143:12:   required from 'struct std::__and_<std::__not_<std::is_same<A, std::filesystem::__cxx11::path> >, std::__not_<std::is_void<A> >, std::filesystem::__cxx11::__detail::__constructible_from<A, void> >'

/opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/fs_path.h:119:11:   required by substitution of 'template<class _Tp1, class _Tp2> using _Path = typename std::enable_if<std::__and_<std::__not_<std::is_same<typename std::remove_cv< <template-parameter-1-1> >::type, std::filesystem::__cxx11::path> >, std::__not_<std::is_void<typename std::remove_pointer<_Tp>::type> >, std::filesystem::__cxx11::__detail::__constructible_from<_Tp1, _Tp2> >::value, std::filesystem::__cxx11::path>::type [with _Tp1 = A; _Tp2 = void]'

/opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/fs_path.h:219:7:   required by substitution of 'template<class _Source, class _Require> std::filesystem::__cxx11::path::path(const _Source&, std::filesystem::__cxx11::path::format) [with _Source = A; _Require = <missing>]'

/opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/type_traits:901:30:   required from 'struct std::__is_constructible_impl<A, A>'

/opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/type_traits:906:12:   required from 'struct std::is_constructible<A, A>'

/opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/type_traits:3091:25:   required from 'constexpr const bool std::is_constructible_v<A, A>'

/opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/concepts:139:30:   required from here

/opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/concepts:139:30: error: the value of 'std::is_constructible_v<A, A>' is not usable in a constant expression

  139 |       = destructible<_Tp> && is_constructible_v<_Tp, _Args...>;

      |                              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

In file included from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/move.h:57,

                 from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/nested_exception.h:40,

                 from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/exception:148,

                 from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/stdexcept:38,

                 from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/system_error:41,

                 from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/fs_fwd.h:35,

                 from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/filesystem:44,

                 from <source>:1:

/opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/type_traits:3091:25: note: 'std::is_constructible_v<A, A>' used in its own initializer

 3091 |   inline constexpr bool is_constructible_v =

      |                         ^~~~~~~~~~~~~~~~~~

ASM generation compiler returned: 1

In file included from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/compare:39,

                 from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/stl_pair.h:65,

                 from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/stl_algobase.h:64,

                 from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/char_traits.h:39,

                 from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/string:40,

                 from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/stdexcept:39,

                 from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/system_error:41,

                 from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/fs_fwd.h:35,

                 from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/filesystem:44,

                 from <source>:1:

/opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/stl_iterator_base_types.h: In instantiation of 'struct std::iterator_traits<A>':

/opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/fs_path.h:84:11:   required by substitution of 'template<class _Iter, class _Iter_traits> using __is_path_iter_src = std::__and_<std::__or_<std::is_same<typename std::remove_const<typename _Iter_traits::value_type>::type, char>, std::is_same<typename std::remove_const<typename _Iter_traits::value_type>::type, char8_t>, std::is_same<typename std::remove_const<typename _Iter_traits::value_type>::type, wchar_t>, std::is_same<typename std::remove_const<typename _Iter_traits::value_type>::type, char16_t>, std::is_same<typename std::remove_const<typename _Iter_traits::value_type>::type, char32_t> >, std::is_base_of<std::input_iterator_tag, typename _Iter_traits::iterator_category> > [with _Iter = A; _Iter_traits = std::iterator_traits<A>]'

/opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/fs_path.h:91:5:   required by substitution of 'template<class _Iter> std::filesystem::__cxx11::__detail::__is_path_iter_src<_Iter> std::filesystem::__cxx11::__detail::__is_path_src(_Iter, int) [with _Iter = A]'

/opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/fs_path.h:115:29:   required from 'struct std::filesystem::__cxx11::__detail::__constructible_from<A, void>'

/opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/type_traits:138:12:   required from 'struct std::__and_<std::__not_<std::is_void<A> >, std::filesystem::__cxx11::__detail::__constructible_from<A, void> >'

/opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/type_traits:143:12:   required from 'struct std::__and_<std::__not_<std::is_same<A, std::filesystem::__cxx11::path> >, std::__not_<std::is_void<A> >, std::filesystem::__cxx11::__detail::__constructible_from<A, void> >'

/opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/fs_path.h:119:11:   required by substitution of 'template<class _Tp1, class _Tp2> using _Path = typename std::enable_if<std::__and_<std::__not_<std::is_same<typename std::remove_cv< <template-parameter-1-1> >::type, std::filesystem::__cxx11::path> >, std::__not_<std::is_void<typename std::remove_pointer<_Tp>::type> >, std::filesystem::__cxx11::__detail::__constructible_from<_Tp1, _Tp2> >::value, std::filesystem::__cxx11::path>::type [with _Tp1 = A; _Tp2 = void]'

/opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/fs_path.h:219:7:   required by substitution of 'template<class _Source, class _Require> std::filesystem::__cxx11::path::path(const _Source&, std::filesystem::__cxx11::path::format) [with _Source = A; _Require = <missing>]'

/opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/type_traits:901:30:   required from 'struct std::__is_constructible_impl<A, A>'

/opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/type_traits:906:12:   required from 'struct std::is_constructible<A, A>'

/opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/type_traits:3091:25:   required from 'constexpr const bool std::is_constructible_v<A, A>'

/opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/concepts:139:30:   required from here

/opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/concepts:139:30: error: the value of 'std::is_constructible_v<A, A>' is not usable in a constant expression

  139 |       = destructible<_Tp> && is_constructible_v<_Tp, _Args...>;

      |                              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

In file included from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/move.h:57,

                 from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/nested_exception.h:40,

                 from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/exception:148,

                 from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/stdexcept:38,

                 from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/system_error:41,

                 from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/fs_fwd.h:35,

                 from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/filesystem:44,

                 from <source>:1:

/opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/type_traits:3091:25: note: 'std::is_constructible_v<A, A>' used in its own initializer

 3091 |   inline constexpr bool is_constructible_v =

      |                         ^~~~~~~~~~~~~~~~~~
Comment 5 Jonathan Wakely 2020-03-21 20:22:49 UTC
(In reply to Paco Arjonilla from comment #4)
> There is no reason why an extra constructor would affect the semiregularity
> of a type.

That's not true.

A private or deleted constructor that is a better match for some arguments can affect it.
Comment 6 gcc-bugs 2020-05-12 21:42:03 UTC
It seems that I hit the same issue when making us of ranges:

```c++
#include <filesystem>
#include <ranges>

static_assert(std::input_iterator<int *>);

struct alignment_file_input
{
  alignment_file_input(std::filesystem::path);

  template <typename stream_t>
  alignment_file_input(stream_t);

  int* begin();
  int* end();
};
static_assert(std::ranges::input_range<alignment_file_input>);

int main()
{
  alignment_file_input fin{int{}};

  auto && view = fin | std::views::take(1);
}
```

https://godbolt.org/z/__hw9w
Comment 7 Jonathan Wakely 2020-05-21 00:35:47 UTC
(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.
Comment 8 TC 2020-05-21 01:11:12 UTC
(really from Tim)

This is https://cplusplus.github.io/LWG/issue3420
Comment 9 Jonathan Wakely 2020-05-21 05:57:46 UTC
Thanks, Tim. I'd forgotten about that issue and was about to reinvent the resolution.
Comment 10 Jonathan Wakely 2020-05-21 06:31:07 UTC
*** Bug 95233 has been marked as a duplicate of this bug. ***
Comment 11 GCC Commits 2020-05-21 06:39:07 UTC
The master branch has been updated by Jonathan Wakely <redi@gcc.gnu.org>:

https://gcc.gnu.org/g:f094665d465cdf8903797cc58bea13007e588616

commit r11-541-gf094665d465cdf8903797cc58bea13007e588616
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Thu May 21 07:32:15 2020 +0100

    libstdc++: Avoid constraint recursion with iterator_traits (PR 93983)
    
    Checking whether a filesystem::path constructor argument is an iterator
    requires instantiating std::iterator_traits. In C++20 that checks for
    satisfaction of std::iterator_traits constraints, which checks if the
    type is copyable, which can end up recursing back to the path
    constructor. The fix in LWG 3420 is to reorder the cpp17-iterator
    concept's constraints to check if the type looks vaguely like an
    iterator before checking copyable. That avoids the recursion for types
    which definitely aren't iterators, but isn't foolproof.
    
            PR libstdc++/93983
            * include/bits/iterator_concepts.h (__detail::__cpp17_iterator):
            Reorder constraints to avoid recursion when constructors use
            iterator_traits (LWG 3420).
            * testsuite/24_iterators/customization_points/lwg3420.cc: New test.
Comment 12 GCC Commits 2020-05-21 07:05:19 UTC
The releases/gcc-10 branch has been updated by Jonathan Wakely <redi@gcc.gnu.org>:

https://gcc.gnu.org/g:566ba72126288272607374a32ac646dcd36fe584

commit r10-8163-g566ba72126288272607374a32ac646dcd36fe584
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Thu May 21 07:47:17 2020 +0100

    libstdc++: Avoid constraint recursion with iterator_traits (PR 93983)
    
    Checking whether a filesystem::path constructor argument is an iterator
    requires instantiating std::iterator_traits. In C++20 that checks for
    satisfaction of std::iterator_traits constraints, which checks if the
    type is copyable, which can end up recursing back to the path
    constructor. The fix in LWG 3420 is to reorder the cpp17-iterator
    concept's constraints to check if the type looks vaguely like an
    iterator before checking copyable. That avoids the recursion for types
    which definitely aren't iterators, but isn't foolproof.
    
    Backport from mainline
    2020-05-21  Jonathan Wakely  <jwakely@redhat.com>
    
            PR libstdc++/93983
            * include/bits/iterator_concepts.h (__detail::__cpp17_iterator):
            Reorder constraints to avoid recursion when constructors use
            iterator_traits (LWG 3420).
            * testsuite/24_iterators/customization_points/lwg3420.cc: New test.
Comment 13 Jonathan Wakely 2020-05-21 07:05:45 UTC
Fixed for 10.2