diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -14,6 +14,7 @@
   __hash_table
   __iterator/advance.h
   __iterator/concepts.h
+  __iterator/distance.h
   __iterator/incrementable_traits.h
   __iterator/iter_move.h
   __iterator/iterator_traits.h
diff --git a/libcxx/include/__iterator/distance.h b/libcxx/include/__iterator/distance.h
new file mode 100644
--- /dev/null
+++ b/libcxx/include/__iterator/distance.h
@@ -0,0 +1,67 @@
+// -*- 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_DISTANCE_H
+#define _LIBCPP___ITERATOR_DISTANCE_H
+
+#include <__config>
+#include <__function_like.h>
+#include <__iterator/concepts.h>
+#include <__iterator/incrementable_traits.h>
+#include <__ranges/concepts.h>
+
+#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)
+
+namespace ranges {
+struct __distance_fn final : __function_like {
+  constexpr explicit __distance_fn(__tag __x) noexcept : __function_like(__x) {}
+
+  template <input_or_output_iterator _Ip, sentinel_for<_Ip> _Sp>
+  [[nodiscard]] constexpr iter_difference_t<_Ip> operator()(_Ip __first, _Sp __last) const {
+    if constexpr (sized_sentinel_for<_Sp, _Ip>) {
+      return __last - __first;
+    }
+
+    auto __distance = iter_difference_t<_Ip>(0);
+    for (; __first != __last; ++__first) {
+      ++__distance;
+    }
+
+    return __distance;
+  }
+
+  template <range _Rp>
+  [[nodiscard]] constexpr range_difference_t<_Rp> operator()(_Rp&& __r) const {
+    if constexpr (sized_range<_Rp>) {
+      return static_cast<range_difference_t<_Rp> >(ranges::size(__r));
+    } else {
+      return (*this)(ranges::begin(__r), ranges::end(__r));
+    }
+  }
+};
+
+inline constexpr auto distance = __distance_fn(__function_like::__value);
+} // namespace ranges
+
+#endif // !defined(_LIBCPP_HAS_NO_RANGES)
+
+_LIBCPP_END_NAMESPACE_STD
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___ITERATOR_DISTANCE_H
diff --git a/libcxx/include/iterator b/libcxx/include/iterator
--- a/libcxx/include/iterator
+++ b/libcxx/include/iterator
@@ -485,6 +485,7 @@
 #include <__functional_base>
 #include <__iterator/advance.h>
 #include <__iterator/concepts.h>
+#include <__iterator/distance.h>
 #include <__iterator/incrementable_traits.h>
 #include <__iterator/iter_move.h>
 #include <__iterator/iterator_traits.h>
diff --git a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.distance/distance.pass.cpp b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.distance/distance.pass.cpp
--- a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.distance/distance.pass.cpp
+++ b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.distance/distance.pass.cpp
@@ -10,12 +10,178 @@
 // UNSUPPORTED: libcpp-no-concepts
 // UNSUPPORTED: gcc-10
 
-// std::forward_iterator;
+// std::ranges::distance
 
 #include <iterator>
 
-#include <concepts>
+#include <array>
+#include <cassert>
+#include <ranges>
+#include <utility>
 
 #include "test_iterators.h"
+#include "test_range.h"
+#include "test_standard_function.h"
 
-int main(int, char**) { return 0; }
+static_assert(is_function_like<decltype(std::ranges::distance)>());
+
+constexpr auto range = std::array{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+using iterator = decltype(range)::const_iterator;
+
+template <class T>
+constexpr bool operator==(external_stride_counting_iterator<T> const& x, sentinel_wrapper<iterator> const& y) {
+  return x.base() == y;
+}
+
+template <template <class...> class I>
+requires requires {
+  typename I<iterator>;
+}
+constexpr bool operator==(I<iterator> const& x, sentinel_wrapper<iterator> const& y) { return x.base() == y; }
+
+namespace iterator_sentinel {
+template <std::input_or_output_iterator I>
+constexpr void check_iterator_sentinel() {
+  assert(std::ranges::distance(I(range.begin()), sentinel_wrapper(range.begin() + 5)) == 5);
+  assert(std::ranges::distance(I(range.begin()), sentinel_wrapper(range.begin())) == 0);
+
+  auto counter = std::ptrdiff_t(0);
+  assert(std::ranges::distance(external_stride_counting_iterator(I(range.begin()), counter),
+                               sentinel_wrapper(range.end())) == 10);
+  assert(counter == 10);
+}
+
+template <std::input_or_output_iterator I>
+constexpr void check_iterator_sized_sentinel() {
+  assert(std::ranges::distance(I(range.begin()), sized_sentinel_wrapper(I(range.end()))) == 10);
+  assert(std::ranges::distance(I(range.begin()), sized_sentinel_wrapper(I(range.begin()))) == 0);
+
+  auto counter = std::ptrdiff_t(0);
+  assert((std::ranges::distance(
+              external_stride_counting_iterator(I(range.begin()), counter),
+              sized_sentinel_wrapper(external_stride_counting_iterator(I(range.begin() + 5), counter))) == 5));
+  assert(counter == 0);
+
+  counter = 0;
+  assert(std::ranges::distance(external_stride_counting_iterator(I(range.begin() + 2), counter),
+                               external_stride_counting_iterator(I(range.begin()), counter)) == -2);
+  assert(counter == 0);
+}
+
+constexpr bool test() {
+  check_iterator_sentinel<cpp17_input_iterator<iterator> >();
+  check_iterator_sentinel<cpp20_input_iterator<iterator> >();
+  check_iterator_sentinel<forward_iterator<iterator> >();
+  check_iterator_sentinel<bidirectional_iterator<iterator> >();
+  check_iterator_sentinel<random_access_iterator<iterator> >();
+  check_iterator_sentinel<contiguous_iterator<iterator> >();
+
+  check_iterator_sized_sentinel<random_access_iterator<iterator> >();
+  check_iterator_sized_sentinel<contiguous_iterator<iterator> >();
+  return true;
+}
+} // namespace iterator_sentinel
+
+namespace range_based {
+template <std::input_or_output_iterator I>
+class external_stride_counting_range {
+public:
+  constexpr external_stride_counting_range(I first, iterator last) : first_(std::move(first), counter_), last_(last) {}
+
+  [[nodiscard]] constexpr external_stride_counting_iterator<I> begin() {
+    if constexpr (std::copy_constructible<I>)
+      return first_;
+    else
+      return std::move(first_);
+  }
+
+  [[nodiscard]] constexpr external_stride_counting_iterator<I> begin() const { return first_; }
+
+  [[nodiscard]] constexpr sentinel_wrapper<iterator> end() const { return last_; }
+
+  [[nodiscard]] constexpr std::ptrdiff_t counter() const { return counter_; }
+  constexpr void reset() { counter_ = 0; }
+
+private:
+  std::ptrdiff_t counter_ = 0;
+  external_stride_counting_iterator<I> first_;
+  sentinel_wrapper<iterator> last_;
+};
+
+template <std::input_or_output_iterator I>
+constexpr void check_range_case() {
+  auto r = external_stride_counting_range<I>(I(range.begin()), range.end());
+  assert(std::ranges::distance(r) == 10);
+  assert(r.counter() == 10);
+
+  r.reset();
+  assert(std::ranges::distance(std::as_const(r)) == 10);
+  assert(r.counter() == 10);
+
+  r.reset();
+  assert(std::ranges::distance(std::move(r)) == 10); // use after move okay
+  assert(r.counter() == 10);
+}
+
+template <std::input_or_output_iterator I>
+class sized_range {
+public:
+  constexpr sized_range(std::size_t const size) : size_(size) {}
+
+  external_stride_counting_iterator<I> begin();
+  external_stride_counting_iterator<I> begin() const;
+  sentinel_wrapper<iterator> end() const;
+
+  [[nodiscard]] constexpr std::size_t size() const { return size_; }
+
+private:
+  std::size_t size_ = 0;
+};
+
+template <std::input_or_output_iterator I>
+constexpr void check_sized_range_case() {
+  auto r = sized_range<I>(42);
+  assert(std::ranges::distance(r) == 42);
+  assert(std::ranges::distance(std::as_const(r)) == 42);
+  assert(std::ranges::distance(std::move(r)) == 42);
+}
+
+constexpr bool test() {
+  check_range_case<cpp17_input_iterator<iterator> >();
+  // cpp20_input_iterator special cased below
+  check_range_case<forward_iterator<iterator> >();
+  check_range_case<bidirectional_iterator<iterator> >();
+  check_range_case<random_access_iterator<iterator> >();
+  check_range_case<contiguous_iterator<iterator> >();
+  check_range_case<output_iterator<iterator> >();
+
+  check_sized_range_case<cpp17_input_iterator<iterator> >();
+  check_sized_range_case<cpp20_input_iterator<iterator> >();
+  check_sized_range_case<forward_iterator<iterator> >();
+  check_sized_range_case<bidirectional_iterator<iterator> >();
+  check_sized_range_case<random_access_iterator<iterator> >();
+  check_sized_range_case<contiguous_iterator<iterator> >();
+  check_sized_range_case<output_iterator<iterator> >();
+
+  {
+    auto r = external_stride_counting_range<cpp20_input_iterator<iterator> >(cpp20_input_iterator(range.begin()),
+                                                                             range.end());
+    assert(std::ranges::distance(r) == 10);
+    assert(r.counter() == 10);
+
+    r.reset();
+    assert(std::ranges::distance(std::move(r)) == 10); // use after move okay
+    assert(r.counter() == 10);
+  }
+  return true;
+}
+} // namespace range_based
+
+int main(int, char**) {
+  static_assert(iterator_sentinel::test());
+  iterator_sentinel::test();
+
+  static_assert(range_based::test());
+  range_based::test();
+  return 0;
+}
diff --git a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.distance/distance.verify.cpp b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.distance/distance.verify.cpp
new file mode 100644
--- /dev/null
+++ b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.distance/distance.verify.cpp
@@ -0,0 +1,99 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// ranges::distance
+
+#include <iterator>
+
+namespace std::ranges {
+class forward_iterator {
+public:
+  using value_type = int;
+  using difference_type = std::ptrdiff_t;
+  using iterator_category = std::forward_iterator_tag;
+
+  forward_iterator() = default;
+
+  value_type operator*() const;
+  forward_iterator& operator++();
+  forward_iterator operator++(int);
+
+  bool operator==(forward_iterator const&) const = default;
+};
+
+struct some_range {
+  int* begin() const;
+  int* end() const;
+};
+} // namespace std::ranges
+
+// The function templates defined in [range.iter.ops] are not found by argument-dependent name lookup ([basic.lookup.argdep]).
+void no_adl_participation() {
+  std::ranges::forward_iterator i;
+  distance(i, i); // expected-error {{use of undeclared identifier 'distance'}}
+
+  std::ranges::some_range r;
+  distance(r); // expected-error {{use of undeclared identifier 'distance'}}
+}
+
+namespace test {
+template <class>
+class forward_iterator {
+public:
+  using value_type = int;
+  using difference_type = std::ptrdiff_t;
+  using iterator_category = std::forward_iterator_tag;
+
+  forward_iterator() = default;
+
+  value_type operator*() const;
+  forward_iterator& operator++();
+  forward_iterator operator++(int);
+
+  bool operator==(forward_iterator const&) const = default;
+};
+
+template <class I>
+void distance(forward_iterator<I>, forward_iterator<I>) {
+  static_assert(std::same_as<I, I*>);
+}
+
+template <class>
+struct range {
+  int* begin() const;
+  int* end() const;
+};
+
+template <class R>
+void distance(range<R>) {
+  static_assert(std::same_as<R, R*>);
+}
+} // namespace test
+
+// When found by unqualified ([basic.lookup.unqual]) name lookup for the postfix-expression in a
+// function call ([expr.call]), they inhibit argument-dependent name lookup.
+void adl_inhibition() {
+  test::forward_iterator<int*> i;
+  test::range<int> r;
+
+  using std::ranges::distance;
+
+  distance(i, i); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  distance(r);    // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+}
+
+void correct_interface() {
+  int i = 0;
+  (void)std::ranges::distance(1, nullptr); // expected-error {{no matching function for call}}
+  (void)std::ranges::distance(&i, 1);      // expected-error {{no matching function for call}}
+  (void)std::ranges::distance(i);          // expected-error {{no matching function for call}}
+}
diff --git a/libcxx/test/support/test_iterators.h b/libcxx/test/support/test_iterators.h
--- a/libcxx/test/support/test_iterators.h
+++ b/libcxx/test/support/test_iterators.h
@@ -861,16 +861,175 @@
   difference_type stride_displacement_ = 0;
 };
 
+// std::ranges::distance doesn't give back an iterator, so we need to ensure the counter is external
+// to our iterator for inspection.
+template <std::input_or_output_iterator I>
+class external_stride_counting_iterator {
+public:
+  using value_type = typename iter_value_or_void<I>::type;
+  using difference_type = std::iter_difference_t<I>;
+  using iterator_concept = iterator_concept_t<I>;
+
+  external_stride_counting_iterator() = default;
+
+  constexpr explicit external_stride_counting_iterator(I current, difference_type& counter) : base_(std::move(current)), counter_(&counter) {}
+
+  [[nodiscard]] constexpr I const& base() const& requires std::copyable<I> { return base_; }
+
+  [[nodiscard]] constexpr I base() && { return std::move(base_); }
+
+  [[nodiscard]] constexpr decltype(auto) operator*() const { return *base_; }
+
+  [[nodiscard]] constexpr decltype(auto) operator[](difference_type const n) const { return base_[n]; }
+
+  constexpr external_stride_counting_iterator& operator++()
+  {
+    ++base_;
+    ++*counter_;
+    return *this;
+  }
+
+  constexpr void operator++(int) { ++*this; }
+
+  constexpr external_stride_counting_iterator operator++(int)
+  requires std::forward_iterator<I>
+  {
+    auto temp = *this;
+    ++*this;
+    return temp;
+  }
+
+  constexpr external_stride_counting_iterator& operator--()
+  requires std::bidirectional_iterator<I>
+  {
+    --base_;
+    ++*counter_;
+    return *this;
+  }
+
+  [[nodiscard]] constexpr external_stride_counting_iterator operator--(int)
+  requires std::bidirectional_iterator<I>
+  {
+    auto temp = *this;
+    --*this;
+    return temp;
+  }
+
+  constexpr external_stride_counting_iterator& operator+=(difference_type const n)
+  requires std::random_access_iterator<I>
+  {
+    base_ += n;
+    ++*counter_;
+    return *this;
+  }
+
+  constexpr external_stride_counting_iterator& operator-=(difference_type const n)
+  requires std::random_access_iterator<I>
+  {
+    base_ -= n;
+    ++*counter_;
+    return *this;
+  }
+
+  [[nodiscard]] constexpr friend external_stride_counting_iterator operator+(external_stride_counting_iterator i, difference_type const n)
+  requires std::random_access_iterator<I>
+  {
+    return i += n;
+  }
+
+  [[nodiscard]] constexpr friend external_stride_counting_iterator operator+(difference_type const n, external_stride_counting_iterator i)
+  requires std::random_access_iterator<I>
+  {
+    return i += n;
+  }
+
+  [[nodiscard]] constexpr friend external_stride_counting_iterator operator-(external_stride_counting_iterator i, difference_type const n)
+  requires std::random_access_iterator<I>
+  {
+    return i -= n;
+  }
+
+  [[nodiscard]] constexpr friend difference_type operator-(external_stride_counting_iterator const& x, external_stride_counting_iterator const& y)
+  requires std::sized_sentinel_for<I, I>
+  {
+    return x.base() - y.base();
+  }
+
+  constexpr bool operator==(external_stride_counting_iterator const& other) const
+  requires std::sentinel_for<I, I>
+  {
+    return base_ == other.base_;
+  }
+
+  template <std::sentinel_for<I> S>
+  constexpr bool operator==(S const last) const
+  {
+      return base_ == last;
+  }
+
+  constexpr friend bool operator<(external_stride_counting_iterator const& x, external_stride_counting_iterator const& y)
+  requires std::random_access_iterator<I>
+  {
+    return x.base_ < y.base_;
+  }
+
+  constexpr friend bool operator>(external_stride_counting_iterator const& x, external_stride_counting_iterator const& y)
+  requires std::random_access_iterator<I>
+  {
+    return y < x;
+  }
+
+  constexpr friend bool operator<=(external_stride_counting_iterator const& x, external_stride_counting_iterator const& y)
+  requires std::random_access_iterator<I>
+  {
+    return !(y < x);
+  }
+
+  constexpr friend bool operator>=(external_stride_counting_iterator const& x, external_stride_counting_iterator const& y)
+  requires std::random_access_iterator<I>
+  {
+    return !(x < y);
+  }
+
+private:
+  I base_ = I();
+  difference_type* counter_ = nullptr;
+};
+
 template <std::input_or_output_iterator I>
 class sentinel_wrapper {
 public:
   sentinel_wrapper() = default;
   constexpr explicit sentinel_wrapper(I base) : base_(std::move(base)) {}
 
+  constexpr bool operator==(I const& other) const requires std::sentinel_for<I, I> {
+    return base_ == other;
+  }
+
+private:
+  I base_ = I();
+};
+
+template <std::input_or_output_iterator I>
+class sized_sentinel_wrapper {
+public:
+  sized_sentinel_wrapper() = default;
+  constexpr explicit sized_sentinel_wrapper(I base) : base_(std::move(base)) {}
+
   constexpr bool operator==(I const& other) const requires std::equality_comparable<I> {
     return base_ == other;
   }
 
+  [[nodiscard]] friend constexpr std::iter_difference_t<I> operator-(sized_sentinel_wrapper const& s, I const& i)
+  {
+    return s.base_ - i;
+  }
+
+  [[nodiscard]] friend constexpr std::iter_difference_t<I> operator-(I const& i, sized_sentinel_wrapper const& s)
+  {
+    return i - s.base_;
+  }
+
 private:
   I base_ = I();
 };