From 4118858b4e4d072ac2ceef6cbc52088438781f39 Mon Sep 17 00:00:00 2001 From: Arthur O'Dwyer Date: Wed, 14 Jul 2021 00:01:47 -0400 Subject: [PATCH] [libc++] NFCI: Restore code duplication in wrap_iter, with test. It turns out that D105040 broke `std::rel_ops`; we actually do need both a one-template-parameter and a two-template-parameter version of all the comparison operators, because if we have only the heterogeneous two-parameter version, then `x > x` is ambiguous: template int f(S, S) { return 1; } template int f(T, T) { return 2; } // rel_ops S s; f(s,s); // ambiguous between #1 and #2 Adding the one-template-parameter version fixes the ambiguity: template int f(S, S) { return 1; } template int f(T, T) { return 2; } // rel_ops template int f(S, S) { return 3; } S s; f(s,s); // #3 beats both #1 and #2 We have the same problem with `reverse_iterator` as with `__wrap_iter`. But so do libstdc++ and Microsoft, so we're not going to worry about it. Differential Revision: https://reviews.llvm.org/D105894 --- libcxx/include/__iterator/wrap_iter.h | 46 +++++++ .../containers/iterator.rel_ops.compile.pass.cpp | 140 +++++++++++++++++++++ 2 files changed, 186 insertions(+) create mode 100644 libcxx/test/std/containers/iterator.rel_ops.compile.pass.cpp diff --git a/libcxx/include/__iterator/wrap_iter.h b/libcxx/include/__iterator/wrap_iter.h index 4f2228c..e35a372 100644 --- a/libcxx/include/__iterator/wrap_iter.h +++ b/libcxx/include/__iterator/wrap_iter.h @@ -164,6 +164,13 @@ private: template friend class _LIBCPP_TEMPLATE_VIS span; }; +template +_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG +bool operator==(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT +{ + return __x.base() == __y.base(); +} + template _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG bool operator==(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT @@ -171,6 +178,17 @@ bool operator==(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) return __x.base() == __y.base(); } +template +_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG +bool operator<(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT +{ +#if _LIBCPP_DEBUG_LEVEL == 2 + _LIBCPP_ASSERT(__get_const_db()->__less_than_comparable(&__x, &__y), + "Attempted to compare incomparable iterators"); +#endif + return __x.base() < __y.base(); +} + template _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG bool operator<(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT @@ -182,6 +200,13 @@ bool operator<(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _ return __x.base() < __y.base(); } +template +_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG +bool operator!=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT +{ + return !(__x == __y); +} + template _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG bool operator!=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT @@ -189,6 +214,13 @@ bool operator!=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) return !(__x == __y); } +template +_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG +bool operator>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT +{ + return __y < __x; +} + template _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG bool operator>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT @@ -196,6 +228,13 @@ bool operator>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _ return __y < __x; } +template +_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG +bool operator>=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT +{ + return !(__x < __y); +} + template _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG bool operator>=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT @@ -203,6 +242,13 @@ bool operator>=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) return !(__x < __y); } +template +_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG +bool operator<=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT +{ + return !(__y < __x); +} + template _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG bool operator<=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT diff --git a/libcxx/test/std/containers/iterator.rel_ops.compile.pass.cpp b/libcxx/test/std/containers/iterator.rel_ops.compile.pass.cpp new file mode 100644 index 0000000..12efbd3 --- /dev/null +++ b/libcxx/test/std/containers/iterator.rel_ops.compile.pass.cpp @@ -0,0 +1,140 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: libcpp-has-no-filesystem-library + +// Make sure the various containers' iterators are not broken by the use of `std::rel_ops`. + +#include // for std::rel_ops + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" + +#if TEST_STD_VER >= 11 +#include "filesystem_include.h" +#endif + +#if TEST_STD_VER >= 17 +#include +#endif + +#if TEST_STD_VER >= 20 +#include +#endif + +using namespace std::rel_ops; + +template +void test_eq(It it, ConstIt cit) { + (void)(it == it); + (void)(it != it); + (void)(it == cit); + (void)(it != cit); + (void)(cit == it); + (void)(cit != it); + (void)(cit == cit); + (void)(cit != cit); +} + +template +void test_lt(It it, ConstIt cit) { + (void)(it < it); + (void)(it <= it); + (void)(it > it); + (void)(it >= it); + (void)(it < cit); + (void)(it <= cit); + (void)(it > cit); + (void)(it >= cit); + (void)(cit < it); + (void)(cit <= it); + (void)(cit > it); + (void)(cit >= it); + (void)(cit < cit); + (void)(cit <= cit); + (void)(cit > cit); + (void)(cit >= cit); + + // Test subtraction too, even though std::rel_ops shouldn't affect it. + + (void)(it - it); + (void)(it - cit); + (void)(cit - it); + (void)(cit - cit); +} + +template +void test_forward() { + // There is no need to distinguish "forward" from "bidirectional." + // libc++ already can't handle `c.rbegin() >= c.rbegin()` in the + // presence of std::rel_ops, and neither can Microsoft nor libstdc++. + + Container c; + typename Container::iterator it = c.begin(); + typename Container::const_iterator cit = c.begin(); + test_eq(it, cit); +} + +template +void test_random_access() { + Container c; + typename Container::iterator it = c.begin(); + typename Container::const_iterator cit = c.begin(); + test_eq(it, cit); + test_lt(it, cit); +} + +template void test_random_access >(); +template void test_random_access >(); +template void test_forward >(); +template void test_forward >(); +template void test_forward >(); +template void test_forward >(); +template void test_forward >(); +template void test_forward >(); +template void test_random_access(); +template void test_forward >(); +template void test_forward >(); +template void test_forward >(); +template void test_forward >(); +template void test_random_access >(); + +#if TEST_STD_VER >= 11 +void test_directory_iterators() { + fs::directory_iterator it; + test_eq(it, it); + + fs::recursive_directory_iterator rdit; + test_eq(rdit, rdit); +} + +template void test_forward(); +#endif + +#if TEST_STD_VER >= 17 +template void test_random_access(); +#endif + +#if TEST_STD_VER >= 20 +void test_span() { + std::span c; + std::span::iterator it = c.begin(); // span has no const_iterator + test_eq(it, it); + test_lt(it, it); +} +#endif -- 2.7.4