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

This commit is contained in:
Louis Dionne 2021-06-03 14:14:57 -04:00
parent 1dff8637b1
commit e4d3a993c2
9 changed files with 151 additions and 104 deletions

View 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","",""

1 Issue # Issue Name Meeting Status First released version
6 `3211 <https://wg21.link/LWG3211>`__ ``std::tuple<>`` should be trivially constructible November 2020
7 `3236 <https://wg21.link/LWG3236>`__ Random access iterator requirements lack limiting relational operators domain to comparing those from the same range November 2020
8 `3265 <https://wg21.link/LWG3265>`__ ``move_iterator``'s conversions are more broken after P1207 November 2020 Fixed by `LWG3435 <https://wg21.link/LWG3435>`__
9 `3435 <https://wg21.link/LWG3435>`__ ``three_way_comparable_with<reverse_iterator<int*>, reverse_iterator<const int*>>`` November 2020 |Complete| 13.0
10 `3432 <https://wg21.link/LWG3432>`__ Missing requirement for comparison_category November 2020
11 `3447 <https://wg21.link/LWG3447>`__ Deduction guides for ``take_view`` and ``drop_view`` have different constraints November 2020
12 `3450 <https://wg21.link/LWG3450>`__ The const overloads of ``take_while_view::begin/end`` are underconstrained November 2020

View 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); }

View File

@ -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);
return 0;
struct Base { };
struct Derived : Base { };
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 *>'}}
}

View File

@ -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;
}

View File

@ -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 '='}}
}

View File

@ -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;
}

View 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);
}

View File

@ -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 '='}}
}

View File

@ -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 *>'}}
}