diff --git a/libcxx/docs/Status/RangesAlgorithms.csv b/libcxx/docs/Status/RangesAlgorithms.csv
--- a/libcxx/docs/Status/RangesAlgorithms.csv
+++ b/libcxx/docs/Status/RangesAlgorithms.csv
@@ -32,7 +32,7 @@
 Read-only,includes,Not assigned,n/a,Not started
 Read-only,is_heap,Not assigned,n/a,Not started
 Read-only,is_heap_until,Not assigned,n/a,Not started
-Read-only,clamp,Not assigned,n/a,Not started
+Read-only,clamp,Nikolas Klauser,` `_,✅
 Read-only,is_permutation,Not assigned,n/a,Not started
 Read-only,for_each,Nikolas Klauser,n/a,✅
 Read-only,for_each_n,Nikolas Klauser,n/a,✅
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -66,6 +66,7 @@
   __algorithm/pop_heap.h
   __algorithm/prev_permutation.h
   __algorithm/push_heap.h
+  __algorithm/ranges_clamp.h
   __algorithm/ranges_copy.h
   __algorithm/ranges_copy_backward.h
   __algorithm/ranges_copy_if.h
diff --git a/libcxx/include/__algorithm/clamp.h b/libcxx/include/__algorithm/clamp.h
--- a/libcxx/include/__algorithm/clamp.h
+++ b/libcxx/include/__algorithm/clamp.h
@@ -22,7 +22,7 @@
 #if _LIBCPP_STD_VER > 14
 template
 _LIBCPP_NODISCARD_EXT inline
-_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
+_LIBCPP_INLINE_VISIBILITY constexpr
 const _Tp&
 clamp(const _Tp& __v, const _Tp& __lo, const _Tp& __hi, _Compare __comp)
 {
@@ -33,7 +33,7 @@
 
 template
 _LIBCPP_NODISCARD_EXT inline
-_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
+_LIBCPP_INLINE_VISIBILITY constexpr
 const _Tp&
 clamp(const _Tp& __v, const _Tp& __lo, const _Tp& __hi)
 {
diff --git a/libcxx/include/__algorithm/ranges_clamp.h b/libcxx/include/__algorithm/ranges_clamp.h
new file mode 100644
--- /dev/null
+++ b/libcxx/include/__algorithm/ranges_clamp.h
@@ -0,0 +1,64 @@
+//===----------------------------------------------------------------------===//
+//
+// 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___ALGORITHM_RANGES_CLAMP_H
+#define _LIBCPP___ALGORITHM_RANGES_CLAMP_H
+
+#include <__assert>
+#include <__config>
+#include <__functional/identity.h>
+#include <__functional/invoke.h>
+#include <__functional/ranges_operations.h>
+#include <__iterator/concepts.h>
+#include <__iterator/projected.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+namespace ranges {
+namespace __clamp {
+struct __fn {
+
+  template > _Comp = ranges::less>
+  _LIBCPP_HIDE_FROM_ABI constexpr
+  const _Type& operator()(const _Type& __value,
+                          const _Type& __low,
+                          const _Type& __high,
+                          _Comp __comp = {},
+                          _Proj __proj = {}) const {
+    _LIBCPP_ASSERT(bool(std::invoke(__comp, std::invoke(__proj, __high), std::invoke(__proj, __low))),
+                   "Bad bounds passed to std::ranges::clamp");
+    auto&& __val = std::invoke(__proj, __value);
+    if (std::invoke(__comp, __val, std::invoke(__proj, __low)))
+      return __low;
+    else if (std::invoke(__comp, std::invoke(__proj, __high), __val))
+      return __high;
+    else
+      return __value;
+  }
+
+};
+} // namespace __clamp
+
+inline namespace __cpo {
+  inline constexpr auto clamp = __clamp::__fn{};
+} // namespace __cpo
+} // namespace ranges
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
+
+#endif // _LIBCPP___ALGORITHM_RANGES_CLAMP_H
diff --git a/libcxx/include/algorithm b/libcxx/include/algorithm
--- a/libcxx/include/algorithm
+++ b/libcxx/include/algorithm
@@ -265,6 +265,11 @@
            indirect_unary_predicate, Proj>> Pred>
     constexpr bool ranges::is_partitioned(R&& r, Pred pred, Proj proj = {});                // since C++20
 
+  template> Comp = ranges::less>
+    constexpr const T&
+      ranges::clamp(const T& v, const T& lo, const T& hi, Comp comp = {}, Proj proj = {});  // since C++20
+
 }
 
     constexpr bool     // constexpr in C++20
@@ -981,6 +986,7 @@
 #include <__algorithm/pop_heap.h>
 #include <__algorithm/prev_permutation.h>
 #include <__algorithm/push_heap.h>
+#include <__algorithm/ranges_clamp.h>
 #include <__algorithm/ranges_copy.h>
 #include <__algorithm/ranges_copy_backward.h>
 #include <__algorithm/ranges_copy_if.h>
diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap
--- a/libcxx/include/module.modulemap
+++ b/libcxx/include/module.modulemap
@@ -299,6 +299,7 @@
       module pop_heap                 { private header "__algorithm/pop_heap.h" }
       module prev_permutation         { private header "__algorithm/prev_permutation.h" }
       module push_heap                { private header "__algorithm/push_heap.h" }
+      module ranges_clamp             { private header "__algorithm/ranges_clamp.h" }
       module ranges_copy              { private header "__algorithm/ranges_copy.h" }
       module ranges_copy_backward     { private header "__algorithm/ranges_copy_backward.h" }
       module ranges_copy_if           { private header "__algorithm/ranges_copy_if.h" }
diff --git a/libcxx/test/libcxx/private_headers.verify.cpp b/libcxx/test/libcxx/private_headers.verify.cpp
--- a/libcxx/test/libcxx/private_headers.verify.cpp
+++ b/libcxx/test/libcxx/private_headers.verify.cpp
@@ -103,6 +103,7 @@
 #include <__algorithm/pop_heap.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/pop_heap.h'}}
 #include <__algorithm/prev_permutation.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/prev_permutation.h'}}
 #include <__algorithm/push_heap.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/push_heap.h'}}
+#include <__algorithm/ranges_clamp.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_clamp.h'}}
 #include <__algorithm/ranges_copy.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_copy.h'}}
 #include <__algorithm/ranges_copy_backward.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_copy_backward.h'}}
 #include <__algorithm/ranges_copy_if.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_copy_if.h'}}
diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.clamp/ranges.clamp.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.clamp/ranges.clamp.pass.cpp
new file mode 100644
--- /dev/null
+++ b/libcxx/test/std/algorithms/alg.sorting/alg.clamp/ranges.clamp.pass.cpp
@@ -0,0 +1,63 @@
+//===----------------------------------------------------------------------===//
+//
+// 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-has-no-incomplete-ranges
+
+// template> Comp = ranges::less>
+//   constexpr const T&
+//     ranges::clamp(const T& v, const T& lo, const T& hi, Comp comp = {}, Proj proj = {});
+
+#include 
+#include 
+#include 
+
+constexpr bool test() {
+  { // low < val < high
+    auto val = 20;
+    auto low = 10;
+    auto high = 30;
+    std::same_as decltype(auto) ret = std::ranges::clamp(val, low, high);
+    assert(ret == 20);
+  }
+  // val < low < high
+  assert(std::ranges::clamp(10, 20, 30) == 20);
+
+  // low < high < val
+  assert(std::ranges::clamp(30, 10, 20) == 20);
+
+  // check that the comparator is used
+  assert(std::ranges::clamp(10, 30, 20, std::ranges::greater{}) == 20);
+
+  { // low = val = high
+    int val = 10;
+    assert(&std::ranges::clamp(val, 10, 10) == &val);
+  }
+
+  { // check that the projection is used
+    struct S {
+      int i;
+    };
+
+    auto val = S{10};
+    auto low = S{20};
+    auto high = S{30};
+    assert(&std::ranges::clamp(val, low, high, {}, &S::i) == &low);
+  }
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}