[libcxx-commits] [libcxx] e4d3a99 - [libc++] Implement LWG3435 (constraints on reverse_iterator and move_iterator)

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Thu Jun 3 12:50:07 PDT 2021


Author: Louis Dionne
Date: 2021-06-03T15:49:41-04:00
New Revision: e4d3a993c2675f46cbe99acd1bf6e6d39d9c1aee

URL: https://github.com/llvm/llvm-project/commit/e4d3a993c2675f46cbe99acd1bf6e6d39d9c1aee
DIFF: https://github.com/llvm/llvm-project/commit/e4d3a993c2675f46cbe99acd1bf6e6d39d9c1aee.diff

LOG: [libc++] Implement LWG3435 (constraints on reverse_iterator and move_iterator)

Added: 
    libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/ctor.convert.LWG3435.verify.cpp
    libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/ctor.iter.explicit.verify.cpp
    libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op=/assign.LWG3435.verify.cpp
    libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.cons/assign.LWG3435.verify.cpp
    libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.cons/ctor.reverse_iterator.LWG3435.verify.cpp

Modified: 
    libcxx/docs/Cxx2bStatusIssuesStatus.csv
    libcxx/include/iterator
    libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op=/move_iterator.pass.cpp

Removed: 
    libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/convert.compile.fail.cpp
    libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/iter.compile.fail.cpp
    libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op=/move_iterator.compile.fail.cpp


################################################################################
diff  --git a/libcxx/docs/Cxx2bStatusIssuesStatus.csv b/libcxx/docs/Cxx2bStatusIssuesStatus.csv
index 2e4f416e9ecff..15356409a0356 100644
--- a/libcxx/docs/Cxx2bStatusIssuesStatus.csv
+++ b/libcxx/docs/Cxx2bStatusIssuesStatus.csv
@@ -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 
diff erent constraints","November 2020","",""
 "`3450 <https://wg21.link/LWG3450>`__","The const overloads of ``take_while_view::begin/end`` are underconstrained","November 2020","",""

diff  --git a/libcxx/include/iterator b/libcxx/include/iterator
index 9d9a5532a2c63..06617146da8f8 100644
--- a/libcxx/include/iterator
+++ b/libcxx/include/iterator
@@ -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); }

diff  --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/convert.compile.fail.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/ctor.convert.LWG3435.verify.cpp
similarity index 50%
rename from libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/convert.compile.fail.cpp
rename to libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/ctor.convert.LWG3435.verify.cpp
index 4e60adc689f09..7ef5655b26706 100644
--- a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/convert.compile.fail.cpp
+++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/ctor.convert.LWG3435.verify.cpp
@@ -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 *>'}}
 }

diff  --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/iter.compile.fail.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/ctor.iter.explicit.verify.cpp
similarity index 63%
rename from libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/iter.compile.fail.cpp
rename to libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/ctor.iter.explicit.verify.cpp
index 1dd9813d78608..b14111555966e 100644
--- a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/iter.compile.fail.cpp
+++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/ctor.iter.explicit.verify.cpp
@@ -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
index 0000000000000..2bdfadf02decc
--- /dev/null
+++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op=/assign.LWG3435.verify.cpp
@@ -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
index fafe70647b667..0000000000000
--- a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op=/move_iterator.compile.fail.cpp
+++ /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;
-}

diff  --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op=/move_iterator.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op=/move_iterator.pass.cpp
index a847192ef6005..9b5441431aa68 100644
--- a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op=/move_iterator.pass.cpp
+++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op=/move_iterator.pass.cpp
@@ -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
index 0000000000000..3b3c7cb671457
--- /dev/null
+++ b/libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.cons/assign.LWG3435.verify.cpp
@@ -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
index 0000000000000..6082809b7b1bd
--- /dev/null
+++ b/libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.cons/ctor.reverse_iterator.LWG3435.verify.cpp
@@ -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 *>'}}
+}


        


More information about the libcxx-commits mailing list