diff --git a/libcxx/include/iterator b/libcxx/include/iterator
--- a/libcxx/include/iterator
+++ b/libcxx/include/iterator
@@ -18,7 +18,12 @@
 namespace std
 {
 template<class> struct incrementable_traits;       // since C++20
+template<class T>
+  using iter_difference_t = see below;             // since C++20
+
 template<class> struct indirectly_readable_traits; // since C++20
+template<class T>
+  using iter_value_t = see below;                  // since C++20
 
 template<class Iterator>
 struct iterator_traits;
@@ -428,6 +433,9 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
+template <class _Iter>
+struct _LIBCPP_TEMPLATE_VIS iterator_traits;
+
 #if !defined(_LIBCPP_HAS_NO_RANGES)
 
 template<class _Tp>
@@ -475,7 +483,15 @@
   using difference_type = make_signed_t<decltype(declval<_Tp>() - declval<_Tp>())>;
 };
 
-// TODO(cjdb): add iter_difference_t once iterator_traits is cleaned up.
+// Let `RI` be `remove_­cvref_­t<I>`. The type `iter_­difference_­t<I>` denotes
+// `incrementable_­traits<RI>::difference_­type` if `iterator_­traits<RI>` names a specialization
+// generated from the primary template, and `iterator_­traits<R[I]>::difference_­type` otherwise.
+template <class _Ip>
+using iter_difference_t =
+    typename conditional_t<
+      __is_primary_template<iterator_traits<remove_cvref_t<_Ip>>>::value,
+      incrementable_traits<remove_cvref_t<_Ip>>,
+      iterator_traits<remove_cvref_t<_Ip>>>::difference_type;
 
 // [readable.traits]
 template<class> struct __cond_value_type {};
@@ -523,14 +539,21 @@
 struct indirectly_readable_traits<_Tp>
   : __cond_value_type<typename _Tp::value_type> {};
 
+// Let `RI` be `remove_­cvref_­t<I>`. The type `iter_­value_­t<I>` denotes
+// `indirectly_­readable_­traits<RI>::value_­type` if `iterator_­traits<RI>` names a specialization
+// generated from the primary template, and `iterator_­traits<RI>::value_­type` otherwise.
+template<class _Ip>
+using iter_value_t =
+    typename conditional_t<
+      __is_primary_template<iterator_traits<remove_cvref_t<_Ip>>>::value,
+      indirectly_readable_traits<remove_cvref_t<_Ip>>,
+      iterator_traits<remove_cvref_t<_Ip>>>::value_type;
+
 // [iterator.traits]
 template<__dereferenceable _Tp>
 using iter_reference_t = decltype(*declval<_Tp&>());
 #endif // !defined(_LIBCPP_HAS_NO_RANGES)
 
-template <class _Iter>
-struct _LIBCPP_TEMPLATE_VIS iterator_traits;
-
 struct _LIBCPP_TEMPLATE_VIS input_iterator_tag {};
 struct _LIBCPP_TEMPLATE_VIS output_iterator_tag {};
 struct _LIBCPP_TEMPLATE_VIS forward_iterator_tag       : public input_iterator_tag {};
diff --git a/libcxx/test/std/iterators/iterator.requirements/iterator.assoc.types/incrementable.traits/iter_difference_t.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/iterator.assoc.types/incrementable.traits/iter_difference_t.pass.cpp
new file mode 100644
--- /dev/null
+++ b/libcxx/test/std/iterators/iterator.requirements/iterator.assoc.types/incrementable.traits/iter_difference_t.pass.cpp
@@ -0,0 +1,70 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 T>
+// using iter_difference_t;
+
+#include <iterator>
+
+#include <concepts>
+#include <vector>
+
+template <class T, class Expected>
+[[nodiscard]] constexpr bool check_iter_difference_t() {
+  constexpr bool result = std::same_as<std::iter_difference_t<T>, Expected>;
+  static_assert(std::same_as<std::iter_difference_t<T const>, Expected> == result);
+  static_assert(std::same_as<std::iter_difference_t<T volatile>, Expected> == result);
+  static_assert(std::same_as<std::iter_difference_t<T const volatile>, Expected> == result);
+  static_assert(std::same_as<std::iter_difference_t<T const&>, Expected> == result);
+  static_assert(std::same_as<std::iter_difference_t<T volatile&>, Expected> == result);
+  static_assert(std::same_as<std::iter_difference_t<T const volatile&>, Expected> == result);
+  static_assert(std::same_as<std::iter_difference_t<T const&&>, Expected> == result);
+  static_assert(std::same_as<std::iter_difference_t<T volatile&&>, Expected> == result);
+  static_assert(std::same_as<std::iter_difference_t<T const volatile&&>, Expected> == result);
+
+  return result;
+}
+
+static_assert(check_iter_difference_t<int, int>());
+static_assert(check_iter_difference_t<int*, std::ptrdiff_t>());
+static_assert(check_iter_difference_t<std::vector<int>::iterator, std::vector<int>::iterator::difference_type>());
+
+struct int_subtraction {
+  friend int operator-(int_subtraction, int_subtraction) noexcept;
+};
+static_assert(check_iter_difference_t<int_subtraction, int>());
+
+// clang-format off
+template <class T>
+requires requires { typename std::iter_difference_t<T>; }
+[[nodiscard]] constexpr bool check_no_iter_difference_t() {
+  return false;
+}
+// clang-format on
+
+template <class T>
+[[nodiscard]] constexpr bool check_no_iter_difference_t() {
+  return true;
+}
+
+static_assert(check_no_iter_difference_t<void>());
+static_assert(check_no_iter_difference_t<double>());
+
+struct S {};
+static_assert(check_no_iter_difference_t<S>());
+
+struct void_subtraction {
+  friend void operator-(void_subtraction, void_subtraction);
+};
+static_assert(check_no_iter_difference_t<void_subtraction>());
+
+int main(int, char**) { return 0; }
diff --git a/libcxx/test/std/iterators/iterator.requirements/iterator.assoc.types/readable.traits/iter_value_t.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/iterator.assoc.types/readable.traits/iter_value_t.pass.cpp
new file mode 100644
--- /dev/null
+++ b/libcxx/test/std/iterators/iterator.requirements/iterator.assoc.types/readable.traits/iter_value_t.pass.cpp
@@ -0,0 +1,75 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 T>
+// using iter_value_t;
+
+#include <iterator>
+
+#include <concepts>
+#include <memory>
+#include <vector>
+
+template <class T, class Expected>
+[[nodiscard]] constexpr bool check_iter_value_t() {
+  constexpr bool result = std::same_as<std::iter_value_t<T>, Expected>;
+  static_assert(std::same_as<std::iter_value_t<T const>, Expected> == result);
+  static_assert(std::same_as<std::iter_value_t<T volatile>, Expected> == result);
+  static_assert(std::same_as<std::iter_value_t<T const volatile>, Expected> == result);
+  static_assert(std::same_as<std::iter_value_t<T const&>, Expected> == result);
+  static_assert(std::same_as<std::iter_value_t<T volatile&>, Expected> == result);
+  static_assert(std::same_as<std::iter_value_t<T const volatile&>, Expected> == result);
+  static_assert(std::same_as<std::iter_value_t<T const&&>, Expected> == result);
+  static_assert(std::same_as<std::iter_value_t<T volatile&&>, Expected> == result);
+  static_assert(std::same_as<std::iter_value_t<T const volatile&&>, Expected> == result);
+
+  return result;
+}
+
+static_assert(check_iter_value_t<int*, int>());
+static_assert(check_iter_value_t<int[], int>());
+static_assert(check_iter_value_t<int[10], int>());
+static_assert(check_iter_value_t<std::vector<int>::iterator, std::vector<int>::iterator::value_type>());
+static_assert(check_iter_value_t<std::shared_ptr<int>, std::shared_ptr<int>::element_type>());
+
+struct both_members {
+  using value_type = double;
+  using element_type = double;
+};
+static_assert(check_iter_value_t<both_members, double>());
+
+// clang-format off
+template <class T>
+requires requires { typename std::iter_value_t<T>; }
+[[nodiscard]] constexpr bool check_no_iter_value_t() {
+  return false;
+}
+// clang-format on
+
+template <class T>
+[[nodiscard]] constexpr bool check_no_iter_value_t() {
+  return true;
+}
+
+static_assert(check_no_iter_value_t<void>());
+static_assert(check_no_iter_value_t<double>());
+
+struct S {};
+static_assert(check_no_iter_value_t<S>());
+
+struct different_value_element_members {
+  using value_type = int;
+  using element_type = long;
+};
+static_assert(check_no_iter_value_t<different_value_element_members>());
+
+int main(int, char**) { return 0; }