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

commit r14-11414-ga3c01af5e34801aaf65ba76f4afce753e443a99c
Author: Patrick Palka <ppa...@redhat.com>
Date:   Fri Feb 28 09:39:57 2025 -0500

    libstdc++: Fix constraint recursion in basic_const_iterator relops 
[PR112490]
    
    Here for
    
      using RCI = reverse_iterator<basic_const_iterator<vector<int>::iterator>>
      static_assert(std::totally_ordered<RCI>);
    
    we effectively need to check the requirement
    
      requires (RCI x) { x RELOP x; }  for each RELOP in {<, >, <=, >=}
    
    which we expect to be straightforwardly satisfied by reverse_iterator's
    namespace-scope relops.  But due to ADL we find ourselves also
    considering the basic_const_iterator relop friends, which before CWG
    2369 would be quickly discarded since RCI clearly isn't convertible to
    basic_const_iterator.  After CWG 2369 though we must first check these
    relops' constraints (with _It = vector<int>::iterator and _It2 = RCI),
    which entails checking totally_ordered<RCI> recursively.
    
    This patch fixes this by turning the problematic non-dependent function
    parameters of type basic_const_iterator<_It> into dependent ones of
    type basic_const_iterator<_It3> where _It3 is constrained to match _It.
    Thus the basic_const_iterator relop friends now get quickly discarded
    during deduction and before the constraint check if the second operand
    isn't a specialization of basic_const_iterator (or derived from one)
    like before CWG 2369.
    
            PR libstdc++/112490
    
    libstdc++-v3/ChangeLog:
    
            * include/bits/stl_iterator.h (basic_const_iterator::operator<):
            Replace non-dependent basic_const_iterator function parameter with
            a dependent one of type basic_const_iterator<_It3> where _It3
            matches _It.
            (basic_const_iterator::operator>): Likewise.
            (basic_const_iterator::operator<=): Likewise.
            (basic_const_iterator::operator>=): Likewise.
            * testsuite/24_iterators/const_iterator/112490.cc: New test.
    
    Reviewed-by: Jonathan Wakely <jwak...@redhat.com>
    (cherry picked from commit 4342c50ca84ae5448c0128c52120f4fe9005f203)

Diff:
---
 libstdc++-v3/include/bits/stl_iterator.h                 | 16 ++++++++--------
 .../testsuite/24_iterators/const_iterator/112490.cc      | 12 ++++++++++++
 2 files changed, 20 insertions(+), 8 deletions(-)

diff --git a/libstdc++-v3/include/bits/stl_iterator.h 
b/libstdc++-v3/include/bits/stl_iterator.h
index fff5f4015330..5e1fe30135ef 100644
--- a/libstdc++-v3/include/bits/stl_iterator.h
+++ b/libstdc++-v3/include/bits/stl_iterator.h
@@ -2865,30 +2865,30 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        && three_way_comparable_with<_It, _It2>
       { return _M_current <=> __y; }
 
-    template<__detail::__not_a_const_iterator _It2>
+    template<__detail::__not_a_const_iterator _It2, same_as<_It> _It3>
       friend constexpr bool
-      operator<(const _It2& __x, const basic_const_iterator& __y)
+      operator<(const _It2& __x, const basic_const_iterator<_It3>& __y)
       noexcept(noexcept(__x < __y._M_current))
       requires random_access_iterator<_It> && totally_ordered_with<_It, _It2>
       { return __x < __y._M_current; }
 
-    template<__detail::__not_a_const_iterator _It2>
+    template<__detail::__not_a_const_iterator _It2, same_as<_It> _It3>
       friend constexpr bool
-      operator>(const _It2& __x, const basic_const_iterator& __y)
+      operator>(const _It2& __x, const basic_const_iterator<_It3>& __y)
       noexcept(noexcept(__x > __y._M_current))
       requires random_access_iterator<_It> && totally_ordered_with<_It, _It2>
       { return __x > __y._M_current; }
 
-    template<__detail::__not_a_const_iterator _It2>
+    template<__detail::__not_a_const_iterator _It2, same_as<_It> _It3>
       friend constexpr bool
-      operator<=(const _It2& __x, const basic_const_iterator& __y)
+      operator<=(const _It2& __x, const basic_const_iterator<_It3>& __y)
       noexcept(noexcept(__x <= __y._M_current))
       requires random_access_iterator<_It> && totally_ordered_with<_It, _It2>
       { return __x <= __y._M_current; }
 
-    template<__detail::__not_a_const_iterator _It2>
+    template<__detail::__not_a_const_iterator _It2, same_as<_It> _It3>
       friend constexpr bool
-      operator>=(const _It2& __x, const basic_const_iterator& __y)
+      operator>=(const _It2& __x, const basic_const_iterator<_It3>& __y)
       noexcept(noexcept(__x >= __y._M_current))
       requires random_access_iterator<_It> && totally_ordered_with<_It, _It2>
       { return __x >= __y._M_current; }
diff --git a/libstdc++-v3/testsuite/24_iterators/const_iterator/112490.cc 
b/libstdc++-v3/testsuite/24_iterators/const_iterator/112490.cc
new file mode 100644
index 000000000000..9bb154847cff
--- /dev/null
+++ b/libstdc++-v3/testsuite/24_iterators/const_iterator/112490.cc
@@ -0,0 +1,12 @@
+// { dg-do compile { target c++23 } }
+
+// PR libstdc++/112490 - infinite meta error in
+// reverse_iterator<basic_const_iterator<vector<int>::iterator>>
+
+#include <iterator>
+#include <vector>
+
+using I = std::vector<int>::iterator;
+using CI = std::basic_const_iterator<I>;
+using RCI = std::reverse_iterator<CI>;
+static_assert(std::totally_ordered<RCI>);

Reply via email to