[libcxx-commits] [libcxx] 6938270 - [libcxx] Fix enable_if condition of std::reverse_iterator::operator=
Mikhail Maltsev via libcxx-commits
libcxx-commits at lists.llvm.org
Mon Nov 15 05:09:40 PST 2021
Author: Mikhail Maltsev
Date: 2021-11-15T13:08:36Z
New Revision: 6938270fa68d2242999802fdc306dc60326df020
URL: https://github.com/llvm/llvm-project/commit/6938270fa68d2242999802fdc306dc60326df020
DIFF: https://github.com/llvm/llvm-project/commit/6938270fa68d2242999802fdc306dc60326df020.diff
LOG: [libcxx] Fix enable_if condition of std::reverse_iterator::operator=
The template std::is_assignable<T, U> checks that T is assignable from
U. Hence, the order of operands in the instantiation of
std::is_assignable in the std::reverse_iterator::operator= condition
should be reversed.
This issue remained unnoticed because std::reverse_iterator has an
implicit conversion constructor. This patch adds a test to check that
the assignment operator is used directly, without any implicit
conversions. The patch also adds a similar test for
std::move_iterator.
Reviewed By: Quuxplusone, ldionne, #libc
Differential Revision: https://reviews.llvm.org/D113417
Added:
Modified:
libcxx/include/__iterator/reverse_iterator.h
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.pass.cpp
Removed:
################################################################################
diff --git a/libcxx/include/__iterator/reverse_iterator.h b/libcxx/include/__iterator/reverse_iterator.h
index fad9bc175b0c..f7a948950df2 100644
--- a/libcxx/include/__iterator/reverse_iterator.h
+++ b/libcxx/include/__iterator/reverse_iterator.h
@@ -86,7 +86,7 @@ _LIBCPP_SUPPRESS_DEPRECATED_POP
template <class _Up, class = __enable_if_t<
!is_same<_Up, _Iter>::value &&
is_convertible<_Up const&, _Iter>::value &&
- is_assignable<_Up const&, _Iter>::value
+ is_assignable<_Iter, _Up const&>::value
> >
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
reverse_iterator& operator=(const reverse_iterator<_Up>& __u) {
@@ -111,7 +111,7 @@ _LIBCPP_SUPPRESS_DEPRECATED_POP
template <class _Up, class = __enable_if_t<
!is_same<_Up, _Iter>::value &&
is_convertible<_Up const&, _Iter>::value &&
- is_assignable<_Up const&, _Iter>::value
+ is_assignable<_Iter, _Up const&>::value
> >
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
reverse_iterator& operator=(const reverse_iterator<_Up>& __u) {
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 9b5441431aa6..c6dcef9a0d19 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
@@ -37,6 +37,39 @@ test(U u)
struct Base {};
struct Derived : Base {};
+struct ToIter {
+ typedef std::forward_iterator_tag iterator_category;
+ typedef char *pointer;
+ typedef char &reference;
+ typedef char value_type;
+ typedef value_type
diff erence_type;
+
+ explicit TEST_CONSTEXPR_CXX17 ToIter() : m_value(0) {}
+ TEST_CONSTEXPR_CXX17 ToIter(const ToIter &src) : m_value(src.m_value) {}
+ // Intentionally not defined, must not be called.
+ ToIter(char *src);
+ TEST_CONSTEXPR_CXX17 ToIter &operator=(char *src) {
+ m_value = src;
+ return *this;
+ }
+ TEST_CONSTEXPR_CXX17 ToIter &operator=(const ToIter &src) {
+ m_value = src.m_value;
+ return *this;
+ }
+ char *m_value;
+};
+
+TEST_CONSTEXPR_CXX17 bool test_conv_assign()
+{
+ char c = '\0';
+ char *fi = &c;
+ const std::move_iterator<char *> move_fi(fi);
+ std::move_iterator<ToIter> move_ti;
+ move_ti = move_fi;
+ assert(move_ti.base().m_value == fi);
+ return true;
+}
+
int main(int, char**)
{
Derived d;
@@ -46,6 +79,7 @@ int main(int, char**)
test<bidirectional_iterator<Base*> >(bidirectional_iterator<Derived*>(&d));
test<random_access_iterator<const Base*> >(random_access_iterator<Derived*>(&d));
test<Base*>(&d);
+ test_conv_assign();
#if TEST_STD_VER > 14
{
using BaseIter = std::move_iterator<const Base *>;
@@ -54,6 +88,7 @@ int main(int, char**)
constexpr DerivedIter it1 = std::make_move_iterator(p);
constexpr BaseIter it2 = (BaseIter{nullptr} = it1);
static_assert(it2.base() == p, "");
+ static_assert(test_conv_assign(), "");
}
#endif
diff --git a/libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.cons/assign.pass.cpp b/libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.cons/assign.pass.cpp
index 95c6bde040ab..be7f01c16810 100644
--- a/libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.cons/assign.pass.cpp
+++ b/libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.cons/assign.pass.cpp
@@ -31,11 +31,41 @@ TEST_CONSTEXPR_CXX17 void test(U u) {
struct Base { };
struct Derived : Base { };
+struct ToIter {
+ typedef std::bidirectional_iterator_tag iterator_category;
+ typedef char *pointer;
+ typedef char &reference;
+ typedef char value_type;
+ typedef value_type
diff erence_type;
+
+ explicit TEST_CONSTEXPR_CXX17 ToIter() : m_value(0) {}
+ TEST_CONSTEXPR_CXX17 ToIter(const ToIter &src) : m_value(src.m_value) {}
+ // Intentionally not defined, must not be called.
+ ToIter(char *src);
+ TEST_CONSTEXPR_CXX17 ToIter &operator=(char *src) {
+ m_value = src;
+ return *this;
+ }
+ TEST_CONSTEXPR_CXX17 ToIter &operator=(const ToIter &src) {
+ m_value = src.m_value;
+ return *this;
+ }
+ char *m_value;
+};
+
TEST_CONSTEXPR_CXX17 bool tests() {
Derived d;
test<bidirectional_iterator<Base*> >(bidirectional_iterator<Derived*>(&d));
test<random_access_iterator<const Base*> >(random_access_iterator<Derived*>(&d));
test<Base*>(&d);
+
+ char c = '\0';
+ char *fi = &c;
+ const std::reverse_iterator<char *> rev_fi(fi);
+ std::reverse_iterator<ToIter> rev_ti;
+ rev_ti = rev_fi;
+ assert(rev_ti.base().m_value == fi);
+
return true;
}
More information about the libcxx-commits
mailing list