libstdc++: Fix concept checks for iterators
authorJonathan Wakely <jwakely@redhat.com>
Fri, 24 Sep 2021 12:56:33 +0000 (13:56 +0100)
committerJonathan Wakely <jwakely@redhat.com>
Tue, 28 Sep 2021 19:22:51 +0000 (20:22 +0100)
This adds some additional checks the the C++98-style concept checks for
iterators, and removes some bogus checks for mutable iterators. Instead
of requiring that the result of dereferencing a mutable iterator is
assignable (which is a property of the value type, not required for the
iterator) check that the reference type is a non-const reference to the
value type.

Signed-off-by: Jonathan Wakely <jwakely@redhat.com>
libstdc++-v3/ChangeLog:

* include/bits/boost_concept_check.h (_ForwardIteratorConcept)
(_BidirectionalIteratorConcept, _RandomAccessIteratorConcept):
Check result types of iterator operations.
(_Mutable_ForwardIteratorConcept): Check that iterator's
reference type is a reference to its value type.
(_Mutable_BidirectionalIteratorConcept): Do not require the
value type to be assignable.
(_Mutable_RandomAccessIteratorConcept): Likewise.
* testsuite/24_iterators/operations/prev_neg.cc: Adjust dg-error
line number.

libstdc++-v3/include/bits/boost_concept_check.h
libstdc++-v3/testsuite/24_iterators/operations/prev_neg.cc

index ba36c24..71c99c1 100644 (file)
 #include <bits/c++config.h>
 #include <bits/stl_iterator_base_types.h>    // for traits and tags
 
+namespace std  _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+  struct _Bit_iterator;
+  struct _Bit_const_iterator;
+_GLIBCXX_END_NAMESPACE_VERSION
+}
+
 namespace __gnu_cxx _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
@@ -470,6 +478,52 @@ struct _Aux_require_same<_Tp,_Tp> { typedef _Tp _Type; };
     _ValueT __val() const;
   };
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-variable"
+
+  template <class _Tp>
+  struct _ForwardIteratorReferenceConcept
+  {
+    void __constraints() {
+#if __cplusplus >= 201103L
+      typedef typename std::iterator_traits<_Tp>::reference _Ref;
+      static_assert(std::is_reference<_Ref>::value,
+         "reference type of a forward iterator must be a real reference");
+#endif
+    }
+  };
+
+  template <class _Tp>
+  struct _Mutable_ForwardIteratorReferenceConcept
+  {
+    void __constraints() {
+      typedef typename std::iterator_traits<_Tp>::reference _Ref;
+      typedef typename std::iterator_traits<_Tp>::value_type _Val;
+      __function_requires< _SameTypeConcept<_Ref, _Val&> >();
+    }
+  };
+
+  // vector<bool>::iterator is not a real forward reference, but pretend it is.
+  template <>
+  struct _ForwardIteratorReferenceConcept<std::_Bit_iterator>
+  {
+    void __constraints() { }
+  };
+
+  // vector<bool>::iterator is not a real forward reference, but pretend it is.
+  template <>
+  struct _Mutable_ForwardIteratorReferenceConcept<std::_Bit_iterator>
+  {
+    void __constraints() { }
+  };
+
+  // And vector<bool>::const iterator too.
+  template <>
+  struct _ForwardIteratorReferenceConcept<std::_Bit_const_iterator>
+  {
+    void __constraints() { }
+  };
+
   template <class _Tp>
   struct _ForwardIteratorConcept
   {
@@ -479,8 +533,12 @@ struct _Aux_require_same<_Tp,_Tp> { typedef _Tp _Type; };
       __function_requires< _ConvertibleConcept<
         typename std::iterator_traits<_Tp>::iterator_category,
         std::forward_iterator_tag> >();
+      __function_requires< _ForwardIteratorReferenceConcept<_Tp> >();
+      _Tp& __j = ++__i;
+      const _Tp& __k = __i++;
       typedef typename std::iterator_traits<_Tp>::reference _Ref;
-      _Ref __r _IsUnused = *__i;
+      _Ref __r = *__k;
+      _Ref __r2 = *__i++;
     }
     _Tp __i;
   };
@@ -490,7 +548,9 @@ struct _Aux_require_same<_Tp,_Tp> { typedef _Tp _Type; };
   {
     void __constraints() {
       __function_requires< _ForwardIteratorConcept<_Tp> >();
-      *__i++ = *__i;                    // require postincrement and assignment
+      typedef typename std::iterator_traits<_Tp>::reference _Ref;
+      typedef typename std::iterator_traits<_Tp>::value_type _Val;
+      __function_requires< _Mutable_ForwardIteratorReferenceConcept<_Tp> >();
     }
     _Tp __i;
   };
@@ -503,8 +563,10 @@ struct _Aux_require_same<_Tp,_Tp> { typedef _Tp _Type; };
       __function_requires< _ConvertibleConcept<
         typename std::iterator_traits<_Tp>::iterator_category,
         std::bidirectional_iterator_tag> >();
-      --__i;                            // require predecrement operator
-      __i--;                            // require postdecrement operator
+      _Tp& __j = --__i;                 // require predecrement operator
+      const _Tp& __k = __i--;           // require postdecrement operator
+      typedef typename std::iterator_traits<_Tp>::reference _Ref;
+      _Ref __r = *__j--;
     }
     _Tp __i;
   };
@@ -515,7 +577,6 @@ struct _Aux_require_same<_Tp,_Tp> { typedef _Tp _Type; };
     void __constraints() {
       __function_requires< _BidirectionalIteratorConcept<_Tp> >();
       __function_requires< _Mutable_ForwardIteratorConcept<_Tp> >();
-      *__i-- = *__i;                    // require postdecrement and assignment
     }
     _Tp __i;
   };
@@ -530,16 +591,15 @@ struct _Aux_require_same<_Tp,_Tp> { typedef _Tp _Type; };
       __function_requires< _ConvertibleConcept<
         typename std::iterator_traits<_Tp>::iterator_category,
         std::random_access_iterator_tag> >();
-      // ??? We don't use _Ref, are we just checking for "referenceability"?
       typedef typename std::iterator_traits<_Tp>::reference _Ref;
 
-      __i += __n;                       // require assignment addition operator
+      _Tp& __j = __i += __n;            // require assignment addition operator
       __i = __i + __n; __i = __n + __i; // require addition with difference type
-      __i -= __n;                       // require assignment subtraction op
+      _Tp& __k = __i -= __n;            // require assignment subtraction op
       __i = __i - __n;                  // require subtraction with
                                         //            difference type
       __n = __i - __j;                  // require difference operator
-      (void)__i[__n];                   // require element access operator
+      _Ref __r = __i[__n];              // require element access operator
     }
     _Tp __a, __b;
     _Tp __i, __j;
@@ -552,12 +612,13 @@ struct _Aux_require_same<_Tp,_Tp> { typedef _Tp _Type; };
     void __constraints() {
       __function_requires< _RandomAccessIteratorConcept<_Tp> >();
       __function_requires< _Mutable_BidirectionalIteratorConcept<_Tp> >();
-      __i[__n] = *__i;                  // require element access and assignment
     }
     _Tp __i;
     typename std::iterator_traits<_Tp>::difference_type __n;
   };
 
+#pragma GCC diagnostic pop
+
   //===========================================================================
   // Container Concepts
 
index cafafc4..d224919 100644 (file)
@@ -38,5 +38,5 @@ test02()
 {
   const Y array[1] = { };
   (void) std::prev(array + 1);
-  // { dg-error "forward_iterator" "" { target *-*-* } 223 }
+  // { dg-error "forward_iterator" "" { target *-*-* } 231 }
 }