[libcxx-commits] [libcxx] 1a29403 - [libcxx][ranges] Add common_iterator.

via libcxx-commits libcxx-commits at lists.llvm.org
Tue Jul 20 08:13:22 PDT 2021


Author: zoecarver
Date: 2021-07-20T08:12:44-07:00
New Revision: 1a29403d2f8a0d74effcee6ab3d29d361fe97276

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

LOG: [libcxx][ranges] Add common_iterator.

Differential Revision: https://reviews.llvm.org/D103335

Added: 
    libcxx/include/__iterator/common_iterator.h
    libcxx/test/std/iterators/predef.iterators/iterators.common/arrow.pass.cpp
    libcxx/test/std/iterators/predef.iterators/iterators.common/assign.pass.cpp
    libcxx/test/std/iterators/predef.iterators/iterators.common/ctor.pass.cpp
    libcxx/test/std/iterators/predef.iterators/iterators.common/deref.pass.cpp
    libcxx/test/std/iterators/predef.iterators/iterators.common/eq.pass.cpp
    libcxx/test/std/iterators/predef.iterators/iterators.common/iter_move.pass.cpp
    libcxx/test/std/iterators/predef.iterators/iterators.common/iter_swap.pass.cpp
    libcxx/test/std/iterators/predef.iterators/iterators.common/iterator_traits.compile.pass.cpp
    libcxx/test/std/iterators/predef.iterators/iterators.common/minus.pass.cpp
    libcxx/test/std/iterators/predef.iterators/iterators.common/plus_plus.pass.cpp
    libcxx/test/std/iterators/predef.iterators/iterators.common/types.h

Modified: 
    libcxx/docs/Status/RangesPaper.csv
    libcxx/include/CMakeLists.txt
    libcxx/include/iterator
    libcxx/include/module.modulemap
    libcxx/include/variant
    libcxx/test/support/test_iterators.h

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/Status/RangesPaper.csv b/libcxx/docs/Status/RangesPaper.csv
index 4ee8d0d74b1d1..3fadfc3f15fad 100644
--- a/libcxx/docs/Status/RangesPaper.csv
+++ b/libcxx/docs/Status/RangesPaper.csv
@@ -77,7 +77,7 @@ Section,Description,Dependencies,Assignee,Complete
 [move.sentinel],,[predef.iterators],Unassigned,Not started
 [common.iterator],,"| [iterator.concepts]
 | [iterator.cust.swap]
-| [iterator.cust.move]",Zoe Carver,In Progress
+| [iterator.cust.move]",Zoe Carver,✅
 [default.sentinels],std::default_sentinel_t.,No dependencies,Zoe Carver,✅
 [counted.iterator],,"| [iterator.concepts]
 | [iterator.cust.swap]

diff  --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 57304baeba31b..fd86cf114822c 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -133,6 +133,7 @@ set(files
   __iterator/access.h
   __iterator/advance.h
   __iterator/back_insert_iterator.h
+  __iterator/common_iterator.h
   __iterator/concepts.h
   __iterator/data.h
   __iterator/default_sentinel.h

diff  --git a/libcxx/include/__iterator/common_iterator.h b/libcxx/include/__iterator/common_iterator.h
new file mode 100644
index 0000000000000..fb01d8bd4b955
--- /dev/null
+++ b/libcxx/include/__iterator/common_iterator.h
@@ -0,0 +1,301 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___ITERATOR_COMMON_ITERATOR_H
+#define _LIBCPP___ITERATOR_COMMON_ITERATOR_H
+
+#include <__config>
+#include <__debug>
+#include <__iterator/concepts.h>
+#include <__iterator/incrementable_traits.h>
+#include <__iterator/iter_move.h>
+#include <__iterator/iter_swap.h>
+#include <__iterator/iterator_traits.h>
+#include <__iterator/readable_traits.h>
+#include <concepts>
+#include <variant>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if !defined(_LIBCPP_HAS_NO_RANGES)
+
+template<input_or_output_iterator _Iter, sentinel_for<_Iter> _Sent>
+  requires (!same_as<_Iter, _Sent> && copyable<_Iter>)
+class common_iterator {
+  class __proxy {
+    friend common_iterator;
+
+    iter_value_t<_Iter> __value;
+    // We can move __x because the only caller verifies that __x is not a reference.
+    constexpr __proxy(iter_reference_t<_Iter>&& __x)
+      : __value(_VSTD::move(__x)) {}
+
+  public:
+    const iter_value_t<_Iter>* operator->() const {
+      return _VSTD::addressof(__value);
+    }
+  };
+
+  class __postfix_proxy {
+    friend common_iterator;
+
+    iter_value_t<_Iter> __value;
+    constexpr __postfix_proxy(iter_reference_t<_Iter>&& __x)
+      : __value(_VSTD::forward<iter_reference_t<_Iter>>(__x)) {}
+
+  public:
+    constexpr static bool __valid_for_iter =
+      constructible_from<iter_value_t<_Iter>, iter_reference_t<_Iter>> &&
+      move_constructible<iter_value_t<_Iter>>;
+
+    const iter_value_t<_Iter>& operator*() const {
+      return __value;
+    }
+  };
+
+public:
+  variant<_Iter, _Sent> __hold_;
+
+  common_iterator() requires default_initializable<_Iter> = default;
+
+  constexpr common_iterator(_Iter __i) : __hold_(in_place_type<_Iter>, _VSTD::move(__i)) {}
+  constexpr common_iterator(_Sent __s) : __hold_(in_place_type<_Sent>, _VSTD::move(__s)) {}
+
+  template<class _I2, class _S2>
+    requires convertible_to<const _I2&, _Iter> && convertible_to<const _S2&, _Sent>
+  constexpr common_iterator(const common_iterator<_I2, _S2>& __other)
+    : __hold_([&]() -> variant<_Iter, _Sent> {
+      _LIBCPP_ASSERT(!__other.__hold_.valueless_by_exception(), "Constructed from valueless iterator.");
+      if (__other.__hold_.index() == 0)
+        return variant<_Iter, _Sent>{in_place_index<0>, _VSTD::__unchecked_get<0>(__other.__hold_)};
+      return variant<_Iter, _Sent>{in_place_index<1>, _VSTD::__unchecked_get<1>(__other.__hold_)};
+    }()) {}
+
+  template<class _I2, class _S2>
+    requires convertible_to<const _I2&, _Iter> && convertible_to<const _S2&, _Sent> &&
+             assignable_from<_Iter&, const _I2&> && assignable_from<_Sent&, const _S2&>
+  common_iterator& operator=(const common_iterator<_I2, _S2>& __other) {
+    _LIBCPP_ASSERT(!__other.__hold_.valueless_by_exception(), "Assigned from valueless iterator.");
+
+    auto __idx = __hold_.index();
+    auto __other_idx = __other.__hold_.index();
+
+    // If they're the same index, just assign.
+    if (__idx == 0 && __other_idx == 0)
+      _VSTD::__unchecked_get<0>(__hold_) = _VSTD::__unchecked_get<0>(__other.__hold_);
+    else if (__idx == 1 && __other_idx == 1)
+      _VSTD::__unchecked_get<1>(__hold_) = _VSTD::__unchecked_get<1>(__other.__hold_);
+
+    // Otherwise replace with the oposite element.
+    else if (__other_idx == 1)
+      __hold_.template emplace<1>(_VSTD::__unchecked_get<1>(__other.__hold_));
+    else if (__other_idx == 0)
+      __hold_.template emplace<0>(_VSTD::__unchecked_get<0>(__other.__hold_));
+
+    return *this;
+  }
+
+  decltype(auto) operator*()
+  {
+    _LIBCPP_ASSERT(holds_alternative<_Iter>(__hold_),
+                   "Cannot dereference sentinel. Common iterator not holding an iterator.");
+    return *_VSTD::__unchecked_get<_Iter>(__hold_);
+  }
+
+  decltype(auto) operator*() const
+    requires __dereferenceable<const _Iter>
+  {
+    _LIBCPP_ASSERT(holds_alternative<_Iter>(__hold_),
+                   "Cannot dereference sentinel. Common iterator not holding an iterator.");
+    return *_VSTD::__unchecked_get<_Iter>(__hold_);
+  }
+
+  template<class _I2 = _Iter>
+  decltype(auto) operator->() const
+    requires indirectly_readable<const _I2> &&
+    (requires(const _I2& __i) { __i.operator->(); } ||
+     is_reference_v<iter_reference_t<_I2>> ||
+     constructible_from<iter_value_t<_I2>, iter_reference_t<_I2>>)
+  {
+    _LIBCPP_ASSERT(holds_alternative<_Iter>(__hold_),
+                   "Cannot dereference sentinel. Common iterator not holding an iterator.");
+
+    if constexpr (is_pointer_v<_Iter> || requires(const _Iter& __i) { __i.operator->(); })    {
+      return _VSTD::__unchecked_get<_Iter>(__hold_);
+    } else if constexpr (is_reference_v<iter_reference_t<_Iter>>) {
+      auto&& __tmp = *_VSTD::__unchecked_get<_Iter>(__hold_);
+      return _VSTD::addressof(__tmp);
+    } else {
+      return __proxy(*_VSTD::__unchecked_get<_Iter>(__hold_));
+    }
+  }
+
+  common_iterator& operator++() {
+    _LIBCPP_ASSERT(holds_alternative<_Iter>(__hold_),
+                   "Cannot increment sentinel. Common iterator not holding an iterator.");
+    ++_VSTD::__unchecked_get<_Iter>(__hold_); return *this;
+  }
+
+  decltype(auto) operator++(int) {
+    _LIBCPP_ASSERT(holds_alternative<_Iter>(__hold_),
+                   "Cannot increment sentinel. Common iterator not holding an iterator.");
+
+    if constexpr (forward_iterator<_Iter>) {
+      auto __tmp = *this;
+      ++*this;
+      return __tmp;
+    } else if constexpr (requires (_Iter& __i) { { *__i++ } -> __referenceable; } ||
+                         !__postfix_proxy::__valid_for_iter) {
+      return _VSTD::__unchecked_get<_Iter>(__hold_)++;
+    } else {
+      __postfix_proxy __p(**this);
+      ++*this;
+      return __p;
+    }
+  }
+
+  template<class _I2, sentinel_for<_Iter> _S2>
+    requires sentinel_for<_Sent, _I2>
+  friend bool operator==(const common_iterator& __x, const common_iterator<_I2, _S2>& __y) {
+    _LIBCPP_ASSERT(!__x.__hold_.valueless_by_exception() &&
+                   !__y.__hold_.valueless_by_exception(),
+                   "One or both common_iterators are valueless. (Cannot compare valueless iterators.)");
+
+    auto __x_index = __x.__hold_.index();
+    auto __y_index = __y.__hold_.index();
+
+    if (__x_index == __y_index)
+      return true;
+
+    if (__x_index == 0)
+      return _VSTD::__unchecked_get<_Iter>(__x.__hold_) == _VSTD::__unchecked_get<_S2>(__y.__hold_);
+
+    return _VSTD::__unchecked_get<_Sent>(__x.__hold_) == _VSTD::__unchecked_get<_I2>(__y.__hold_);
+  }
+
+  template<class _I2, sentinel_for<_Iter> _S2>
+    requires sentinel_for<_Sent, _I2> && equality_comparable_with<_Iter, _I2>
+  friend bool operator==(const common_iterator& __x, const common_iterator<_I2, _S2>& __y) {
+    _LIBCPP_ASSERT(!__x.__hold_.valueless_by_exception() &&
+                   !__y.__hold_.valueless_by_exception(),
+                   "One or both common_iterators are valueless. (Cannot compare valueless iterators.)");
+
+    auto __x_index = __x.__hold_.index();
+    auto __y_index = __y.__hold_.index();
+
+    if (__x_index == 1 && __y_index == 1)
+      return true;
+
+    if (__x_index == 0 && __y_index == 0)
+      return  _VSTD::__unchecked_get<_Iter>(__x.__hold_) ==  _VSTD::__unchecked_get<_I2>(__y.__hold_);
+
+    if (__x_index == 0)
+      return  _VSTD::__unchecked_get<_Iter>(__x.__hold_) == _VSTD::__unchecked_get<_S2>(__y.__hold_);
+
+    return _VSTD::__unchecked_get<_Sent>(__x.__hold_) ==  _VSTD::__unchecked_get<_I2>(__y.__hold_);
+  }
+
+  template<sized_sentinel_for<_Iter> _I2, sized_sentinel_for<_Iter> _S2>
+    requires sized_sentinel_for<_Sent, _I2>
+  friend iter_
diff erence_t<_I2> operator-(const common_iterator& __x, const common_iterator<_I2, _S2>& __y) {
+    _LIBCPP_ASSERT(!__x.__hold_.valueless_by_exception() &&
+                   !__y.__hold_.valueless_by_exception(),
+                   "One or both common_iterators are valueless. (Cannot subtract valueless iterators.)");
+
+    auto __x_index = __x.__hold_.index();
+    auto __y_index = __y.__hold_.index();
+
+    if (__x_index == 1 && __y_index == 1)
+      return 0;
+
+    if (__x_index == 0 && __y_index == 0)
+      return  _VSTD::__unchecked_get<_Iter>(__x.__hold_) - _VSTD::__unchecked_get<_I2>(__y.__hold_);
+
+    if (__x_index == 0)
+      return  _VSTD::__unchecked_get<_Iter>(__x.__hold_) - _VSTD::__unchecked_get<_S2>(__y.__hold_);
+
+    return _VSTD::__unchecked_get<_Sent>(__x.__hold_) - _VSTD::__unchecked_get<_I2>(__y.__hold_);
+  }
+
+  friend iter_rvalue_reference_t<_Iter> iter_move(const common_iterator& __i)
+    noexcept(noexcept(ranges::iter_move(declval<const _Iter&>())))
+      requires input_iterator<_Iter>
+  {
+    _LIBCPP_ASSERT(holds_alternative<_Iter>(__i.__hold_),
+                   "Cannot iter_move a sentinel. Common iterator not holding an iterator.");
+    return ranges::iter_move( _VSTD::__unchecked_get<_Iter>(__i.__hold_));
+  }
+
+  template<indirectly_swappable<_Iter> _I2, class _S2>
+  friend void iter_swap(const common_iterator& __x, const common_iterator<_I2, _S2>& __y)
+      noexcept(noexcept(ranges::iter_swap(declval<const _Iter&>(), declval<const _I2&>())))
+  {
+    _LIBCPP_ASSERT(holds_alternative<_Iter>(__x.__hold_),
+                   "Cannot swap __y with a sentinel. Common iterator (__x) not holding an iterator.");
+    _LIBCPP_ASSERT(holds_alternative<_Iter>(__y.__hold_),
+                   "Cannot swap __x with a sentinel. Common iterator (__y) not holding an iterator.");
+    return ranges::iter_swap( _VSTD::__unchecked_get<_Iter>(__x.__hold_),  _VSTD::__unchecked_get<_Iter>(__y.__hold_));
+  }
+};
+
+template<class _Iter, class _Sent>
+struct incrementable_traits<common_iterator<_Iter, _Sent>> {
+  using 
diff erence_type = iter_
diff erence_t<_Iter>;
+};
+
+template<class _Iter>
+concept __denotes_forward_iter =
+  requires { typename iterator_traits<_Iter>::iterator_category; } &&
+  derived_from<typename iterator_traits<_Iter>::iterator_category, forward_iterator_tag>;
+
+template<class _Iter, class _Sent>
+concept __common_iter_has_ptr_op = requires(const common_iterator<_Iter, _Sent>& __a) {
+  __a.operator->();
+};
+
+template<class, class>
+struct __arrow_type_or_void {
+    using type = void;
+};
+
+template<class _Iter, class _Sent>
+  requires __common_iter_has_ptr_op<_Iter, _Sent>
+struct __arrow_type_or_void<_Iter, _Sent> {
+    using type = decltype(declval<const common_iterator<_Iter, _Sent>>().operator->());
+};
+
+template<class _Iter, class _Sent>
+struct iterator_traits<common_iterator<_Iter, _Sent>> {
+  using iterator_concept = _If<forward_iterator<_Iter>,
+                               forward_iterator_tag,
+                               input_iterator_tag>;
+  using iterator_category = _If<__denotes_forward_iter<_Iter>,
+                                forward_iterator_tag,
+                                input_iterator_tag>;
+  using pointer = typename __arrow_type_or_void<_Iter, _Sent>::type;
+  using value_type = iter_value_t<_Iter>;
+  using 
diff erence_type = iter_
diff erence_t<_Iter>;
+  using reference = iter_reference_t<_Iter>;
+};
+
+
+#endif // !defined(_LIBCPP_HAS_NO_RANGES)
+
+_LIBCPP_END_NAMESPACE_STD
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___ITERATOR_COMMON_ITERATOR_H

diff  --git a/libcxx/include/iterator b/libcxx/include/iterator
index 52b04e4cc779c..80f3827b72034 100644
--- a/libcxx/include/iterator
+++ b/libcxx/include/iterator
@@ -136,6 +136,10 @@ template<class In, class Out>
 template<class I1, class I2 = I1>
   concept indirectly_swappable = see below;                // since C++20
 
+template<input_or_output_iterator I, sentinel_for<I> S>
+  requires (!same_as<I, S> && copyable<I>)
+class common_iterator;                                     // since C++20
+
 template<class Category, class T, class Distance = ptr
diff _t,
          class Pointer = T*, class Reference = T&>
 struct iterator                                            // deprecated in C++17
@@ -564,6 +568,7 @@ template <class E> constexpr const E* data(initializer_list<E> il) noexcept;
 #include <__iterator/access.h>
 #include <__iterator/advance.h>
 #include <__iterator/back_insert_iterator.h>
+#include <__iterator/common_iterator.h>
 #include <__iterator/concepts.h>
 #include <__iterator/data.h>
 #include <__iterator/default_sentinel.h>

diff  --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap
index 1d22f866dea79..ecd853c8536b3 100644
--- a/libcxx/include/module.modulemap
+++ b/libcxx/include/module.modulemap
@@ -480,6 +480,7 @@ module std [system] {
       module access                { private header "__iterator/access.h" }
       module advance               { private header "__iterator/advance.h" }
       module back_insert_iterator  { private header "__iterator/back_insert_iterator.h" }
+      module common_iterator       { private header "__iterator/common_iterator.h" }
       module concepts              { private header "__iterator/concepts.h" }
       module data                  { private header "__iterator/data.h" }
       module default_sentinel      { private header "__iterator/default_sentinel.h" }

diff  --git a/libcxx/include/variant b/libcxx/include/variant
index 7e8b683953d42..700e6f3f11514 100644
--- a/libcxx/include/variant
+++ b/libcxx/include/variant
@@ -201,12 +201,12 @@ namespace std {
 
 #include <__availability>
 #include <__config>
+#include <__functional/hash.h>
+#include <__tuple>
 #include <__utility/forward.h>
 #include <__variant/monostate.h>
-#include <__tuple>
 #include <compare>
 #include <exception>
-#include <functional>
 #include <initializer_list>
 #include <limits>
 #include <new>
@@ -1748,6 +1748,28 @@ struct _LIBCPP_TEMPLATE_VIS hash<
   }
 };
 
+// __unchecked_get is the same as std::get, except, it is UB to use it with the wrong
+// type whereas std::get will throw or returning nullptr. This makes it faster than
+// std::get.
+template <size_t _Ip, class _Vp>
+inline _LIBCPP_INLINE_VISIBILITY
+constexpr auto&& __unchecked_get(_Vp&& __v) noexcept {
+  using __variant_detail::__access::__variant;
+  return __variant::__get_alt<_Ip>(_VSTD::forward<_Vp>(__v)).__value;
+}
+
+template <class _Tp, class... _Types>
+inline _LIBCPP_INLINE_VISIBILITY
+constexpr auto&& __unchecked_get(const variant<_Types...>& __v) noexcept {
+  return __unchecked_get<__find_exactly_one_t<_Tp, _Types...>::value>(__v);
+}
+
+template <class _Tp, class... _Types>
+inline _LIBCPP_INLINE_VISIBILITY
+constexpr auto&& __unchecked_get(variant<_Types...>& __v) noexcept {
+  return __unchecked_get<__find_exactly_one_t<_Tp, _Types...>::value>(__v);
+}
+
 #endif // _LIBCPP_STD_VER > 14
 
 _LIBCPP_END_NAMESPACE_STD

diff  --git a/libcxx/test/std/iterators/predef.iterators/iterators.common/arrow.pass.cpp b/libcxx/test/std/iterators/predef.iterators/iterators.common/arrow.pass.cpp
new file mode 100644
index 0000000000000..f3b741d1c4c95
--- /dev/null
+++ b/libcxx/test/std/iterators/predef.iterators/iterators.common/arrow.pass.cpp
@@ -0,0 +1,90 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: c++03, c++11, c++14, c++17
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: gcc-10
+
+// decltype(auto) operator->() const
+//   requires see below;
+
+#include <iterator>
+#include <cassert>
+
+#include "test_macros.h"
+#include "types.h"
+
+void test() {
+  int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
+
+  // Case 2: http://eel.is/c++draft/iterators.common#common.iter.access-5.2
+  {
+    auto iter1 = simple_iterator<int*>(buffer);
+    auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+    const auto commonIter2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+
+    assert(commonIter1.operator->() == buffer);
+    assert(commonIter2.operator->() == buffer);
+  }
+
+  // Case 3: http://eel.is/c++draft/iterators.common#common.iter.access-5.3
+  {
+    auto iter1 = value_iterator<int*>(buffer);
+    auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+    const auto commonIter2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+
+    assert(*commonIter1.operator->().operator->() == 1);
+    assert(*commonIter2.operator->().operator->() == 1);
+  }
+
+  // Case 3: http://eel.is/c++draft/iterators.common#common.iter.access-5.3
+  {
+    auto iter1 = void_plus_plus_iterator<int*>(buffer);
+    auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+    const auto commonIter2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+
+    assert(*commonIter1.operator->().operator->() == 1);
+    assert(*commonIter2.operator->().operator->() == 1);
+  }
+
+  // Case 1: http://eel.is/c++draft/iterators.common#common.iter.access-5.1
+  {
+    auto iter1 = cpp17_input_iterator<int*>(buffer);
+    auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+    const auto commonIter2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+
+    assert(commonIter1.operator->().base() == buffer);
+    assert(commonIter2.operator->().base() == buffer);
+  }
+
+  // Case 1: http://eel.is/c++draft/iterators.common#common.iter.access-5.1
+  {
+    auto iter1 = forward_iterator<int*>(buffer);
+    auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+    const auto commonIter2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+
+    assert(commonIter1.operator->().base() == buffer);
+    assert(commonIter2.operator->().base() == buffer);
+  }
+
+  // Case 1: http://eel.is/c++draft/iterators.common#common.iter.access-5.1
+  {
+    auto iter1 = random_access_iterator<int*>(buffer);
+    auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+    const auto commonIter2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+
+    assert(commonIter1.operator->().base() == buffer);
+    assert(commonIter2.operator->().base() == buffer);
+  }
+}
+
+int main(int, char**) {
+  test();
+
+  return 0;
+}

diff  --git a/libcxx/test/std/iterators/predef.iterators/iterators.common/assign.pass.cpp b/libcxx/test/std/iterators/predef.iterators/iterators.common/assign.pass.cpp
new file mode 100644
index 0000000000000..baa759f78462c
--- /dev/null
+++ b/libcxx/test/std/iterators/predef.iterators/iterators.common/assign.pass.cpp
@@ -0,0 +1,144 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: c++03, c++11, c++14, c++17
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: gcc-10
+
+// template<class I2, class S2>
+//   requires convertible_to<const I2&, I> && convertible_to<const S2&, S> &&
+//            assignable_from<I&, const I2&> && assignable_from<S&, const S2&>
+//     common_iterator& operator=(const common_iterator<I2, S2>& x);
+
+#include <iterator>
+#include <ranges>
+#include <cassert>
+
+#include "test_macros.h"
+#include "types.h"
+
+void test() {
+  int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
+
+  {
+    auto iter1 = cpp17_input_iterator<int*>(buffer);
+    auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+    auto commonIter2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(cpp17_input_iterator<int*>(buffer + 1));
+
+    assert(*commonIter1 == 1);
+    assert(*commonIter2 == 2);
+    assert(commonIter1 != commonIter2);
+
+    commonIter1 = commonIter2;
+
+    assert(*commonIter1 == 2);
+    assert(*commonIter2 == 2);
+    assert(commonIter1 == commonIter2);
+  }
+  {
+    auto iter1 = forward_iterator<int*>(buffer);
+    auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+    auto commonIter2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(forward_iterator<int*>(buffer + 1));
+
+    assert(*commonIter1 == 1);
+    assert(*commonIter2 == 2);
+    assert(commonIter1 != commonIter2);
+
+    commonIter1 = commonIter2;
+
+    assert(*commonIter1 == 2);
+    assert(*commonIter2 == 2);
+    assert(commonIter1 == commonIter2);
+  }
+  {
+    auto iter1 = random_access_iterator<int*>(buffer);
+    auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+    auto commonSent1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
+
+    auto commonIter2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1 + 1);
+    auto commonSent2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 7});
+
+    assert(*commonIter1 == 1);
+    assert(*commonIter2 == 2);
+    assert(commonIter1 != commonIter2);
+
+    commonIter1 = commonIter2;
+
+    assert(*commonIter1 == 2);
+    assert(*commonIter2 == 2);
+    assert(commonIter1 == commonIter2);
+
+    assert(std::ranges::next(commonIter1, 6) != commonSent1);
+    assert(std::ranges::next(commonIter1, 6) == commonSent2);
+
+    commonSent1 = commonSent2;
+
+    assert(std::ranges::next(commonIter1, 6) == commonSent1);
+    assert(std::ranges::next(commonIter1, 6) == commonSent2);
+  }
+  {
+    auto iter1 = assignable_iterator<int*>(buffer);
+    auto iter2 = forward_iterator<int*>(buffer + 1);
+    auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+    auto commonSent1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
+
+    auto commonIter2 = std::common_iterator<decltype(iter2), sentinel_type<int*>>(iter2);
+    auto commonSent2 = std::common_iterator<decltype(iter2), sentinel_type<int*>>(sentinel_type<int*>{buffer + 7});
+
+    assert(*commonIter1 == 1);
+    assert(*commonIter2 == 2);
+
+    commonIter1 = commonIter2;
+
+    assert(*commonIter1 == 2);
+    assert(*commonIter2 == 2);
+    assert(commonIter1 == commonIter2);
+
+    assert(std::ranges::next(commonIter1, 6) != commonSent1);
+    assert(std::ranges::next(commonIter1, 6) == commonSent2);
+
+    commonSent1 = commonSent2;
+
+    assert(std::ranges::next(commonIter1, 6) == commonSent1);
+    assert(std::ranges::next(commonIter1, 6) == commonSent2);
+
+    commonIter1 = commonSent1;
+
+    assert(commonIter1 == commonSent2);
+
+    commonIter1 = commonSent2;
+
+    assert(commonIter1 == commonSent2);
+  }
+#ifndef TEST_HAS_NO_EXCEPTIONS
+  {
+    auto iter1 = maybe_valueless_iterator<int*>(buffer);
+    auto iter2 = forward_iterator<int*>(buffer);
+    auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+    auto commonSent2 = std::common_iterator<decltype(iter1),
+      sentinel_throws_on_convert<int*>>(sentinel_throws_on_convert<int*>{buffer + 8});
+    auto commonIter2 = std::common_iterator<decltype(iter2), sentinel_type<int*>>(iter2);
+
+    try {
+      commonIter1 = commonSent2;
+      assert(false);
+    } catch (int x) {
+      assert(x == 42);
+      commonIter1 = commonIter2;
+    }
+
+    assert(*commonIter1 == 1);
+  }
+#endif // TEST_HAS_NO_EXCEPTIONS
+}
+
+int main(int, char**) {
+  test();
+
+  return 0;
+}

diff  --git a/libcxx/test/std/iterators/predef.iterators/iterators.common/ctor.pass.cpp b/libcxx/test/std/iterators/predef.iterators/iterators.common/ctor.pass.cpp
new file mode 100644
index 0000000000000..d8226a142b111
--- /dev/null
+++ b/libcxx/test/std/iterators/predef.iterators/iterators.common/ctor.pass.cpp
@@ -0,0 +1,91 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: c++03, c++11, c++14, c++17
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: gcc-10
+
+// constexpr common_iterator() requires default_initializable<I> = default;
+// constexpr common_iterator(I i);
+// constexpr common_iterator(S s);
+// template<class I2, class S2>
+//   requires convertible_to<const I2&, I> && convertible_to<const S2&, S>
+//     constexpr common_iterator(const common_iterator<I2, S2>& x);
+
+#include <iterator>
+#include <cassert>
+
+#include "test_macros.h"
+#include "types.h"
+
+template<class I, class S>
+concept ValidCommonIterator = requires {
+  typename std::common_iterator<I, S>;
+};
+
+template<class I, class I2>
+concept ConvCtorEnabled = requires(std::common_iterator<I2, sentinel_type<int*>> ci) {
+  std::common_iterator<I, sentinel_type<int*>>(ci);
+};
+
+void test() {
+  int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
+
+  static_assert( std::is_default_constructible_v<std::common_iterator<int*, sentinel_type<int*>>>);
+  static_assert(!std::is_default_constructible_v<std::common_iterator<non_default_constructible_iterator<int*>, sentinel_type<int*>>>);
+
+  // Not copyable:
+  static_assert(!ValidCommonIterator<cpp20_input_iterator<int*>, sentinel_type<int*>>);
+  // Same iter and sent:
+  static_assert(!ValidCommonIterator<cpp17_input_iterator<int*>, cpp17_input_iterator<int*>>);
+
+  {
+    auto iter1 = cpp17_input_iterator<int*>(buffer);
+    auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+    auto commonSent1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
+
+    assert(*iter1 == 1);
+    assert(*commonIter1 == 1);
+    assert(commonIter1 != commonSent1);
+  }
+  {
+    auto iter1 = forward_iterator<int*>(buffer);
+    auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+    auto commonSent1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
+
+    assert(*iter1 == 1);
+    assert(*commonIter1 == 1);
+    assert(commonIter1 != commonSent1);
+  }
+  {
+    auto iter1 = random_access_iterator<int*>(buffer);
+    auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+    auto commonSent1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
+
+    assert(*iter1 == 1);
+    assert(*commonIter1 == 1);
+    assert(commonIter1 != commonSent1);
+  }
+
+  // Conversion constructor:
+  {
+    convertible_iterator<int*> conv{buffer};
+    auto commonIter1 = std::common_iterator<convertible_iterator<int*>, sentinel_type<int*>>(conv);
+    auto commonIter2 = std::common_iterator<forward_iterator<int*>, sentinel_type<int*>>(commonIter1);
+    assert(*commonIter2 == 1);
+
+    static_assert( ConvCtorEnabled<forward_iterator<int*>, convertible_iterator<int*>>);
+    static_assert(!ConvCtorEnabled<forward_iterator<int*>, random_access_iterator<int*>>);
+  }
+}
+
+int main(int, char**) {
+  test();
+
+  return 0;
+}

diff  --git a/libcxx/test/std/iterators/predef.iterators/iterators.common/deref.pass.cpp b/libcxx/test/std/iterators/predef.iterators/iterators.common/deref.pass.cpp
new file mode 100644
index 0000000000000..533a4a48b0065
--- /dev/null
+++ b/libcxx/test/std/iterators/predef.iterators/iterators.common/deref.pass.cpp
@@ -0,0 +1,147 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: c++03, c++11, c++14, c++17
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: gcc-10
+
+// decltype(auto) operator*();
+// decltype(auto) operator*() const
+//   requires dereferenceable<const I>;
+
+#include <iterator>
+#include <cassert>
+
+#include "test_macros.h"
+#include "types.h"
+
+void test() {
+  int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
+
+  {
+    auto iter1 = simple_iterator<int*>(buffer);
+    auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+    auto commonSent1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
+
+    const auto iter2 = simple_iterator<int*>(buffer);
+    const auto commonIter2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+
+    assert(*iter1 == 1);
+    assert(*commonIter1 == 1);
+
+    assert(*iter2 == 1);
+    assert(*commonIter2 == 1);
+
+    assert(*(commonIter1++) == 1);
+    assert(*commonIter1 == 2);
+    assert(*(++commonIter1) == 3);
+    assert(*commonIter1 == 3);
+
+    for (auto i = 3; commonIter1 != commonSent1; ++i) {
+      assert(*(commonIter1++) == i);
+    }
+  }
+  {
+    auto iter1 = value_iterator<int*>(buffer);
+    auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+    auto commonSent1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
+
+    const auto iter2 = value_iterator<int*>(buffer);
+    const auto commonIter2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+
+    assert(*iter1 == 1);
+    assert(*commonIter1 == 1);
+
+    assert(*iter2 == 1);
+    assert(*commonIter2 == 1);
+
+    assert(*(commonIter1++) == 1);
+    assert(*commonIter1 == 2);
+    assert(*(++commonIter1) == 3);
+    assert(*commonIter1 == 3);
+
+    for (auto i = 3; commonIter1 != commonSent1; ++i) {
+      assert(*(commonIter1++) == i);
+    }
+  }
+  {
+    auto iter1 = cpp17_input_iterator<int*>(buffer);
+    auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+    auto commonSent1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
+
+    const auto iter2 = cpp17_input_iterator<int*>(buffer);
+    const auto commonIter2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+
+    assert(*iter1 == 1);
+    assert(*commonIter1 == 1);
+
+    assert(*iter2 == 1);
+    assert(*commonIter2 == 1);
+
+    assert(*(commonIter1++) == 1);
+    assert(*commonIter1 == 2);
+    assert(*(++commonIter1) == 3);
+    assert(*commonIter1 == 3);
+
+    for (auto i = 3; commonIter1 != commonSent1; ++i) {
+      assert(*(commonIter1++) == i);
+    }
+  }
+  {
+    auto iter1 = forward_iterator<int*>(buffer);
+    auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+    auto commonSent1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
+
+    const auto iter2 = forward_iterator<int*>(buffer);
+    const auto commonIter2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+
+    assert(*iter1 == 1);
+    assert(*commonIter1 == 1);
+
+    assert(*iter2 == 1);
+    assert(*commonIter2 == 1);
+
+    assert(*(commonIter1++) == 1);
+    assert(*commonIter1 == 2);
+    assert(*(++commonIter1) == 3);
+    assert(*commonIter1 == 3);
+
+    for (auto i = 3; commonIter1 != commonSent1; ++i) {
+      assert(*(commonIter1++) == i);
+    }
+  }
+  {
+    auto iter1 = random_access_iterator<int*>(buffer);
+    auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+    auto commonSent1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
+
+    const auto iter2 = random_access_iterator<int*>(buffer);
+    const auto commonIter2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+
+    assert(*iter1 == 1);
+    assert(*commonIter1 == 1);
+
+    assert(*iter2 == 1);
+    assert(*commonIter2 == 1);
+
+    assert(*(commonIter1++) == 1);
+    assert(*commonIter1 == 2);
+    assert(*(++commonIter1) == 3);
+    assert(*commonIter1 == 3);
+
+    for (auto i = 3; commonIter1 != commonSent1; ++i) {
+      assert(*(commonIter1++) == i);
+    }
+  }
+}
+
+int main(int, char**) {
+  test();
+
+  return 0;
+}

diff  --git a/libcxx/test/std/iterators/predef.iterators/iterators.common/eq.pass.cpp b/libcxx/test/std/iterators/predef.iterators/iterators.common/eq.pass.cpp
new file mode 100644
index 0000000000000..7d7513b369cc0
--- /dev/null
+++ b/libcxx/test/std/iterators/predef.iterators/iterators.common/eq.pass.cpp
@@ -0,0 +1,168 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: c++03, c++11, c++14, c++17
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: gcc-10
+
+// template<class I2, sentinel_for<I> S2>
+//   requires sentinel_for<S, I2>
+// friend bool operator==(
+//   const common_iterator& x, const common_iterator<I2, S2>& y);
+// template<class I2, sentinel_for<I> S2>
+//   requires sentinel_for<S, I2> && equality_comparable_with<I, I2>
+// friend bool operator==(
+//   const common_iterator& x, const common_iterator<I2, S2>& y);
+
+#include <iterator>
+#include <cassert>
+
+#include "test_macros.h"
+#include "types.h"
+
+void test() {
+  int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
+
+  {
+    auto iter1 = simple_iterator<int*>(buffer);
+    auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+    auto commonSent1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
+
+    const auto commonIter2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+    const auto commonSent2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
+
+    assert(commonIter1 != commonSent1);
+    assert(commonIter2 != commonSent2);
+    assert(commonSent1 != commonIter1);
+    assert(commonSent2 != commonIter2);
+
+    for (auto i = 1; commonIter1 != commonSent1; ++i) {
+      assert(*(commonIter1++) == i);
+    }
+    assert(commonIter1 == commonSent1);
+    assert(commonSent1 == commonIter1);
+  }
+  {
+    auto iter1 = value_iterator<int*>(buffer);
+    auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+    auto commonSent1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
+
+    const auto commonIter2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+    const auto commonSent2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
+
+    assert(commonIter1 != commonSent1);
+    assert(commonIter2 != commonSent2);
+    assert(commonSent1 != commonIter1);
+    assert(commonSent2 != commonIter2);
+
+    for (auto i = 1; commonIter1 != commonSent1; ++i) {
+      assert(*(commonIter1++) == i);
+    }
+    assert(commonIter1 == commonSent1);
+    assert(commonSent1 == commonIter1);
+  }
+  {
+    auto iter1 = simple_iterator<int*>(buffer);
+    auto iter2 = comparable_iterator<int*>(buffer);
+    auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+    auto commonSent1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
+
+    const auto commonIter2 = std::common_iterator<decltype(iter2), sentinel_type<int*>>(iter2);
+    const auto commonSent2 = std::common_iterator<decltype(iter2), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
+
+    assert(commonIter1 == commonIter2);
+    assert(commonSent1 != commonIter2);
+    assert(commonSent1 == commonSent2);
+    assert(commonSent2 == commonSent1);
+
+    assert(commonIter1 != commonSent1);
+    assert(commonIter2 != commonSent2);
+    assert(commonSent1 != commonIter1);
+    assert(commonSent2 != commonIter2);
+
+    assert(commonIter1 == commonIter2);
+    assert(commonIter2 == commonIter1);
+
+    for (auto i = 1; commonIter1 != commonSent1; ++i) {
+      assert(*(commonIter1++) == i);
+    }
+    assert(commonIter1 == commonSent1);
+    assert(commonSent1 == commonIter1);
+
+    // This check may *seem* incorrect (our iterators point to two completely 
diff erent
+    // elements of buffer). However, this is actually what the Standard wants.
+    // See https://eel.is/c++draft/iterators.common#common.iter.cmp-2.
+    assert(commonIter1 == commonIter2);
+  }
+  {
+    auto iter1 = cpp17_input_iterator<int*>(buffer);
+    auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+    auto commonSent1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
+
+    const auto commonIter2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+    const auto commonSent2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
+
+    assert(commonIter1 != commonSent1);
+    assert(commonIter2 != commonSent2);
+    assert(commonSent1 != commonIter1);
+    assert(commonSent2 != commonIter2);
+
+    for (auto i = 1; commonIter1 != commonSent1; ++i) {
+      assert(*(commonIter1++) == i);
+    }
+    assert(commonIter1 == commonSent1);
+    assert(commonSent1 == commonIter1);
+  }
+  {
+    auto iter1 = forward_iterator<int*>(buffer);
+    auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+    auto commonSent1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
+
+    const auto commonIter2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+    const auto commonSent2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
+
+    assert(commonIter1 != commonSent1);
+    assert(commonIter2 != commonSent2);
+    assert(commonSent1 != commonIter1);
+    assert(commonSent2 != commonIter2);
+
+    for (auto i = 1; commonIter1 != commonSent1; ++i) {
+      assert(*(commonIter1++) == i);
+    }
+    assert(commonIter1 == commonSent1);
+    assert(commonSent1 == commonIter1);
+  }
+  {
+    auto iter1 = random_access_iterator<int*>(buffer);
+    auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+    auto commonSent1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
+
+    const auto commonIter2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+    const auto commonSent2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
+
+    assert(commonIter1 != commonSent1);
+    assert(commonIter2 != commonSent2);
+    assert(commonSent1 != commonIter1);
+    assert(commonSent2 != commonIter2);
+
+    assert(commonSent1 == commonSent2);
+    assert(commonSent2 == commonSent1);
+
+    for (auto i = 1; commonIter1 != commonSent1; ++i) {
+      assert(*(commonIter1++) == i);
+    }
+    assert(commonIter1 == commonSent1);
+    assert(commonSent1 == commonIter1);
+  }
+}
+
+int main(int, char**) {
+  test();
+
+  return 0;
+}

diff  --git a/libcxx/test/std/iterators/predef.iterators/iterators.common/iter_move.pass.cpp b/libcxx/test/std/iterators/predef.iterators/iterators.common/iter_move.pass.cpp
new file mode 100644
index 0000000000000..b79f0590e7cdd
--- /dev/null
+++ b/libcxx/test/std/iterators/predef.iterators/iterators.common/iter_move.pass.cpp
@@ -0,0 +1,50 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: c++03, c++11, c++14, c++17
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: gcc-10
+
+// friend iter_rvalue_reference_t<I> iter_move(const common_iterator& i)
+//   noexcept(noexcept(ranges::iter_move(declval<const I&>())))
+//     requires input_iterator<I>;
+
+#include <iterator>
+#include <cassert>
+
+#include "test_macros.h"
+#include "types.h"
+
+void test() {
+  int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
+
+  {
+    auto iter1 = cpp17_input_iterator<int*>(buffer);
+    auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+    assert(std::ranges::iter_move(commonIter1) == 1);
+    ASSERT_SAME_TYPE(decltype(std::ranges::iter_move(commonIter1)), int&&);
+  }
+  {
+    auto iter1 = forward_iterator<int*>(buffer);
+    auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+    assert(std::ranges::iter_move(commonIter1) == 1);
+    ASSERT_SAME_TYPE(decltype(std::ranges::iter_move(commonIter1)), int&&);
+  }
+  {
+    auto iter1 = random_access_iterator<int*>(buffer);
+    auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+    assert(std::ranges::iter_move(commonIter1) == 1);
+    ASSERT_SAME_TYPE(decltype(std::ranges::iter_move(commonIter1)), int&&);
+  }
+}
+
+int main(int, char**) {
+  test();
+
+  return 0;
+}

diff  --git a/libcxx/test/std/iterators/predef.iterators/iterators.common/iter_swap.pass.cpp b/libcxx/test/std/iterators/predef.iterators/iterators.common/iter_swap.pass.cpp
new file mode 100644
index 0000000000000..348c9fab21547
--- /dev/null
+++ b/libcxx/test/std/iterators/predef.iterators/iterators.common/iter_swap.pass.cpp
@@ -0,0 +1,65 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: c++03, c++11, c++14, c++17
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: gcc-10
+
+// template<indirectly_swappable<I> I2, class S2>
+//   friend void iter_swap(const common_iterator& x, const common_iterator<I2, S2>& y)
+//     noexcept(noexcept(ranges::iter_swap(declval<const I&>(), declval<const I2&>())));
+
+#include <iterator>
+#include <cassert>
+
+#include "test_macros.h"
+#include "types.h"
+
+void test() {
+  int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
+
+  {
+    auto iter1 = cpp17_input_iterator<int*>(buffer);
+    auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+    auto commonIter2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+    for (auto i = 0; i < 4; ++i) ++commonIter2;
+    assert(*commonIter2 == 5);
+    std::ranges::iter_swap(commonIter1, commonIter2);
+    assert(*commonIter1 == 5);
+    assert(*commonIter2 == 1);
+    std::ranges::iter_swap(commonIter2, commonIter1);
+  }
+  {
+    auto iter1 = forward_iterator<int*>(buffer);
+    auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+    auto commonIter2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+    for (auto i = 0; i < 4; ++i) ++commonIter2;
+    assert(*commonIter2 == 5);
+    std::ranges::iter_swap(commonIter1, commonIter2);
+    assert(*commonIter1 == 5);
+    assert(*commonIter2 == 1);
+    std::ranges::iter_swap(commonIter2, commonIter1);
+  }
+  {
+    auto iter1 = random_access_iterator<int*>(buffer);
+    auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+    auto commonIter2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+    for (auto i = 0; i < 4; ++i) ++commonIter2;
+    assert(*commonIter2 == 5);
+    std::ranges::iter_swap(commonIter1, commonIter2);
+    assert(*commonIter1 == 5);
+    assert(*commonIter2 == 1);
+    std::ranges::iter_swap(commonIter2, commonIter1);
+  }
+}
+
+int main(int, char**) {
+  test();
+
+  return 0;
+}

diff  --git a/libcxx/test/std/iterators/predef.iterators/iterators.common/iterator_traits.compile.pass.cpp b/libcxx/test/std/iterators/predef.iterators/iterators.common/iterator_traits.compile.pass.cpp
new file mode 100644
index 0000000000000..8309ab7f732da
--- /dev/null
+++ b/libcxx/test/std/iterators/predef.iterators/iterators.common/iterator_traits.compile.pass.cpp
@@ -0,0 +1,110 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: c++03, c++11, c++14, c++17
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: gcc-10
+
+// template<input_iterator I, class S>
+//   struct iterator_traits<common_iterator<I, S>>;
+
+#include <iterator>
+
+#include "test_macros.h"
+#include "types.h"
+
+void test() {
+  {
+    using Iter = simple_iterator<int*>;
+    using CommonIter = std::common_iterator<Iter, sentinel_type<int*>>;
+    using IterTraits = std::iterator_traits<CommonIter>;
+
+    static_assert(std::same_as<IterTraits::iterator_concept, std::input_iterator_tag>);
+    static_assert(std::same_as<IterTraits::iterator_category, std::input_iterator_tag>);
+    static_assert(std::same_as<IterTraits::value_type, int>);
+    static_assert(std::same_as<IterTraits::
diff erence_type, std::ptr
diff _t>);
+    static_assert(std::same_as<IterTraits::pointer, int*>);
+    static_assert(std::same_as<IterTraits::reference, int&>);
+  }
+  {
+    using Iter = value_iterator<int*>;
+    using CommonIter = std::common_iterator<Iter, sentinel_type<int*>>;
+    using IterTraits = std::iterator_traits<CommonIter>;
+
+    static_assert(std::same_as<IterTraits::iterator_concept, std::input_iterator_tag>);
+    static_assert(std::same_as<IterTraits::iterator_category, std::input_iterator_tag>);
+    static_assert(std::same_as<IterTraits::value_type, int>);
+    static_assert(std::same_as<IterTraits::
diff erence_type, std::ptr
diff _t>);
+    // Note: IterTraits::pointer == __proxy.
+    static_assert(!std::same_as<IterTraits::pointer, int*>);
+    static_assert(std::same_as<IterTraits::reference, int>);
+  }
+  {
+    using Iter = non_const_deref_iterator<int*>;
+    using CommonIter = std::common_iterator<Iter, sentinel_type<int*>>;
+    using IterTraits = std::iterator_traits<CommonIter>;
+
+    static_assert(std::same_as<IterTraits::iterator_concept, std::input_iterator_tag>);
+    static_assert(std::same_as<IterTraits::iterator_category, std::input_iterator_tag>);
+    static_assert(std::same_as<IterTraits::value_type, int>);
+    static_assert(std::same_as<IterTraits::
diff erence_type, std::ptr
diff _t>);
+    static_assert(std::same_as<IterTraits::pointer, void>);
+    static_assert(std::same_as<IterTraits::reference, int&>);
+  }
+  {
+    using Iter = cpp17_input_iterator<int*>;
+    using CommonIter = std::common_iterator<Iter, sentinel_type<int*>>;
+    using IterTraits = std::iterator_traits<CommonIter>;
+
+    static_assert(std::same_as<IterTraits::iterator_concept, std::input_iterator_tag>);
+    static_assert(std::same_as<IterTraits::iterator_category, std::input_iterator_tag>);
+    static_assert(std::same_as<IterTraits::value_type, int>);
+    static_assert(std::same_as<IterTraits::
diff erence_type, std::ptr
diff _t>);
+    static_assert(std::same_as<IterTraits::pointer, const Iter&>);
+    static_assert(std::same_as<IterTraits::reference, int&>);
+  }
+  {
+    using Iter = forward_iterator<int*>;
+    using CommonIter = std::common_iterator<Iter, sentinel_type<int*>>;
+    using IterTraits = std::iterator_traits<CommonIter>;
+
+    static_assert(std::same_as<IterTraits::iterator_concept, std::forward_iterator_tag>);
+    static_assert(std::same_as<IterTraits::iterator_category, std::forward_iterator_tag>);
+    static_assert(std::same_as<IterTraits::value_type, int>);
+    static_assert(std::same_as<IterTraits::
diff erence_type, std::ptr
diff _t>);
+    static_assert(std::same_as<IterTraits::pointer, const Iter&>);
+    static_assert(std::same_as<IterTraits::reference, int&>);
+  }
+  {
+    using Iter = random_access_iterator<int*>;
+    using CommonIter = std::common_iterator<Iter, sentinel_type<int*>>;
+    using IterTraits = std::iterator_traits<CommonIter>;
+
+    static_assert(std::same_as<IterTraits::iterator_concept, std::forward_iterator_tag>);
+    static_assert(std::same_as<IterTraits::iterator_category, std::forward_iterator_tag>);
+    static_assert(std::same_as<IterTraits::value_type, int>);
+    static_assert(std::same_as<IterTraits::
diff erence_type, std::ptr
diff _t>);
+    static_assert(std::same_as<IterTraits::pointer, const Iter&>);
+    static_assert(std::same_as<IterTraits::reference, int&>);
+  }
+
+  // Testing iterator conformance.
+  {
+    static_assert(std::input_iterator<std::common_iterator<cpp17_input_iterator<int*>, sentinel_type<int*>>>);
+    static_assert(std::forward_iterator<std::common_iterator<forward_iterator<int*>, sentinel_type<int*>>>);
+    static_assert(std::forward_iterator<std::common_iterator<random_access_iterator<int*>, sentinel_type<int*>>>);
+    static_assert(std::forward_iterator<std::common_iterator<contiguous_iterator<int*>, sentinel_type<int*>>>);
+    // Even these are only forward.
+    static_assert(!std::bidirectional_iterator<std::common_iterator<random_access_iterator<int*>, sentinel_type<int*>>>);
+    static_assert(!std::bidirectional_iterator<std::common_iterator<contiguous_iterator<int*>, sentinel_type<int*>>>);
+
+    using Iter = std::common_iterator<forward_iterator<int*>, sentinel_type<int*>>;
+    static_assert(std::indirectly_writable<Iter, int>);
+    static_assert(std::indirectly_swappable<Iter, Iter>);
+  }
+}

diff  --git a/libcxx/test/std/iterators/predef.iterators/iterators.common/minus.pass.cpp b/libcxx/test/std/iterators/predef.iterators/iterators.common/minus.pass.cpp
new file mode 100644
index 0000000000000..41f8c77268c93
--- /dev/null
+++ b/libcxx/test/std/iterators/predef.iterators/iterators.common/minus.pass.cpp
@@ -0,0 +1,67 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: c++03, c++11, c++14, c++17
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: gcc-10
+
+// template<sized_sentinel_for<I> I2, sized_sentinel_for<I> S2>
+//   requires sized_sentinel_for<S, I2>
+// friend iter_
diff erence_t<I2> operator-(
+//   const common_iterator& x, const common_iterator<I2, S2>& y);
+
+#include <iterator>
+#include <cassert>
+
+#include "test_macros.h"
+#include "types.h"
+
+void test() {
+  int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
+
+  {
+    auto iter1 = random_access_iterator<int*>(buffer);
+    auto commonIter1 = std::common_iterator<decltype(iter1), sized_sentinel_type<int*>>(iter1);
+    auto commonSent1 = std::common_iterator<decltype(iter1), sized_sentinel_type<int*>>(sized_sentinel_type<int*>{buffer + 8});
+    assert(commonIter1 - commonSent1 == -8);
+    assert(commonSent1 - commonIter1 == 8);
+    assert(commonIter1 - commonIter1 == 0);
+    assert(commonSent1 - commonSent1 == 0);
+  }
+  {
+    auto iter1 = simple_iterator<int*>(buffer);
+    auto iter2 = comparable_iterator<int*>(buffer);
+    auto commonIter1 = std::common_iterator<decltype(iter1), sized_sentinel_type<int*>>(iter1);
+    auto commonIter2 = std::common_iterator<decltype(iter2), sized_sentinel_type<int*>>(iter2);
+
+    assert(commonIter1 - commonIter2 == 0);
+  }
+  {
+    auto iter1 = random_access_iterator<int*>(buffer);
+    const auto commonIter1 = std::common_iterator<decltype(iter1), sized_sentinel_type<int*>>(iter1);
+    const auto commonSent1 = std::common_iterator<decltype(iter1), sized_sentinel_type<int*>>(sized_sentinel_type<int*>{buffer + 8});
+    assert(commonIter1 - commonSent1 == -8);
+    assert(commonSent1 - commonIter1 == 8);
+    assert(commonIter1 - commonIter1 == 0);
+    assert(commonSent1 - commonSent1 == 0);
+  }
+  {
+    auto iter1 = simple_iterator<int*>(buffer);
+    auto iter2 = comparable_iterator<int*>(buffer);
+    const auto commonIter1 = std::common_iterator<decltype(iter1), sized_sentinel_type<int*>>(iter1);
+    const auto commonIter2 = std::common_iterator<decltype(iter2), sized_sentinel_type<int*>>(iter2);
+
+    assert(commonIter1 - commonIter2 == 0);
+  }
+}
+
+int main(int, char**) {
+  test();
+
+  return 0;
+}

diff  --git a/libcxx/test/std/iterators/predef.iterators/iterators.common/plus_plus.pass.cpp b/libcxx/test/std/iterators/predef.iterators/iterators.common/plus_plus.pass.cpp
new file mode 100644
index 0000000000000..4d8ef3984cb00
--- /dev/null
+++ b/libcxx/test/std/iterators/predef.iterators/iterators.common/plus_plus.pass.cpp
@@ -0,0 +1,155 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: c++03, c++11, c++14, c++17
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: gcc-10
+
+// common_iterator& operator++();
+// decltype(auto) operator++(int);
+
+#include <iterator>
+#include <cassert>
+
+#include "test_macros.h"
+#include "types.h"
+
+struct Incomplete;
+
+void test() {
+  int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
+
+  // Reference: http://eel.is/c++draft/iterators.common#common.iter.nav-5
+  // Case 2: can-reference
+  {
+    auto iter1 = simple_iterator<int*>(buffer);
+    auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+    auto commonSent1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
+
+    assert(*(commonIter1++) == 1);
+    assert(*commonIter1 == 2);
+    assert(*(++commonIter1) == 3);
+    assert(*commonIter1 == 3);
+
+    for (auto i = 3; commonIter1 != commonSent1; ++i) {
+      assert(*(commonIter1++) == i);
+    }
+    assert(commonIter1 == commonSent1);
+  }
+
+  // Case 2: can-reference
+  {
+    auto iter1 = value_iterator<int*>(buffer);
+    auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+    auto commonSent1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
+
+    assert(*(commonIter1++) == 1);
+    assert(*commonIter1 == 2);
+    assert(*(++commonIter1) == 3);
+    assert(*commonIter1 == 3);
+
+    for (auto i = 3; commonIter1 != commonSent1; ++i) {
+      assert(*(commonIter1++) == i);
+    }
+    assert(commonIter1 == commonSent1);
+  }
+
+  // Case 3: postfix-proxy
+  {
+    auto iter1 = void_plus_plus_iterator<int*>(buffer);
+    auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+    auto commonSent1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
+
+    assert(*(commonIter1++) == 1);
+    assert(*commonIter1 == 2);
+    assert(*(++commonIter1) == 3);
+    assert(*commonIter1 == 3);
+
+    for (auto i = 3; commonIter1 != commonSent1; ++i) {
+      assert(*(commonIter1++) == i);
+    }
+    assert(commonIter1 == commonSent1);
+  }
+
+  // Case 2: where this is not referencable or move constructible
+  {
+    auto iter1 = value_type_not_move_constructible_iterator<int*>(buffer);
+    auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+    auto commonSent1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
+
+    commonIter1++;
+    // Note: postfix operator++ returns void.
+    // assert(*(commonIter1++) == 1);
+    assert(*commonIter1 == 2);
+    assert(*(++commonIter1) == 3);
+    assert(*commonIter1 == 3);
+
+    for (auto i = 3; commonIter1 != commonSent1; ++i) {
+      assert(*commonIter1 == i);
+      commonIter1++;
+    }
+    assert(commonIter1 == commonSent1);
+  }
+
+  // Case 2: can-reference
+  {
+    auto iter1 = cpp17_input_iterator<int*>(buffer);
+    auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+    auto commonSent1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
+
+    assert(*(commonIter1++) == 1);
+    assert(*commonIter1 == 2);
+    assert(*(++commonIter1) == 3);
+    assert(*commonIter1 == 3);
+
+    for (auto i = 3; commonIter1 != commonSent1; ++i) {
+      assert(*(commonIter1++) == i);
+    }
+    assert(commonIter1 == commonSent1);
+  }
+
+  // Case 1: forward_iterator
+  {
+    auto iter1 = forward_iterator<int*>(buffer);
+    auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+    auto commonSent1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
+
+    assert(*(commonIter1++) == 1);
+    assert(*commonIter1 == 2);
+    assert(*(++commonIter1) == 3);
+    assert(*commonIter1 == 3);
+
+    for (auto i = 3; commonIter1 != commonSent1; ++i) {
+      assert(*(commonIter1++) == i);
+    }
+    assert(commonIter1 == commonSent1);
+  }
+
+  // Case 1: forward_iterator
+  {
+    auto iter1 = random_access_iterator<int*>(buffer);
+    auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
+    auto commonSent1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
+
+    assert(*(commonIter1++) == 1);
+    assert(*commonIter1 == 2);
+    assert(*(++commonIter1) == 3);
+    assert(*commonIter1 == 3);
+
+    for (auto i = 3; commonIter1 != commonSent1; ++i) {
+      assert(*(commonIter1++) == i);
+    }
+    assert(commonIter1 == commonSent1);
+  }
+}
+
+int main(int, char**) {
+  test();
+
+  return 0;
+}

diff  --git a/libcxx/test/std/iterators/predef.iterators/iterators.common/types.h b/libcxx/test/std/iterators/predef.iterators/iterators.common/types.h
new file mode 100644
index 0000000000000..d5068b3cf013f
--- /dev/null
+++ b/libcxx/test/std/iterators/predef.iterators/iterators.common/types.h
@@ -0,0 +1,316 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef TEST_STD_RANGES_ITERATORS_PREDEF_ITERATORS_ITERATORS_COMMON_TYPES_H
+#define TEST_STD_RANGES_ITERATORS_PREDEF_ITERATORS_ITERATORS_COMMON_TYPES_H
+
+#include "test_macros.h"
+#include "test_iterators.h"
+
+template <class>
+class assignable_iterator;
+
+template <class It>
+class simple_iterator
+{
+    It it_;
+
+public:
+    typedef          std::input_iterator_tag                   iterator_category;
+    typedef typename std::iterator_traits<It>::value_type      value_type;
+    typedef typename std::iterator_traits<It>::
diff erence_type 
diff erence_type;
+    typedef It                                                 pointer;
+    typedef typename std::iterator_traits<It>::reference       reference;
+
+    constexpr It base() const {return it_;}
+
+    simple_iterator() = default;
+    explicit constexpr simple_iterator(It it) : it_(it) {}
+
+    constexpr reference operator*() const {return *it_;}
+
+    constexpr simple_iterator& operator++() {++it_; return *this;}
+    constexpr simple_iterator operator++(int)
+        {simple_iterator tmp(*this); ++(*this); return tmp;}
+};
+
+template <class It>
+class value_iterator
+{
+    It it_;
+
+public:
+    typedef          std::input_iterator_tag                   iterator_category;
+    typedef typename std::iterator_traits<It>::value_type      value_type;
+    typedef typename std::iterator_traits<It>::
diff erence_type 
diff erence_type;
+    typedef It                                                 pointer;
+    typedef typename std::iterator_traits<It>::reference       reference;
+
+    constexpr It base() const {return it_;}
+
+    value_iterator() = default;
+    explicit constexpr value_iterator(It it) : it_(it) {}
+
+    constexpr value_type operator*() const {return std::move(*it_);}
+
+    constexpr value_iterator& operator++() {++it_; return *this;}
+    constexpr value_iterator operator++(int)
+        {value_iterator tmp(*this); ++(*this); return tmp;}
+};
+
+template <class It>
+class void_plus_plus_iterator
+{
+    It it_;
+
+public:
+    typedef          std::input_iterator_tag                   iterator_category;
+    typedef typename std::iterator_traits<It>::value_type      value_type;
+    typedef typename std::iterator_traits<It>::
diff erence_type 
diff erence_type;
+    typedef It                                                 pointer;
+    typedef typename std::iterator_traits<It>::reference       reference;
+
+    constexpr It base() const {return it_;}
+
+    void_plus_plus_iterator() = default;
+    explicit constexpr void_plus_plus_iterator(It it) : it_(it) {}
+
+    constexpr value_type operator*() const {return std::move(*it_);}
+
+    constexpr void_plus_plus_iterator& operator++() {++it_; return *this;}
+    constexpr void operator++(int) {++(*this);}
+};
+
+// Not referenceable, constructible, and not move constructible.
+template <class It>
+class value_type_not_move_constructible_iterator
+{
+    It it_;
+
+public:
+    template<class T>
+    struct hold {
+      T value_;
+      hold(T v) : value_(v) {}
+      hold(const hold&) = delete;
+      hold(hold&&) = delete;
+    };
+
+    typedef          std::input_iterator_tag                   iterator_category;
+    typedef typename std::iterator_traits<It>::value_type      underlying_value_type;
+    typedef hold<underlying_value_type>                        value_type;
+    typedef typename std::iterator_traits<It>::
diff erence_type 
diff erence_type;
+    typedef It                                                 pointer;
+    typedef typename std::iterator_traits<It>::reference       reference;
+
+    constexpr It base() const {return it_;}
+
+    value_type_not_move_constructible_iterator() = default;
+    explicit constexpr value_type_not_move_constructible_iterator(It it) : it_(it) {}
+
+    constexpr underlying_value_type operator*() const {return std::move(*it_);}
+
+    constexpr value_type_not_move_constructible_iterator& operator++() {++it_; return *this;}
+    constexpr void operator++(int) {++(*this);}
+};
+
+template <class It>
+class comparable_iterator
+{
+    It it_;
+
+public:
+    typedef          std::input_iterator_tag                   iterator_category;
+    typedef typename std::iterator_traits<It>::value_type      value_type;
+    typedef typename std::iterator_traits<It>::
diff erence_type 
diff erence_type;
+    typedef It                                                 pointer;
+    typedef typename std::iterator_traits<It>::reference       reference;
+
+    constexpr It base() const {return it_;}
+
+    comparable_iterator() = default;
+    explicit constexpr comparable_iterator(It it) : it_(it) {}
+
+    constexpr reference operator*() const {return *it_;}
+
+    constexpr comparable_iterator& operator++() {++it_; return *this;}
+    constexpr comparable_iterator operator++(int)
+        {comparable_iterator tmp(*this); ++(*this); return tmp;}
+
+    friend constexpr bool operator==(const comparable_iterator& lhs, const simple_iterator<It>& rhs) {
+      return lhs.base() == rhs.base();
+    }
+    friend constexpr bool operator==(const simple_iterator<It>& lhs, const comparable_iterator& rhs) {
+      return lhs.base() == rhs.base();
+    }
+
+    friend constexpr auto operator-(const comparable_iterator& lhs, const simple_iterator<It>& rhs) {
+      return lhs.base() - rhs.base();
+    }
+    friend constexpr auto operator-(const simple_iterator<It>& lhs, const comparable_iterator& rhs) {
+      return lhs.base() - rhs.base();
+    }
+};
+
+template <class It>
+class convertible_iterator
+{
+    It it_;
+
+public:
+    typedef          std::input_iterator_tag                   iterator_category;
+    typedef typename std::iterator_traits<It>::value_type      value_type;
+    typedef typename std::iterator_traits<It>::
diff erence_type 
diff erence_type;
+    typedef It                                                 pointer;
+    typedef typename std::iterator_traits<It>::reference       reference;
+
+    constexpr It base() const {return it_;}
+
+    convertible_iterator() = default;
+    explicit constexpr convertible_iterator(It it) : it_(it) {}
+
+    constexpr reference operator*() const {return *it_;}
+
+    constexpr convertible_iterator& operator++() {++it_; return *this;}
+    constexpr convertible_iterator operator++(int)
+        {convertible_iterator tmp(*this); ++(*this); return tmp;}
+
+    operator forward_iterator<It>() const { return forward_iterator<It>(it_); }
+};
+
+template <class It>
+class non_const_deref_iterator
+{
+    It it_;
+
+public:
+    typedef          std::input_iterator_tag                   iterator_category;
+    typedef typename std::iterator_traits<It>::value_type      value_type;
+    typedef typename std::iterator_traits<It>::
diff erence_type 
diff erence_type;
+    typedef It                                                 pointer;
+    typedef typename std::iterator_traits<It>::reference       reference;
+
+    constexpr It base() const {return it_;}
+
+    non_const_deref_iterator() = default;
+    explicit constexpr non_const_deref_iterator(It it) : it_(it) {}
+
+    constexpr reference operator*() {return *it_;} // Note: non-const.
+
+    constexpr non_const_deref_iterator& operator++() {++it_; return *this;}
+    constexpr non_const_deref_iterator operator++(int)
+        {non_const_deref_iterator tmp(*this); ++(*this); return tmp;}
+};
+
+template<class T>
+struct sentinel_type {
+  T base;
+
+  template<class U>
+  friend constexpr bool operator==(const sentinel_type& lhs, const U& rhs) { return lhs.base == rhs.base(); }
+  template<class U>
+  friend constexpr bool operator==(const U& lhs, const sentinel_type& rhs) { return lhs.base() == rhs.base; }
+};
+
+template<class T>
+struct sized_sentinel_type {
+  T base;
+
+  template<class U>
+  friend constexpr bool operator==(const sized_sentinel_type& lhs, const U& rhs) { return lhs.base - rhs.base(); }
+  template<class U>
+  friend constexpr bool operator==(const U& lhs, const sized_sentinel_type& rhs) { return lhs.base() - rhs.base; }
+  template<class U>
+  friend constexpr auto operator- (const sized_sentinel_type& lhs, const U& rhs) { return lhs.base - rhs.base(); }
+  template<class U>
+  friend constexpr auto operator- (const U& lhs, const sized_sentinel_type& rhs) { return lhs.base() - rhs.base; }
+};
+
+template <class It>
+class assignable_iterator
+{
+    It it_;
+
+public:
+    typedef          std::input_iterator_tag                   iterator_category;
+    typedef typename std::iterator_traits<It>::value_type      value_type;
+    typedef typename std::iterator_traits<It>::
diff erence_type 
diff erence_type;
+    typedef It                                                 pointer;
+    typedef typename std::iterator_traits<It>::reference       reference;
+
+    constexpr It base() const {return it_;}
+
+    assignable_iterator() = default;
+    explicit constexpr assignable_iterator(It it) : it_(it) {}
+
+    assignable_iterator(const forward_iterator<It>& it) : it_(it.base()) {}
+    assignable_iterator(const sentinel_type<It>& it) : it_(it.base) {}
+
+    constexpr reference operator*() const {return *it_;}
+
+    constexpr assignable_iterator& operator++() {++it_; return *this;}
+    constexpr assignable_iterator operator++(int)
+        {assignable_iterator tmp(*this); ++(*this); return tmp;}
+
+    assignable_iterator& operator=(const forward_iterator<It> &other) {
+      it_ = other.base();
+      return *this;
+    }
+
+    assignable_iterator& operator=(const sentinel_type<It> &other) {
+      it_ = other.base;
+      return *this;
+    }
+};
+
+#ifndef TEST_HAS_NO_EXCEPTIONS
+template<class T>
+struct sentinel_throws_on_convert {
+  T base;
+
+  template<class U>
+  friend constexpr bool operator==(const sentinel_throws_on_convert& lhs, const U& rhs) { return lhs.base == rhs.base(); }
+  template<class U>
+  friend constexpr bool operator==(const U& lhs, const sentinel_throws_on_convert& rhs) { return lhs.base() == rhs.base; }
+
+  operator sentinel_type<int*>() const { throw 42; }
+};
+
+template <class It>
+class maybe_valueless_iterator
+{
+    It it_;
+
+public:
+    typedef          std::input_iterator_tag                   iterator_category;
+    typedef typename std::iterator_traits<It>::value_type      value_type;
+    typedef typename std::iterator_traits<It>::
diff erence_type 
diff erence_type;
+    typedef It                                                 pointer;
+    typedef typename std::iterator_traits<It>::reference       reference;
+
+    constexpr It base() const {return it_;}
+
+    maybe_valueless_iterator() = default;
+    explicit constexpr maybe_valueless_iterator(It it) : it_(it) {}
+
+    maybe_valueless_iterator(const forward_iterator<It>& it) : it_(it.base()) {}
+
+    constexpr reference operator*() const {return *it_;}
+
+    constexpr maybe_valueless_iterator& operator++() {++it_; return *this;}
+    constexpr maybe_valueless_iterator operator++(int)
+        {maybe_valueless_iterator tmp(*this); ++(*this); return tmp;}
+
+    maybe_valueless_iterator& operator=(const forward_iterator<It> &other) {
+      it_ = other.base();
+      return *this;
+    }
+};
+#endif // TEST_HAS_NO_EXCEPTIONS
+
+#endif // TEST_STD_RANGES_ITERATORS_PREDEF_ITERATORS_ITERATORS_COMMON_TYPES_H

diff  --git a/libcxx/test/support/test_iterators.h b/libcxx/test/support/test_iterators.h
index bb1671b909352..7e094428b72f4 100644
--- a/libcxx/test/support/test_iterators.h
+++ b/libcxx/test/support/test_iterators.h
@@ -161,6 +161,59 @@ operator!=(const forward_iterator<T>& x, const forward_iterator<U>& y)
     return !(x == y);
 }
 
+template <class It>
+class non_default_constructible_iterator
+{
+    It it_;
+
+    template <class U> friend class non_default_constructible_iterator;
+public:
+    typedef          std::input_iterator_tag                   iterator_category;
+    typedef typename std::iterator_traits<It>::value_type      value_type;
+    typedef typename std::iterator_traits<It>::
diff erence_type 
diff erence_type;
+    typedef It                                                 pointer;
+    typedef typename std::iterator_traits<It>::reference       reference;
+
+    TEST_CONSTEXPR_CXX14 It base() const {return it_;}
+
+    non_default_constructible_iterator() = delete;
+
+    explicit TEST_CONSTEXPR_CXX14 non_default_constructible_iterator(It it) : it_(it) {}
+    template <class U>
+        TEST_CONSTEXPR_CXX14 non_default_constructible_iterator(const non_default_constructible_iterator<U>& u) :it_(u.it_) {}
+
+    TEST_CONSTEXPR_CXX14 reference operator*() const {return *it_;}
+    TEST_CONSTEXPR_CXX14 pointer operator->() const {return it_;}
+
+    TEST_CONSTEXPR_CXX14 non_default_constructible_iterator& operator++() {++it_; return *this;}
+    TEST_CONSTEXPR_CXX14 non_default_constructible_iterator operator++(int)
+        {non_default_constructible_iterator tmp(*this); ++(*this); return tmp;}
+
+    friend TEST_CONSTEXPR_CXX14 bool operator==(const non_default_constructible_iterator& x, const non_default_constructible_iterator& y)
+        {return x.it_ == y.it_;}
+    friend TEST_CONSTEXPR_CXX14 bool operator!=(const non_default_constructible_iterator& x, const non_default_constructible_iterator& y)
+        {return !(x == y);}
+
+    template <class T>
+    void operator,(T const &) DELETE_FUNCTION;
+};
+
+template <class T, class U>
+inline
+bool TEST_CONSTEXPR_CXX14
+operator==(const non_default_constructible_iterator<T>& x, const non_default_constructible_iterator<U>& y)
+{
+    return x.base() == y.base();
+}
+
+template <class T, class U>
+inline
+bool TEST_CONSTEXPR_CXX14
+operator!=(const non_default_constructible_iterator<T>& x, const non_default_constructible_iterator<U>& y)
+{
+    return !(x == y);
+}
+
 template <class It>
 class bidirectional_iterator
 {


        


More information about the libcxx-commits mailing list