[libc++] Implement LWG3435 (constraints on reverse_iterator and move_iterator)
authorLouis Dionne <ldionne.2@gmail.com>
Thu, 3 Jun 2021 18:14:57 +0000 (14:14 -0400)
committerLouis Dionne <ldionne.2@gmail.com>
Thu, 3 Jun 2021 19:49:41 +0000 (15:49 -0400)
libcxx/docs/Cxx2bStatusIssuesStatus.csv
libcxx/include/iterator
libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/ctor.convert.LWG3435.verify.cpp [moved from libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/convert.compile.fail.cpp with 50% similarity]
libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/ctor.iter.explicit.verify.cpp [moved from libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/iter.compile.fail.cpp with 63% similarity]
libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op=/assign.LWG3435.verify.cpp [new file with mode: 0644]
libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op=/move_iterator.compile.fail.cpp [deleted file]
libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op=/move_iterator.pass.cpp
libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.cons/assign.LWG3435.verify.cpp [new file with mode: 0644]
libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.cons/ctor.reverse_iterator.LWG3435.verify.cpp [new file with mode: 0644]

index 2e4f416..1535640 100644 (file)
@@ -6,7 +6,7 @@
 "`3211 <https://wg21.link/LWG3211>`__","``std::tuple<>`` should be trivially constructible","November 2020","",""
 "`3236 <https://wg21.link/LWG3236>`__","Random access iterator requirements lack limiting relational operators domain to comparing those from the same range","November 2020","",""
 "`3265 <https://wg21.link/LWG3265>`__","``move_iterator``'s conversions are more broken after P1207","November 2020","Fixed by `LWG3435 <https://wg21.link/LWG3435>`__",""
-"`3435 <https://wg21.link/LWG3435>`__","``three_way_comparable_with<reverse_iterator<int*>, reverse_iterator<const int*>>``","November 2020","",""
+"`3435 <https://wg21.link/LWG3435>`__","``three_way_comparable_with<reverse_iterator<int*>, reverse_iterator<const int*>>``","November 2020","|Complete|","13.0"
 "`3432 <https://wg21.link/LWG3432>`__","Missing requirement for comparison_category","November 2020","",""
 "`3447 <https://wg21.link/LWG3447>`__","Deduction guides for ``take_view`` and ``drop_view`` have different constraints","November 2020","",""
 "`3450 <https://wg21.link/LWG3450>`__","The const overloads of ``take_while_view::begin/end`` are underconstrained","November 2020","",""
index 9d9a553..0661714 100644 (file)
@@ -669,27 +669,53 @@ public:
 #ifndef _LIBCPP_ABI_NO_ITERATOR_BASES
     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
     reverse_iterator() : __t(), current() {}
+
     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
     explicit reverse_iterator(_Iter __x) : __t(__x), current(__x) {}
-    template <class _Up>
-        _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
-        reverse_iterator(const reverse_iterator<_Up>& __u) : __t(__u.base()), current(__u.base()) {}
-    template <class _Up>
-        _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
-        reverse_iterator& operator=(const reverse_iterator<_Up>& __u)
-            { __t = current = __u.base(); return *this; }
+
+    template <class _Up, class = _EnableIf<
+        !is_same<_Up, _Iter>::value && is_convertible<_Up const&, _Iter>::value
+    > >
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
+    reverse_iterator(const reverse_iterator<_Up>& __u)
+        : __t(__u.base()), current(__u.base())
+    { }
+
+    template <class _Up, class = _EnableIf<
+        !is_same<_Up, _Iter>::value &&
+        is_convertible<_Up const&, _Iter>::value &&
+        is_assignable<_Up const&, _Iter>::value
+    > >
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
+    reverse_iterator& operator=(const reverse_iterator<_Up>& __u) {
+        __t = current = __u.base();
+        return *this;
+    }
 #else
     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
     reverse_iterator() : current() {}
+
     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
     explicit reverse_iterator(_Iter __x) : current(__x) {}
-    template <class _Up>
-        _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
-        reverse_iterator(const reverse_iterator<_Up>& __u) : current(__u.base()) {}
-    template <class _Up>
-        _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
-        reverse_iterator& operator=(const reverse_iterator<_Up>& __u)
-            { current = __u.base(); return *this; }
+
+    template <class _Up, class = _EnableIf<
+        !is_same<_Up, _Iter>::value && is_convertible<_Up const&, _Iter>::value
+    > >
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
+    reverse_iterator(const reverse_iterator<_Up>& __u)
+        : current(__u.base())
+    { }
+
+    template <class _Up, class = _EnableIf<
+        !is_same<_Up, _Iter>::value &&
+        is_convertible<_Up const&, _Iter>::value &&
+        is_assignable<_Up const&, _Iter>::value
+    > >
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
+    reverse_iterator& operator=(const reverse_iterator<_Up>& __u) {
+        current = __u.base();
+        return *this;
+    }
 #endif
     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
     _Iter base() const {return current;}
@@ -1217,11 +1243,27 @@ public:
 
     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
     move_iterator() : __i() {}
+
     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
     explicit move_iterator(_Iter __x) : __i(__x) {}
-    template <class _Up>
-      _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
-      move_iterator(const move_iterator<_Up>& __u) : __i(__u.base()) {}
+
+    template <class _Up, class = _EnableIf<
+        !is_same<_Up, _Iter>::value && is_convertible<_Up const&, _Iter>::value
+    > >
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
+    move_iterator(const move_iterator<_Up>& __u) : __i(__u.base()) {}
+
+    template <class _Up, class = _EnableIf<
+        !is_same<_Up, _Iter>::value &&
+        is_convertible<_Up const&, _Iter>::value &&
+        is_assignable<_Iter&, _Up const&>::value
+    > >
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
+    move_iterator& operator=(const move_iterator<_Up>& __u) {
+        __i = __u.base();
+        return *this;
+    }
+
     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 _Iter base() const {return __i;}
     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
     reference operator*() const { return static_cast<reference>(*__i); }
@@ -6,37 +6,20 @@
 //
 //===----------------------------------------------------------------------===//
 
-// GCC 5 does not evaluate static assertions dependent on a template parameter.
-// UNSUPPORTED: gcc-5
-
 // <iterator>
 
 // move_iterator
 
 // template <class U>
-//   requires HasConstructor<Iter, const U&>
-//   move_iterator(const move_iterator<U> &u);
-
-// test requires
+//  requires !same_as<U, Iter> && convertible_to<const U&, Iter>
+// move_iterator(const move_iterator<U> &u);
 
 #include <iterator>
 
-template <class It, class U>
-void
-test(U u)
-{
-    std::move_iterator<U> r2(u);
-    std::move_iterator<It> r1 = r2;
-}
-
-struct base {};
-struct derived {};
-
-int main(int, char**)
-{
-    derived d;
-
-    test<base*>(&d);
+struct Base { };
+struct Derived : Base { };
 
-  return 0;
+void test() {
+    std::move_iterator<Base*> base;
+    std::move_iterator<Derived*> derived(base); // expected-error {{no matching constructor for initialization of 'std::move_iterator<Derived *>'}}
 }
@@ -6,30 +6,18 @@
 //
 //===----------------------------------------------------------------------===//
 
-// GCC 5 does not evaluate static assertions dependent on a template parameter.
-// UNSUPPORTED: gcc-5
-
 // <iterator>
 
 // move_iterator
 
 // explicit move_iterator(Iter );
 
-// test explicit
+// test explicitness
 
 #include <iterator>
 
-template <class It>
-void
-test(It i)
-{
-    std::move_iterator<It> r = i;
-}
-
-int main(int, char**)
-{
-    char s[] = "123";
-    test(s);
-
-  return 0;
+int main(int, char**) {
+    char const* it = "";
+    std::move_iterator<char const*> r = it; // expected-error{{no viable conversion from 'const char *' to 'std::move_iterator<const char *>'}}
+    return 0;
 }
diff --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op=/assign.LWG3435.verify.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op=/assign.LWG3435.verify.cpp
new file mode 100644 (file)
index 0000000..2bdfadf
--- /dev/null
@@ -0,0 +1,26 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <iterator>
+
+// move_iterator
+
+// template <class U>
+//  requires !same_as<U, Iter> && convertible_to<const U&, Iter> && assignable_from<Iter&, const U&>
+// move_iterator& operator=(const move_iterator<U>& u);
+
+#include <iterator>
+
+struct Base { };
+struct Derived : Base { };
+
+void test() {
+    std::move_iterator<Base*> base;
+    std::move_iterator<Derived*> derived;
+    derived = base; // expected-error {{no viable overloaded '='}}
+}
diff --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op=/move_iterator.compile.fail.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op=/move_iterator.compile.fail.cpp
deleted file mode 100644 (file)
index fafe706..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// GCC 5 does not evaluate static assertions dependent on a template parameter.
-// UNSUPPORTED: gcc-5
-
-// <iterator>
-
-// move_iterator
-
-// template <class U>
-//   requires HasAssign<Iter, const U&>
-//   move_iterator&
-//   operator=(const move_iterator<U>& u);
-
-// test requires
-
-#include <iterator>
-
-template <class It, class U>
-void
-test(U u)
-{
-    const std::move_iterator<U> r2(u);
-    std::move_iterator<It> r1;
-    r1 = r2;
-}
-
-struct base {};
-struct derived {};
-
-int main(int, char**)
-{
-    derived d;
-    test<base*>(&d);
-
-  return 0;
-}
index a847192..9b54414 100644 (file)
@@ -29,7 +29,7 @@ test(U u)
 {
     const std::move_iterator<U> r2(u);
     std::move_iterator<It> r1;
-    std::move_iterator<It>& rr = r1 = r2;
+    std::move_iterator<It>& rr = (r1 = r2);
     assert(r1.base() == u);
     assert(&rr == &r1);
 }
diff --git a/libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.cons/assign.LWG3435.verify.cpp b/libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.cons/assign.LWG3435.verify.cpp
new file mode 100644 (file)
index 0000000..3b3c7cb
--- /dev/null
@@ -0,0 +1,26 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <iterator>
+
+// reverse_iterator
+
+// template <class U>
+//  requires !same_as<U, Iter> && convertible_to<const U&, Iter> && assignable_from<Iter&, const U&>
+// reverse_iterator& operator=(const reverse_iterator<U>& u);
+
+#include <iterator>
+
+struct Base { };
+struct Derived : Base { };
+
+void test() {
+    std::reverse_iterator<Base*> base;
+    std::reverse_iterator<Derived*> derived;
+    derived = base; // expected-error {{no viable overloaded '='}}
+}
diff --git a/libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.cons/ctor.reverse_iterator.LWG3435.verify.cpp b/libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.cons/ctor.reverse_iterator.LWG3435.verify.cpp
new file mode 100644 (file)
index 0000000..6082809
--- /dev/null
@@ -0,0 +1,25 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <iterator>
+
+// reverse_iterator
+
+// template <class U>
+//  requires !same_as<U, Iter> && convertible_to<const U&, Iter>
+// reverse_iterator(const reverse_iterator<U> &);
+
+#include <iterator>
+
+struct Base { };
+struct Derived : Base { };
+
+void test() {
+    std::reverse_iterator<Base*> base;
+    std::reverse_iterator<Derived*> derived(base); // expected-error {{no matching constructor for initialization of 'std::reverse_iterator<Derived *>'}}
+}