This proposed patch means that span<T,E> is not an associated type of
span<T,E>::iterator, which means that we won't try to complete T when
doing ADL in the constraints for const_iterator. This makes it more
reliable to use std::span<IncompleteType>.

See https://github.com/llvm/llvm-project/issues/107215 for more info on
the problem and the constraint recursion that can happen.

Does this seem worthwhile?

It would be an ABI change to do something like this for other uses of
__normal_iterator, such as std::vector and std::string. But std::span is
a C++20 feature so still experimental. I think we should consider this
for other new uses of __normal_iterator too, e.g. in <stacktrace>.

-- >8 --

libstdc++-v3/ChangeLog:

        * include/std/span (span::__iter_tag): Declare nested type.
        (span::iterator): Use __iter_tag as second template argument.
---
 libstdc++-v3/include/std/span | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/span b/libstdc++-v3/include/std/span
index 00fc5279152..b7392a0500e 100644
--- a/libstdc++-v3/include/std/span
+++ b/libstdc++-v3/include/std/span
@@ -123,6 +123,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        using __is_compatible_ref
          = __is_array_convertible<_Type, remove_reference_t<_Ref>>;
 
+      // Nested type so that _Type is not an associated class of iterator.
+      struct __iter_tag;
+
     public:
       // member types
       using element_type           = _Type;
@@ -133,7 +136,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       using const_pointer          = const _Type*;
       using reference              = element_type&;
       using const_reference        = const element_type&;
-      using iterator = __gnu_cxx::__normal_iterator<pointer, span>;
+      using iterator = __gnu_cxx::__normal_iterator<pointer, __iter_tag>;
       using reverse_iterator       = std::reverse_iterator<iterator>;
 #if __cplusplus > 202002L
       using const_iterator         = std::const_iterator<iterator>;
-- 
2.46.0

Reply via email to