diff --git a/CMake/AbseilDll.cmake b/CMake/AbseilDll.cmake
index 0fa06af..f45b9a4 100644
--- a/CMake/AbseilDll.cmake
+++ b/CMake/AbseilDll.cmake
@@ -20,6 +20,8 @@
   "base/internal/dynamic_annotations.h"
   "base/internal/endian.h"
   "base/internal/errno_saver.h"
+  "base/internal/hardening.h"
+  "base/internal/hardening.cc"
   "base/internal/hide_ptr.h"
   "base/internal/iterator_traits.h"
   "base/internal/low_level_alloc.cc"
@@ -453,6 +455,7 @@
   "types/any.h"
   "types/compare.h"
   "types/optional.h"
+  "types/optional_ref.h"
   "types/span.h"
   "types/internal/span.h"
   "types/variant.h"
diff --git a/absl/base/BUILD.bazel b/absl/base/BUILD.bazel
index f95e187..6b39370 100644
--- a/absl/base/BUILD.bazel
+++ b/absl/base/BUILD.bazel
@@ -61,6 +61,25 @@
 )
 
 cc_library(
+    name = "hardening",
+    srcs = [
+        "internal/hardening.cc",
+    ],
+    hdrs = [
+        "internal/hardening.h",
+    ],
+    copts = ABSL_DEFAULT_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    visibility = [
+        "//absl:__subpackages__",
+    ],
+    deps = [
+        ":config",
+        ":core_headers",
+    ],
+)
+
+cc_library(
     name = "log_severity",
     srcs = ["log_severity.cc"],
     hdrs = ["log_severity.h"],
@@ -619,6 +638,22 @@
 )
 
 cc_test(
+    name = "hardening_test",
+    size = "small",
+    srcs = [
+        "internal/hardening_test.cc",
+    ],
+    copts = ABSL_TEST_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    deps = [
+        ":config",
+        ":hardening",
+        "@googletest//:gtest",
+        "@googletest//:gtest_main",
+    ],
+)
+
+cc_test(
     name = "no_destructor_test",
     srcs = ["no_destructor_test.cc"],
     copts = ABSL_TEST_COPTS,
@@ -953,7 +988,6 @@
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
         ":core_headers",
-        "//absl/types:optional",
         "@googletest//:gtest",
         "@googletest//:gtest_main",
     ],
diff --git a/absl/base/CMakeLists.txt b/absl/base/CMakeLists.txt
index 91a8a58..ad1932e 100644
--- a/absl/base/CMakeLists.txt
+++ b/absl/base/CMakeLists.txt
@@ -43,6 +43,20 @@
 
 absl_cc_library(
   NAME
+    hardening
+  HDRS
+    "internal/hardening.h"
+  SRCS
+    "internal/hardening.cc"
+  DEPS
+    absl::config
+    absl::core_headers
+  COPTS
+    ${ABSL_DEFAULT_COPTS}
+)
+
+absl_cc_library(
+  NAME
     log_severity
   HDRS
     "log_severity.h"
@@ -406,6 +420,19 @@
 
 absl_cc_test(
   NAME
+    hardening_test
+  SRCS
+    "internal/hardening_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  DEPS
+    absl::config
+    absl::hardening
+    GTest::gtest_main
+)
+
+absl_cc_test(
+  NAME
     bit_cast_test
   SRCS
     "bit_cast_test.cc"
@@ -765,7 +792,6 @@
     ${ABSL_TEST_COPTS}
   DEPS
     absl::core_headers
-    absl::optional
     GTest::gtest_main
 )
 
diff --git a/absl/base/attributes.h b/absl/base/attributes.h
index cced170..91e552f 100644
--- a/absl/base/attributes.h
+++ b/absl/base/attributes.h
@@ -933,7 +933,7 @@
 // We disable this on Clang versions < 13 because of the following
 // false-positive:
 //
-//   absl::string_view f(absl::optional<absl::string_view> sv) { return *sv; }
+//   absl::string_view f(std::optional<absl::string_view> sv) { return *sv; }
 //
 // See the following links for details:
 // https://reviews.llvm.org/D64448
@@ -964,7 +964,7 @@
 // We disable this on Clang versions < 13 because of the following
 // false-positive:
 //
-//   absl::string_view f(absl::optional<absl::string_view> sv) { return *sv; }
+//   absl::string_view f(std::optional<absl::string_view> sv) { return *sv; }
 //
 // See the following links for details:
 // https://reviews.llvm.org/D64448
diff --git a/absl/base/internal/hardening.cc b/absl/base/internal/hardening.cc
new file mode 100644
index 0000000..bd7da60
--- /dev/null
+++ b/absl/base/internal/hardening.cc
@@ -0,0 +1,46 @@
+//
+// Copyright 2026 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifdef _WIN32
+#include <intrin.h>
+// kFastFailRangeCheckFailure mirrors the FAST_FAIL_RANGE_CHECK_FAILURE macro.
+// Typically FAST_FAIL_RANGE_CHECK_FAILURE would be imported from winnt.h
+// but winnt.h pulls in other dependencies and introduces build failures.
+constexpr unsigned int kFastFailRangeCheckFailure = 8u;
+#endif
+
+#include "absl/base/internal/hardening.h"
+
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+#include "absl/base/macros.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+namespace base_internal {
+
+[[noreturn]] ABSL_ATTRIBUTE_NOINLINE void FailedBoundsCheckAbort() {
+#ifdef _WIN32
+  __fastfail(kFastFailRangeCheckFailure);
+#else
+  ABSL_INTERNAL_HARDENING_ABORT();
+#endif
+}
+
+}  // namespace base_internal
+
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/absl/base/internal/hardening.h b/absl/base/internal/hardening.h
new file mode 100644
index 0000000..02207cc
--- /dev/null
+++ b/absl/base/internal/hardening.h
@@ -0,0 +1,63 @@
+//
+// Copyright 2026 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: hardening.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines macros and functions for checking bounds on
+// accesses to Abseil container types.
+
+#ifndef ABSL_BASE_INTERNAL_HARDENING_H_
+#define ABSL_BASE_INTERNAL_HARDENING_H_
+
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+#include "absl/base/macros.h"
+#include "absl/base/options.h"
+
+#ifdef ABSL_INTERNAL_ATTRIBUTE_NO_MERGE
+#error ABSL_INTERNAL_ATTRIBUTE_NO_MERGE cannot be directly set
+#elif ABSL_HAVE_CPP_ATTRIBUTE(clang::nomerge)
+#define ABSL_INTERNAL_ATTRIBUTE_NO_MERGE [[clang::nomerge]]
+#else
+#define ABSL_INTERNAL_ATTRIBUTE_NO_MERGE
+#endif
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+namespace base_internal {
+
+[[noreturn]] ABSL_ATTRIBUTE_NOINLINE void FailedBoundsCheckAbort();
+
+inline void HardeningAssertInBounds(size_t index, size_t size) {
+#if (ABSL_OPTION_HARDENED == 1 || ABSL_OPTION_HARDENED == 2) && defined(NDEBUG)
+  if (ABSL_PREDICT_FALSE(index >= size)) {
+    ABSL_INTERNAL_ATTRIBUTE_NO_MERGE FailedBoundsCheckAbort();
+  }
+#else
+  ABSL_ASSERT(index < size);
+#endif
+}
+
+}  // namespace base_internal
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#undef ABSL_INTERNAL_ATTRIBUTE_NO_MERGE
+
+#endif  // ABSL_BASE_INTERNAL_HARDENING_H_
diff --git a/absl/base/internal/hardening_test.cc b/absl/base/internal/hardening_test.cc
new file mode 100644
index 0000000..8666f29
--- /dev/null
+++ b/absl/base/internal/hardening_test.cc
@@ -0,0 +1,35 @@
+// Copyright 2026 The Abseil Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/base/internal/hardening.h"
+
+#include "gtest/gtest.h"
+#include "absl/base/options.h"
+
+namespace {
+
+TEST(BoundsCheckTest, HardeningAssertInBounds) {
+  absl::base_internal::HardeningAssertInBounds(0, 10);
+}
+
+TEST(BoundsChecksDeathTest, HardeningAssertInBounds) {
+#if GTEST_HAS_DEATH_TEST && (!defined(NDEBUG) || (ABSL_OPTION_HARDENED == 1 || \
+                                                  ABSL_OPTION_HARDENED == 2))
+  // The underlying mechanism of termination varies, and may include SIGILL
+  // or SIGABRT.
+  EXPECT_DEATH(absl::base_internal::HardeningAssertInBounds(10, 10), "");
+#endif
+}
+
+}  // namespace
diff --git a/absl/base/optimization_test.cc b/absl/base/optimization_test.cc
index b47b11a..11d22fe 100644
--- a/absl/base/optimization_test.cc
+++ b/absl/base/optimization_test.cc
@@ -14,8 +14,9 @@
 
 #include "absl/base/optimization.h"
 
+#include <optional>
+
 #include "gtest/gtest.h"
-#include "absl/types/optional.h"
 
 namespace {
 
@@ -80,8 +81,8 @@
 
 TEST(PredictTest, Optional) {
   // Note: An optional's truth value is the value's existence, not its truth.
-  absl::optional<bool> has_value(false);
-  absl::optional<bool> no_value;
+  std::optional<bool> has_value(false);
+  std::optional<bool> no_value;
   EXPECT_TRUE(ABSL_PREDICT_TRUE(has_value));
   EXPECT_FALSE(ABSL_PREDICT_TRUE(no_value));
   EXPECT_TRUE(ABSL_PREDICT_FALSE(has_value));
diff --git a/absl/cleanup/internal/cleanup.h b/absl/cleanup/internal/cleanup.h
index 4dd6f91..2022fa7 100644
--- a/absl/cleanup/internal/cleanup.h
+++ b/absl/cleanup/internal/cleanup.h
@@ -49,7 +49,7 @@
   explicit Storage(Callback callback) {
     // Placement-new into a character buffer is used for eager destruction when
     // the cleanup is invoked or cancelled. To ensure this optimizes well, the
-    // behavior is implemented locally instead of using an absl::optional.
+    // behavior is implemented locally instead of using a std::optional.
     ::new (GetCallbackBuffer()) Callback(std::move(callback));
     is_callback_engaged_ = true;
   }
diff --git a/absl/container/BUILD.bazel b/absl/container/BUILD.bazel
index e90aaec..efcdc51 100644
--- a/absl/container/BUILD.bazel
+++ b/absl/container/BUILD.bazel
@@ -54,8 +54,6 @@
         ":compressed_tuple",
         ":test_instance_tracker",
         "//absl/memory",
-        "//absl/types:any",
-        "//absl/types:optional",
         "//absl/utility",
         "@googletest//:gtest",
         "@googletest//:gtest_main",
@@ -283,7 +281,6 @@
         "//absl/base:config",
         "//absl/log:check",
         "//absl/meta:type_traits",
-        "//absl/types:any",
         "@googletest//:gtest",
         "@googletest//:gtest_main",
     ],
@@ -810,7 +807,6 @@
         "//absl/numeric:int128",
         "//absl/random",
         "//absl/strings",
-        "//absl/types:optional",
         "@googletest//:gtest",
         "@googletest//:gtest_main",
     ],
@@ -855,7 +851,6 @@
         "//absl/random:distributions",
         "//absl/strings",
         "//absl/strings:str_format",
-        "//absl/types:optional",
     ],
 )
 
@@ -1193,7 +1188,6 @@
         "//absl/random",
         "//absl/strings",
         "//absl/types:compare",
-        "//absl/types:optional",
         "@googletest//:gtest",
         "@googletest//:gtest_main",
     ],
diff --git a/absl/container/CMakeLists.txt b/absl/container/CMakeLists.txt
index 365c6ea..589a3a4 100644
--- a/absl/container/CMakeLists.txt
+++ b/absl/container/CMakeLists.txt
@@ -80,7 +80,6 @@
     absl::core_headers
     absl::flags
     absl::hash_testing
-    absl::optional
     absl::random_random
     absl::raw_logging_internal
     absl::strings
@@ -110,10 +109,8 @@
   COPTS
     ${ABSL_TEST_COPTS}
   DEPS
-    absl::any
     absl::compressed_tuple
     absl::memory
-    absl::optional
     absl::test_instance_tracker
     absl::utility
     GTest::gmock_main
@@ -309,7 +306,6 @@
   COPTS
     ${ABSL_TEST_COPTS}
   DEPS
-    absl::any
     absl::check
     absl::config
     absl::flat_hash_map
@@ -840,7 +836,6 @@
     absl::log
     absl::memory
     absl::node_hash_set
-    absl::optional
     absl::prefetch
     absl::random_random
     absl::raw_hash_set
@@ -1119,6 +1114,7 @@
     absl::config
     absl::test_instance_tracker
     GTest::gmock
+  TESTONLY
 )
 
 absl_cc_library(
diff --git a/absl/container/btree_test.cc b/absl/container/btree_test.cc
index 0cf3ed3..dc880a8 100644
--- a/absl/container/btree_test.cc
+++ b/absl/container/btree_test.cc
@@ -24,6 +24,7 @@
 #include <map>
 #include <memory>
 #include <numeric>
+#include <optional>
 #include <stdexcept>
 #include <string>
 #include <type_traits>
@@ -47,7 +48,6 @@
 #include "absl/strings/str_split.h"
 #include "absl/strings/string_view.h"
 #include "absl/types/compare.h"
-#include "absl/types/optional.h"
 
 ABSL_FLAG(int, test_values, 10000, "The number of values to use for tests");
 
@@ -3007,11 +3007,11 @@
   // compare differently with each other from how they compare with instances
   // that don't have the optional field.
   struct ClockTime {
-    absl::optional<int> hour;
+    std::optional<int> hour;
     int minute;
   };
   // `comp(a,b) && comp(b,c) && !comp(a,c)` violates transitivity.
-  ClockTime a = {absl::nullopt, 1};
+  ClockTime a = {std::nullopt, 1};
   ClockTime b = {2, 5};
   ClockTime c = {6, 0};
   {
diff --git a/absl/container/flat_hash_map_test.cc b/absl/container/flat_hash_map_test.cc
index a4efb7d..0839b00 100644
--- a/absl/container/flat_hash_map_test.cc
+++ b/absl/container/flat_hash_map_test.cc
@@ -33,7 +33,6 @@
 #include "absl/container/internal/unordered_map_modifiers_test.h"
 #include "absl/log/check.h"
 #include "absl/meta/type_traits.h"
-#include "absl/types/any.h"
 
 #if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
 #include <ranges>  // NOLINT(build/c++20)
diff --git a/absl/container/internal/common.h b/absl/container/internal/common.h
index 3e263a3..62517af 100644
--- a/absl/container/internal/common.h
+++ b/absl/container/internal/common.h
@@ -18,6 +18,7 @@
 #include <algorithm>
 #include <cassert>
 #include <cstddef>
+#include <optional>
 #include <tuple>
 #include <type_traits>
 
@@ -146,7 +147,7 @@
 
   void reset() {
     assert(alloc_.has_value());
-    alloc_ = absl::nullopt;
+    alloc_ = std::nullopt;
   }
 
   slot_type* slot() const {
@@ -156,7 +157,7 @@
   allocator_type* alloc() { return std::addressof(*alloc_); }
 
  private:
-  absl::optional<allocator_type> alloc_ = {};
+  std::optional<allocator_type> alloc_ = {};
   alignas(slot_type) mutable unsigned char slot_space_[sizeof(slot_type)] = {};
 };
 
diff --git a/absl/container/internal/compressed_tuple_test.cc b/absl/container/internal/compressed_tuple_test.cc
index 662f944..47648c9 100644
--- a/absl/container/internal/compressed_tuple_test.cc
+++ b/absl/container/internal/compressed_tuple_test.cc
@@ -14,7 +14,9 @@
 
 #include "absl/container/internal/compressed_tuple.h"
 
+#include <any>
 #include <memory>
+#include <optional>
 #include <set>
 #include <string>
 #include <type_traits>
@@ -25,8 +27,6 @@
 #include "gtest/gtest.h"
 #include "absl/container/internal/test_instance_tracker.h"
 #include "absl/memory/memory.h"
-#include "absl/types/any.h"
-#include "absl/types/optional.h"
 #include "absl/utility/utility.h"
 
 // These are declared at global scope purely so that error messages
@@ -363,13 +363,13 @@
 }
 
 TEST(CompressedTupleTest, AnyElements) {
-  any a(std::string("str"));
-  CompressedTuple<any, any&> x(any(5), a);
-  EXPECT_EQ(absl::any_cast<int>(x.get<0>()), 5);
-  EXPECT_EQ(absl::any_cast<std::string>(x.get<1>()), "str");
+  std::any a(std::string("str"));
+  CompressedTuple<std::any, std::any&> x(std::any(5), a);
+  EXPECT_EQ(std::any_cast<int>(x.get<0>()), 5);
+  EXPECT_EQ(std::any_cast<std::string>(x.get<1>()), "str");
 
   a = 0.5f;
-  EXPECT_EQ(absl::any_cast<float>(x.get<1>()), 0.5);
+  EXPECT_EQ(std::any_cast<float>(x.get<1>()), 0.5);
 }
 
 TEST(CompressedTupleTest, Constexpr) {
@@ -418,15 +418,15 @@
   EXPECT_EQ(trivial1, 0);
   EXPECT_EQ(trivial2, 0);
 
-  constexpr CompressedTuple<Empty<0>, NonTrivialStruct, absl::optional<int>>
+  constexpr CompressedTuple<Empty<0>, NonTrivialStruct, std::optional<int>>
       non_trivial = {};
   constexpr CallType non_trivial0 = non_trivial.get<0>().value();
   constexpr int non_trivial1 = non_trivial.get<1>().value();
-  constexpr absl::optional<int> non_trivial2 = non_trivial.get<2>();
+  constexpr std::optional<int> non_trivial2 = non_trivial.get<2>();
 
   EXPECT_EQ(non_trivial0, CallType::kConstRef);
   EXPECT_EQ(non_trivial1, 5);
-  EXPECT_EQ(non_trivial2, absl::nullopt);
+  EXPECT_EQ(non_trivial2, std::nullopt);
 
   static constexpr char data[] = "DEF";
   constexpr CompressedTuple<const char*> z(data);
diff --git a/absl/container/internal/raw_hash_set.cc b/absl/container/internal/raw_hash_set.cc
index 9955029..15d072a 100644
--- a/absl/container/internal/raw_hash_set.cc
+++ b/absl/container/internal/raw_hash_set.cc
@@ -62,14 +62,15 @@
   assert((CONDITION) && "Try enabling sanitizers.")
 #endif
 
-[[noreturn]] ABSL_ATTRIBUTE_NOINLINE void HashTableSizeOverflow() {
-  ABSL_RAW_LOG(FATAL, "Hash table size overflow");
+void ValidateMaxSize([[maybe_unused]] size_t size,
+                     [[maybe_unused]] size_t key_size,
+                     [[maybe_unused]] size_t slot_size) {
+  ABSL_SWISSTABLE_ASSERT(size <= MaxValidSize(key_size, slot_size));
 }
-
-void ValidateMaxSize(size_t size, size_t slot_size) {
-  if (IsAboveValidSize(size, slot_size)) {
-    HashTableSizeOverflow();
-  }
+void ValidateMaxCapacity(size_t capacity, size_t key_size, size_t slot_size) {
+  if (capacity <= 1) return;
+  ValidateMaxSize(CapacityToGrowth(PreviousCapacity(capacity)), key_size,
+                  slot_size);
 }
 
 // Returns "random" seed.
@@ -1681,7 +1682,7 @@
 void ReserveEmptyNonAllocatedTableToFitNewSize(
     CommonFields& common, const PolicyFunctions& __restrict policy,
     size_t new_size) {
-  ValidateMaxSize(new_size, policy.slot_size);
+  ValidateMaxSize(new_size, policy.key_size, policy.slot_size);
   ABSL_ASSUME(new_size > 0);
   ResizeEmptyNonAllocatedTableImpl(common, policy, SizeToCapacity(new_size),
                                    /*force_infoz=*/false);
@@ -1700,7 +1701,7 @@
     CommonFields& common, const PolicyFunctions& __restrict policy,
     size_t new_size) {
   const size_t cap = common.capacity();
-  ValidateMaxSize(new_size, policy.slot_size);
+  ValidateMaxSize(new_size, policy.key_size, policy.slot_size);
   ABSL_ASSUME(new_size > 0);
   const size_t new_capacity = SizeToCapacity(new_size);
   if (cap == policy.soo_capacity()) {
@@ -1747,7 +1748,7 @@
     CommonFields& common, const PolicyFunctions& __restrict policy,
     size_t bucket_count) {
   size_t new_capacity = NormalizeCapacity(bucket_count);
-  ValidateMaxSize(CapacityToGrowth(new_capacity), policy.slot_size);
+  ValidateMaxCapacity(new_capacity, policy.key_size, policy.slot_size);
   ResizeEmptyNonAllocatedTableImpl(common, policy, new_capacity,
                                    /*force_infoz=*/false);
 }
@@ -1864,11 +1865,11 @@
     }
   }
 
-  ValidateMaxSize(n, policy.slot_size);
   // bitor is a faster way of doing `max` here. We will round up to the next
   // power-of-2-minus-1, so bitor is good enough.
   const size_t new_capacity =
       NormalizeCapacity(n | SizeToCapacity(common.size()));
+  ValidateMaxCapacity(new_capacity, policy.key_size, policy.slot_size);
   // n == 0 unconditionally rehashes as per the standard.
   if (n == 0 || new_capacity > cap) {
     if (cap == policy.soo_capacity()) {
diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h
index e6ea164..1adb396 100644
--- a/absl/container/internal/raw_hash_set.h
+++ b/absl/container/internal/raw_hash_set.h
@@ -1557,51 +1557,52 @@
   }
 };
 
-// Returns the maximum valid size for a table with 1-byte slots.
-// This function is an utility shared by MaxValidSize and IsAboveValidSize.
-// Template parameter is only used to enable testing.
+// The following functions are used for calculating the max valid size of the
+// table. This is important for security to avoid overflowing size_t when
+// calculating the allocation size of the backing array
+// (https://nvd.nist.gov/vuln/detail/CVE-2025-0838). We also limit the max valid
+// size based on the size of the key_type, and this is an optimization because
+// we ABSL_ASSUME that the size is less than MaxValidSize, which can enable
+// other optimizations for tables with small keys.
+
 template <size_t kSizeOfSizeT = sizeof(size_t)>
-constexpr size_t MaxValidSizeFor1ByteSlot() {
-  if constexpr (kSizeOfSizeT == 8) {
-    return CapacityToGrowth(
-        static_cast<size_t>(uint64_t{1} << HashtableSize::kSizeBitCount) - 1);
-  } else {
-    static_assert(kSizeOfSizeT == 4);
-    return CapacityToGrowth((size_t{1} << (kSizeOfSizeT * 8 - 2)) - 1);
-  }
+constexpr size_t MaxSizeAtMaxValidCapacity(size_t slot_size) {
+  using SizeT = std::conditional_t<kSizeOfSizeT == 4, uint32_t, uint64_t>;
+  // We shift right by 2 for a safe margin against overflow.
+  constexpr SizeT kMaxValidCapacity = ~SizeT{} >> 2;
+  return CapacityToGrowth(kMaxValidCapacity) / slot_size;
 }
 
-// Returns the maximum valid size for a table with provided slot size.
-// Template parameter is only used to enable testing.
+constexpr size_t MaxStorableSize() {
+  return static_cast<size_t>(uint64_t{1} << HashtableSize::kSizeBitCount) - 1;
+}
+
+// There are no more than 2^sizeof(key_type) unique key_types (and hashtable
+// keys must be unique) so we can't have a hashtable with more than
+// 2^sizeof(key_type) elements.
 template <size_t kSizeOfSizeT = sizeof(size_t)>
-constexpr size_t MaxValidSize(size_t slot_size) {
+constexpr size_t MaxValidSizeForKeySize(size_t key_size) {
+  if (key_size < kSizeOfSizeT) return uint64_t{1} << 8 * key_size;
+  return (std::numeric_limits<size_t>::max)();
+}
+
+template <size_t kSizeOfSizeT = sizeof(size_t)>
+constexpr size_t MaxValidSizeForSlotSize(size_t slot_size) {
   if constexpr (kSizeOfSizeT == 8) {
     // For small slot sizes we are limited by HashtableSize::kSizeBitCount.
     if (slot_size < size_t{1} << (64 - HashtableSize::kSizeBitCount)) {
-      return MaxValidSizeFor1ByteSlot<kSizeOfSizeT>();
+      return MaxStorableSize();
     }
-    return (size_t{1} << (kSizeOfSizeT * 8 - 2)) / slot_size;
-  } else {
-    return MaxValidSizeFor1ByteSlot<kSizeOfSizeT>() / slot_size;
   }
+  return MaxSizeAtMaxValidCapacity<kSizeOfSizeT>(slot_size);
 }
 
-// Returns true if size is larger than the maximum valid size.
-// It is an optimization to avoid the division operation in the common case.
+// Returns the maximum valid size for a table, given the key size and slot size.
 // Template parameter is only used to enable testing.
 template <size_t kSizeOfSizeT = sizeof(size_t)>
-constexpr bool IsAboveValidSize(size_t size, size_t slot_size) {
-  if constexpr (kSizeOfSizeT == 8) {
-    // For small slot sizes we are limited by HashtableSize::kSizeBitCount.
-    if (ABSL_PREDICT_TRUE(slot_size <
-                          (size_t{1} << (64 - HashtableSize::kSizeBitCount)))) {
-      return size > MaxValidSizeFor1ByteSlot<kSizeOfSizeT>();
-    }
-    return size > MaxValidSize<kSizeOfSizeT>(slot_size);
-  } else {
-    return uint64_t{size} * slot_size >
-           MaxValidSizeFor1ByteSlot<kSizeOfSizeT>();
-  }
+constexpr size_t MaxValidSize(size_t key_size, size_t slot_size) {
+  return (std::min)(MaxValidSizeForKeySize<kSizeOfSizeT>(key_size),
+                    MaxValidSizeForSlotSize<kSizeOfSizeT>(slot_size));
 }
 
 // Returns the index of the SOO slot when growing from SOO to non-SOO in a
@@ -1616,8 +1617,9 @@
 // Allowing till 16 would require additional store that can be avoided.
 constexpr size_t MaxSmallAfterSooCapacity() { return 7; }
 
-// Type erased version of raw_hash_set::reserve.
-// Requires: `new_size > policy.soo_capacity`.
+// Type erased version of raw_hash_set::reserve. Requires:
+//   1. `new_size > policy.soo_capacity`.
+//   2. `new_size <= kMaxValidSize`.
 void ReserveTableToFitNewSize(CommonFields& common,
                               const PolicyFunctions& policy, size_t new_size);
 
@@ -1626,11 +1628,13 @@
 //   1. `c.capacity() == policy.soo_capacity`.
 //   2. `c.empty()`.
 //   3. `new_size > policy.soo_capacity`.
+//   4. `bucket_count <= MaxValidCapacity()`.
 // The table will be attempted to be sampled.
 void ReserveEmptyNonAllocatedTableToFitBucketCount(
     CommonFields& common, const PolicyFunctions& policy, size_t bucket_count);
 
 // Type erased version of raw_hash_set::rehash.
+// Requires: `n <= MaxValidCapacity()`.
 void Rehash(CommonFields& common, const PolicyFunctions& policy, size_t n);
 
 // Type erased version of copy constructor.
@@ -1856,13 +1860,20 @@
   constexpr static size_t DefaultCapacity() {
     return SooEnabled() ? SooCapacity() : 0;
   }
+  constexpr static size_t MaxValidSize() {
+    return container_internal::MaxValidSize(sizeof(key_type),
+                                            sizeof(slot_type));
+  }
+  constexpr static size_t MaxValidCapacity() {
+    return SizeToCapacity(MaxValidSize());
+  }
 
   // Whether `size` fits in the SOO capacity of this table.
   bool fits_in_soo(size_t size) const {
     return SooEnabled() && size <= SooCapacity();
   }
   // Whether this table is in SOO mode or non-SOO mode.
-  bool is_soo() const { return fits_in_soo(capacity()); }
+  bool is_soo() const { return fits_in_soo(maybe_invalid_capacity()); }
   bool is_full_soo() const { return is_soo() && !empty(); }
 
   bool is_small() const { return common().is_small(); }
@@ -2110,7 +2121,8 @@
                   alloc) {
     if (bucket_count > DefaultCapacity()) {
       ReserveEmptyNonAllocatedTableToFitBucketCount(
-          common(), GetPolicyFunctions(), bucket_count);
+          common(), GetPolicyFunctions(),
+          (std::min)(bucket_count, MaxValidCapacity()));
     }
   }
 
@@ -2342,21 +2354,27 @@
   bool empty() const { return !size(); }
   size_t size() const {
     AssertNotDebugCapacity();
-    return common().size();
+    const size_t size = common().size();
+    [[maybe_unused]] const size_t kMaxValidSize = MaxValidSize();
+    ABSL_ASSUME(size <= kMaxValidSize);
+    return size;
   }
   size_t capacity() const {
     const size_t cap = common().capacity();
-    // Compiler complains when using functions in ASSUME so use local variable.
-    [[maybe_unused]] static constexpr size_t kDefaultCapacity =
-        DefaultCapacity();
+    // Compiler complains when using functions in ASSUME so use local variables.
+    [[maybe_unused]] const bool kIsValid = IsValidCapacity(cap);
+    [[maybe_unused]] const size_t kDefaultCapacity = DefaultCapacity();
+    [[maybe_unused]] const size_t kMaxValidCapacity = MaxValidCapacity();
+    ABSL_ASSUME(kIsValid || cap == 0);
     ABSL_ASSUME(cap >= kDefaultCapacity);
+    ABSL_ASSUME(cap <= kMaxValidCapacity);
     return cap;
   }
-  size_t max_size() const { return MaxValidSize(sizeof(slot_type)); }
+  size_t max_size() const { return MaxValidSize(); }
 
   ABSL_ATTRIBUTE_REINITIALIZES void clear() {
     if (SwisstableGenerationsEnabled() &&
-        capacity() >= InvalidCapacity::kMovedFrom) {
+        maybe_invalid_capacity() >= InvalidCapacity::kMovedFrom) {
       common().set_capacity(DefaultCapacity());
     }
     AssertNotDebugCapacity();
@@ -2752,11 +2770,14 @@
               typename AllocTraits::propagate_on_container_swap{});
   }
 
-  void rehash(size_t n) { Rehash(common(), GetPolicyFunctions(), n); }
+  void rehash(size_t n) {
+    Rehash(common(), GetPolicyFunctions(), (std::min)(n, MaxValidCapacity()));
+  }
 
   void reserve(size_t n) {
     if (ABSL_PREDICT_TRUE(n > DefaultCapacity())) {
-      ReserveTableToFitNewSize(common(), GetPolicyFunctions(), n);
+      ReserveTableToFitNewSize(common(), GetPolicyFunctions(),
+                               (std::min)(n, MaxValidSize()));
     }
   }
 
@@ -3034,7 +3055,7 @@
 
   void destructor_impl() {
     if (SwisstableGenerationsEnabled() &&
-        capacity() >= InvalidCapacity::kMovedFrom) {
+        maybe_invalid_capacity() >= InvalidCapacity::kMovedFrom) {
       return;
     }
     if (capacity() == 0) return;
@@ -3132,8 +3153,9 @@
       that.common().set_capacity(this == &that ? InvalidCapacity::kSelfMovedFrom
                                                : InvalidCapacity::kMovedFrom);
     }
-    if (!SwisstableGenerationsEnabled() || capacity() == DefaultCapacity() ||
-        capacity() > kAboveMaxValidCapacity) {
+    if (!SwisstableGenerationsEnabled() ||
+        maybe_invalid_capacity() == DefaultCapacity() ||
+        maybe_invalid_capacity() > kAboveMaxValidCapacity) {
       return;
     }
     common().increment_generation();
@@ -3302,21 +3324,21 @@
       return;
     }
 #endif
-    if (ABSL_PREDICT_TRUE(capacity() <
-                          InvalidCapacity::kAboveMaxValidCapacity)) {
+    const size_t cap = maybe_invalid_capacity();
+    if (ABSL_PREDICT_TRUE(cap < InvalidCapacity::kAboveMaxValidCapacity)) {
       return;
     }
-    assert(capacity() != InvalidCapacity::kReentrance &&
+    assert(cap != InvalidCapacity::kReentrance &&
            "Reentrant container access during element construction/destruction "
            "is not allowed.");
     if constexpr (SwisstableAssertAccessToDestroyedTable()) {
-      if (capacity() == InvalidCapacity::kDestroyed) {
+      if (cap == InvalidCapacity::kDestroyed) {
         ABSL_RAW_LOG(FATAL, "Use of destroyed hash table.");
       }
     }
     if (SwisstableGenerationsEnabled() &&
-        ABSL_PREDICT_FALSE(capacity() >= InvalidCapacity::kMovedFrom)) {
-      if (capacity() == InvalidCapacity::kSelfMovedFrom) {
+        ABSL_PREDICT_FALSE(cap >= InvalidCapacity::kMovedFrom)) {
+      if (cap == InvalidCapacity::kSelfMovedFrom) {
         // If this log triggers, then a hash table was move-assigned to itself
         // and then used again later without being reinitialized.
         ABSL_RAW_LOG(FATAL, "Use of self-move-assigned hash table.");
@@ -3444,6 +3466,9 @@
   CommonFields& common() { return settings_.template get<0>(); }
   const CommonFields& common() const { return settings_.template get<0>(); }
 
+  // For use when the capacity is potentially invalid so we shouldn't assume
+  // that the capacity is valid (which is done in `capacity()`).
+  size_t maybe_invalid_capacity() const { return common().capacity(); }
   ctrl_t* control() const {
     ABSL_SWISSTABLE_ASSERT(!is_soo());
     return common().control();
diff --git a/absl/container/internal/raw_hash_set_probe_benchmark.cc b/absl/container/internal/raw_hash_set_probe_benchmark.cc
index 7165558..dcd1596 100644
--- a/absl/container/internal/raw_hash_set_probe_benchmark.cc
+++ b/absl/container/internal/raw_hash_set_probe_benchmark.cc
@@ -20,6 +20,7 @@
 #include <cstdint>
 #include <limits>
 #include <memory>
+#include <optional>
 #include <regex>  // NOLINT
 #include <string>
 #include <utility>
@@ -36,7 +37,6 @@
 #include "absl/strings/str_format.h"
 #include "absl/strings/string_view.h"
 #include "absl/strings/strip.h"
-#include "absl/types/optional.h"
 
 namespace {
 
@@ -450,10 +450,10 @@
 constexpr int kDistWidth = 16;
 
 bool CanRunBenchmark(absl::string_view name) {
-  static const absl::NoDestructor<absl::optional<std::regex>> filter([] {
+  static const absl::NoDestructor<std::optional<std::regex>> filter([] {
     return benchmarks.empty() || benchmarks == "all"
-               ? absl::nullopt
-               : absl::make_optional(std::regex(std::string(benchmarks)));
+               ? std::nullopt
+               : std::make_optional(std::regex(std::string(benchmarks)));
   }());
   return !filter->has_value() || std::regex_search(std::string(name), **filter);
 }
diff --git a/absl/container/internal/raw_hash_set_test.cc b/absl/container/internal/raw_hash_set_test.cc
index 5b3cd0e..610ba82 100644
--- a/absl/container/internal/raw_hash_set_test.cc
+++ b/absl/container/internal/raw_hash_set_test.cc
@@ -31,6 +31,7 @@
 #include <map>
 #include <memory>
 #include <numeric>
+#include <optional>
 #include <ostream>
 #include <random>
 #include <set>
@@ -53,7 +54,6 @@
 #include "absl/container/internal/container_memory.h"
 #include "absl/container/internal/hash_function_defaults.h"
 #include "absl/container/internal/hash_policy_testing.h"
-#include "absl/random/random.h"
 #include "absl/container/internal/hashtable_control_bytes.h"
 #include "absl/container/internal/hashtable_debug.h"
 #include "absl/container/internal/hashtablez_sampler.h"
@@ -68,9 +68,9 @@
 #include "absl/memory/memory.h"
 #include "absl/meta/type_traits.h"
 #include "absl/numeric/int128.h"
+#include "absl/random/random.h"
 #include "absl/strings/str_cat.h"
 #include "absl/strings/string_view.h"
-#include "absl/types/optional.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
@@ -3840,7 +3840,7 @@
   ~DestroyCaller() {
     if (destroy_func) (*destroy_func)();
   }
-  void Deactivate() { destroy_func = absl::nullopt; }
+  void Deactivate() { destroy_func = std::nullopt; }
 
   template <typename H>
   friend H AbslHashValue(H h, const DestroyCaller& d) {
@@ -3849,7 +3849,7 @@
   bool operator==(const DestroyCaller& d) const { return val == d.val; }
 
   int val;
-  absl::optional<absl::FunctionRef<void()>> destroy_func;
+  std::optional<absl::FunctionRef<void()>> destroy_func;
 };
 
 TEST(Table, ReentrantCallsFail) {
@@ -3896,8 +3896,11 @@
   }
 #if !defined(__clang__) && defined(__GNUC__)
   GTEST_SKIP() << "Flaky on GCC.";
-#endif
-  absl::optional<IntTable> t;
+#elif defined(ABSL_HAVE_THREAD_SANITIZER)
+  GTEST_SKIP() << "Fails on TSan.";
+  // Note: we use else rather than endif here to avoid unreachable code errors.
+#else
+  std::optional<IntTable> t;
   t.emplace({1});
   IntTable* t_ptr = &*t;
   EXPECT_TRUE(t_ptr->contains(1));
@@ -3907,8 +3910,10 @@
       "use-of-uninitialized-value";
 #else
       "destroyed hash table";
-#endif
+#endif  // ABSL_HAVE_MEMORY_SANITIZER
   EXPECT_DEATH_IF_SUPPORTED(t_ptr->contains(1), expected_death_message);
+
+#endif  // ABSL_HAVE_THREAD_SANITIZER
 }
 
 TEST(Table, DestroyedCallsFailDuringDestruction) {
@@ -3925,7 +3930,7 @@
   bool do_lookup = false;
 
   using Table = absl::flat_hash_map<int, std::shared_ptr<int>>;
-  absl::optional<Table> t = Table();
+  std::optional<Table> t = Table();
   Table* t_ptr = &*t;
   auto destroy = [&](int* ptr) {
     if (do_lookup) {
@@ -4001,64 +4006,91 @@
     hs.generate_new_seed();
     EXPECT_EQ(hs.size(), size);
     size = size * 2 + 1;
-  } while (size < MaxValidSizeFor1ByteSlot());
+  } while (size < std::min(MaxStorableSize(),
+                           MaxSizeAtMaxValidCapacity(/*slot_size=*/1)));
 }
 
 TEST(Table, MaxValidSize) {
   IntTable t;
-  EXPECT_EQ(MaxValidSize(sizeof(IntTable::value_type)), t.max_size());
+  EXPECT_EQ(
+      MaxValidSize(sizeof(IntTable::key_type), sizeof(IntTable::value_type)),
+      t.max_size());
   if constexpr (sizeof(size_t) == 8) {
     for (size_t i = 0; i < 35; ++i) {
       SCOPED_TRACE(i);
       size_t slot_size = size_t{1} << i;
-      size_t max_size = MaxValidSize(slot_size);
-      ASSERT_FALSE(IsAboveValidSize(max_size, slot_size));
-      ASSERT_TRUE(IsAboveValidSize(max_size + 1, slot_size));
+      size_t key_size = slot_size;
+      size_t max_size = MaxValidSize(key_size, slot_size);
       ASSERT_LT(max_size, uint64_t{1} << 60);
-      // For non gigantic slot sizes we expect max size to be at least 2^40.
-      if (i <= 22) {
-        ASSERT_FALSE(IsAboveValidSize(size_t{1} << 40, slot_size));
+      if (key_size <= 4) {
+        ASSERT_EQ(max_size, uint64_t{1} << 8 * key_size);
+      } else if (i <= 21) {
         ASSERT_GE(max_size, uint64_t{1} << 40);
       }
-      ASSERT_LT(SizeToCapacity(max_size),
-                uint64_t{1} << HashtableSize::kSizeBitCount);
+      ASSERT_LE(max_size, uint64_t{1} << HashtableSize::kSizeBitCount);
       ASSERT_LT(absl::uint128(max_size) * slot_size, uint64_t{1} << 63);
     }
   }
-  EXPECT_LT(MaxValidSize</*kSizeOfSizeT=*/4>(1), 1 << 30);
-  EXPECT_LT(MaxValidSize</*kSizeOfSizeT=*/4>(2), 1 << 29);
+  EXPECT_LT(MaxValidSize</*kSizeOfSizeT=*/4>(1, 1), 1 << 30);
+  EXPECT_LT(MaxValidSize</*kSizeOfSizeT=*/4>(2, 2), 1 << 29);
   for (size_t i = 0; i < 29; ++i) {
+    SCOPED_TRACE(i);
     size_t slot_size = size_t{1} << i;
-    size_t max_size = MaxValidSize</*kSizeOfSizeT=*/4>(slot_size);
-    ASSERT_FALSE(IsAboveValidSize</*kSizeOfSizeT=*/4>(max_size, slot_size));
-    ASSERT_TRUE(IsAboveValidSize</*kSizeOfSizeT=*/4>(max_size + 1, slot_size));
+    size_t key_size = slot_size;
+    size_t max_size = MaxValidSize</*kSizeOfSizeT=*/4>(key_size, slot_size);
     ASSERT_LT(max_size, 1 << 30);
     size_t max_capacity = SizeToCapacity(max_size);
-    ASSERT_LT(max_capacity, (size_t{1} << 31) / slot_size);
-    ASSERT_GT(max_capacity, (1 << 29) / slot_size);
+    ASSERT_LT(uint64_t{max_capacity} * slot_size, size_t{1} << 31);
+    if (key_size < 4) {
+      ASSERT_EQ(max_size, uint64_t{1} << 8 * key_size);
+    } else {
+      ASSERT_GT(max_capacity, (1 << 29) / slot_size);
+    }
     ASSERT_LT(max_capacity * slot_size, size_t{1} << 31);
   }
 }
 
 TEST(Table, MaxSizeOverflow) {
+#ifdef ABSL_HAVE_EXCEPTIONS
+  GTEST_SKIP() << "Skipping test because exceptions are enabled. EXPECT_DEATH "
+                  "doesn't work with exceptions.";
+#elif defined(ABSL_HAVE_THREAD_SANITIZER)
+  GTEST_SKIP() << "ThreadSanitizer test runs fail on OOM even in EXPECT_DEATH.";
+#else
+  const std::string expected_death_message =
+      "new failed|failed to allocate|bad_alloc|exceeds maximum supported size";
   size_t overflow = (std::numeric_limits<size_t>::max)();
-  EXPECT_DEATH_IF_SUPPORTED(IntTable t(overflow), "Hash table size overflow");
+  EXPECT_DEATH_IF_SUPPORTED(IntTable t(overflow), expected_death_message);
   IntTable t;
-  EXPECT_DEATH_IF_SUPPORTED(t.reserve(overflow), "Hash table size overflow");
-  EXPECT_DEATH_IF_SUPPORTED(t.rehash(overflow), "Hash table size overflow");
-  size_t slightly_overflow = MaxValidSize(sizeof(IntTable::value_type)) + 1;
+  EXPECT_DEATH_IF_SUPPORTED(t.reserve(overflow), expected_death_message);
+  EXPECT_DEATH_IF_SUPPORTED(t.rehash(overflow), expected_death_message);
+  size_t slightly_overflow =
+      MaxValidSize(sizeof(IntTable::key_type), sizeof(IntTable::value_type)) +
+      1;
   size_t slightly_overflow_capacity =
       NextCapacity(NormalizeCapacity(slightly_overflow));
   EXPECT_DEATH_IF_SUPPORTED(IntTable t2(slightly_overflow_capacity - 10),
-                            "Hash table size overflow");
+                            expected_death_message);
   EXPECT_DEATH_IF_SUPPORTED(t.reserve(slightly_overflow),
-                            "Hash table size overflow");
+                            expected_death_message);
   EXPECT_DEATH_IF_SUPPORTED(t.rehash(slightly_overflow),
-                            "Hash table size overflow");
+                            expected_death_message);
   IntTable non_empty_table;
   non_empty_table.insert(0);
   EXPECT_DEATH_IF_SUPPORTED(non_empty_table.reserve(slightly_overflow),
-                            "Hash table size overflow");
+                            expected_death_message);
+#endif  // defined(ABSL_HAVE_THREAD_SANITIZER)
+}
+
+// Tests that reserving enough space for more than the max number of unique keys
+// doesn't crash and we end up with kMaxValidCapacity.
+TEST(Table, MaxSizeOverflowUniqueKeys) {
+  absl::flat_hash_set<uint8_t> t8;
+  t8.reserve(1 << 9);
+  EXPECT_EQ(t8.capacity(), SizeToCapacity(t8.max_size()));
+  absl::flat_hash_set<uint16_t> t16;
+  t16.reserve(1 << 17);
+  EXPECT_EQ(t16.capacity(), SizeToCapacity(t16.max_size()));
 }
 
 // TODO(b/397453582): Remove support for const hasher and remove this test.
@@ -4082,9 +4114,11 @@
   EXPECT_EQ(t.find(3), t.end());
 }
 
-struct ConstUint8Hash {
-  size_t operator()(uint8_t) const { return *value; }
-  size_t* value;
+struct ZeroHash {
+  template <typename T>
+  size_t operator()(T) const {
+    return 0;
+  }
 };
 
 // This test is imitating growth of a very big table and triggers all buffer
@@ -4100,18 +4134,18 @@
 // 4. Then a few times we will extend control buffer end.
 // 5. Finally we will catch up and go to overflow codepath.
 TEST(Table, GrowExtremelyLargeTable) {
+  // ProbedItem8Bytes causes OOMs on some platforms so we use ProbedItem4Bytes.
   constexpr size_t kTargetCapacity =
-#if defined(__wasm__) || defined(__asmjs__) || defined(__i386__)
-      NextCapacity(ProbedItem4Bytes::kMaxNewCapacity);  // OOMs on WASM, 32-bit.
+#if defined(__wasm__) || defined(__asmjs__) || defined(__i386__) || \
+    defined(_MSC_VER) || defined(ABSL_HAVE_THREAD_SANITIZER) ||     \
+    defined(ABSL_HAVE_MEMORY_SANITIZER) ||                          \
+    (!defined(__clang__) && defined(__GNUC__))
+      NextCapacity(ProbedItem4Bytes::kMaxNewCapacity);
 #else
       NextCapacity(ProbedItem8Bytes::kMaxNewCapacity);
 #endif
 
-  size_t hash = 0;
-  // In order to save memory we use 1 byte slot.
-  // There are not enough different values to achieve big capacity, so we
-  // artificially update growth info to force resize.
-  absl::flat_hash_set<uint8_t, ConstUint8Hash> t(63, ConstUint8Hash{&hash});
+  absl::flat_hash_set<uint32_t, ZeroHash> t(63);
   CommonFields& common = RawHashSetTestOnlyAccess::GetCommon(t);
   // Set 0 seed so that H1 is always 0.
   common.set_no_seed_for_testing();
@@ -4127,7 +4161,8 @@
   for (size_t cap = t.capacity(); cap < kTargetCapacity;
        cap = NextCapacity(cap)) {
     ASSERT_EQ(t.capacity(), cap);
-    // Update growth info to force resize on the next insert.
+    // Update growth info to force resize on the next insert. This way we avoid
+    // having to insert many elements.
     common.growth_info().OverwriteManyEmptyAsFull(CapacityToGrowth(cap) -
                                                   t.size());
     t.insert(inserted_till++);
diff --git a/absl/crc/BUILD.bazel b/absl/crc/BUILD.bazel
index 22c3cbf..49e916c 100644
--- a/absl/crc/BUILD.bazel
+++ b/absl/crc/BUILD.bazel
@@ -45,7 +45,6 @@
     deps = [
         "//absl/base",
         "//absl/base:config",
-        "//absl/types:optional",
     ],
 )
 
diff --git a/absl/crc/CMakeLists.txt b/absl/crc/CMakeLists.txt
index 09d3485..034d0d0 100644
--- a/absl/crc/CMakeLists.txt
+++ b/absl/crc/CMakeLists.txt
@@ -25,7 +25,6 @@
   DEPS
     absl::base
     absl::config
-    absl::optional
 )
 
 # Internal-only target, do not depend on directly.
diff --git a/absl/crc/internal/cpu_detect.cc b/absl/crc/internal/cpu_detect.cc
index a697601..86f55d0 100644
--- a/absl/crc/internal/cpu_detect.cc
+++ b/absl/crc/internal/cpu_detect.cc
@@ -15,10 +15,10 @@
 #include "absl/crc/internal/cpu_detect.h"
 
 #include <cstdint>
+#include <optional>  // IWYU pragma: keep
 #include <string>
 
 #include "absl/base/config.h"
-#include "absl/types/optional.h"  // IWYU pragma: keep
 
 #if defined(__aarch64__) && defined(__linux__)
 #include <asm/hwcap.h>
@@ -308,12 +308,12 @@
 CpuType GetCpuType() { return CpuType::kUnknown; }
 
 template <typename T>
-static absl::optional<T> ReadSysctlByName(const char* name) {
+static std::optional<T> ReadSysctlByName(const char* name) {
   T val;
   size_t val_size = sizeof(T);
   int ret = sysctlbyname(name, &val, &val_size, nullptr, 0);
   if (ret == -1) {
-    return absl::nullopt;
+    return std::nullopt;
   }
   return val;
 }
@@ -322,7 +322,7 @@
   // Newer XNU kernels support querying all capabilities in a single
   // sysctlbyname.
 #if defined(CAP_BIT_CRC32) && defined(CAP_BIT_FEAT_PMULL)
-  static const absl::optional<uint64_t> caps =
+  static const std::optional<uint64_t> caps =
       ReadSysctlByName<uint64_t>("hw.optional.arm.caps");
   if (caps.has_value()) {
     constexpr uint64_t kCrc32AndPmullCaps =
@@ -332,13 +332,13 @@
 #endif
 
   // https://developer.apple.com/documentation/kernel/1387446-sysctlbyname/determining_instruction_set_characteristics#3915619
-  static const absl::optional<int> armv8_crc32 =
+  static const std::optional<int> armv8_crc32 =
       ReadSysctlByName<int>("hw.optional.armv8_crc32");
   if (armv8_crc32.value_or(0) == 0) {
     return false;
   }
   // https://developer.apple.com/documentation/kernel/1387446-sysctlbyname/determining_instruction_set_characteristics#3918855
-  static const absl::optional<int> feat_pmull =
+  static const std::optional<int> feat_pmull =
       ReadSysctlByName<int>("hw.optional.arm.FEAT_PMULL");
   if (feat_pmull.value_or(0) == 0) {
     return false;
diff --git a/absl/flags/BUILD.bazel b/absl/flags/BUILD.bazel
index a5ee2c7..9835648 100644
--- a/absl/flags/BUILD.bazel
+++ b/absl/flags/BUILD.bazel
@@ -411,7 +411,6 @@
         "//absl/numeric:int128",
         "//absl/strings",
         "//absl/time",
-        "//absl/types:optional",
         "@googletest//:gtest",
         "@googletest//:gtest_main",
     ],
@@ -437,7 +436,6 @@
         ":reflection",
         "//absl/strings",
         "//absl/time",
-        "//absl/types:optional",
         "@google_benchmark//:benchmark_main",
     ],
 )
diff --git a/absl/flags/CMakeLists.txt b/absl/flags/CMakeLists.txt
index 3ec254a..0c75c93 100644
--- a/absl/flags/CMakeLists.txt
+++ b/absl/flags/CMakeLists.txt
@@ -352,7 +352,6 @@
     absl::flags_parse
     absl::flags_reflection
     absl::int128
-    absl::optional
     absl::raw_logging_internal
     absl::strings
     absl::time
diff --git a/absl/flags/commandlineflag.h b/absl/flags/commandlineflag.h
index 1a9743c..9336d6d 100644
--- a/absl/flags/commandlineflag.h
+++ b/absl/flags/commandlineflag.h
@@ -27,6 +27,7 @@
 #define ABSL_FLAGS_COMMANDLINEFLAG_H_
 
 #include <memory>
+#include <optional>
 #include <string>
 
 #include "absl/base/config.h"
@@ -87,11 +88,11 @@
   // absl::CommandLineFlag::TryGet()
   //
   // Attempts to retrieve the flag value. Returns value on success,
-  // absl::nullopt otherwise.
+  // std::nullopt otherwise.
   template <typename T>
-  absl::optional<T> TryGet() const {
+  std::optional<T> TryGet() const {
     if (IsRetired() || !IsOfType<T>()) {
-      return absl::nullopt;
+      return std::nullopt;
     }
 
     // Implementation notes:
@@ -119,7 +120,7 @@
     Read(&u.value);
     // allow retired flags to be "read", so we can report invalid access.
     if (IsRetired()) {
-      return absl::nullopt;
+      return std::nullopt;
     }
     return std::move(u.value);
   }
diff --git a/absl/flags/flag_benchmark.cc b/absl/flags/flag_benchmark.cc
index 88cc0c5..bbe9cba 100644
--- a/absl/flags/flag_benchmark.cc
+++ b/absl/flags/flag_benchmark.cc
@@ -15,6 +15,7 @@
 
 #include <stdint.h>
 
+#include <optional>
 #include <string>
 #include <vector>
 
@@ -24,7 +25,6 @@
 #include "absl/flags/reflection.h"
 #include "absl/strings/string_view.h"
 #include "absl/time/time.h"
-#include "absl/types/optional.h"
 #include "benchmark/benchmark.h"
 
 namespace {
@@ -32,10 +32,10 @@
 using VectorOfStrings = std::vector<std::string>;
 using AbslDuration = absl::Duration;
 
-// We do not want to take over marshalling for the types absl::optional<int>,
-// absl::optional<std::string> which we do not own. Instead we introduce unique
+// We do not want to take over marshalling for the types std::optional<int>,
+// std::optional<std::string> which we do not own. Instead we introduce unique
 // "aliases" to these types, which we do.
-using AbslOptionalInt = absl::optional<int>;
+using AbslOptionalInt = std::optional<int>;
 struct OptionalInt : AbslOptionalInt {
   using AbslOptionalInt::AbslOptionalInt;
 };
@@ -54,7 +54,7 @@
   return !flag ? "" : absl::UnparseFlag(*flag);
 }
 
-using AbslOptionalString = absl::optional<std::string>;
+using AbslOptionalString = std::optional<std::string>;
 struct OptionalString : AbslOptionalString {
   using AbslOptionalString::AbslOptionalString;
 };
diff --git a/absl/flags/flag_test.cc b/absl/flags/flag_test.cc
index e3ab24c..d303c8d 100644
--- a/absl/flags/flag_test.cc
+++ b/absl/flags/flag_test.cc
@@ -19,6 +19,7 @@
 #include <stdint.h>
 
 #include <atomic>
+#include <optional>
 #include <string>
 #include <thread>  // NOLINT
 #include <vector>
@@ -42,7 +43,6 @@
 #include "absl/strings/string_view.h"
 #include "absl/time/clock.h"
 #include "absl/time/time.h"
-#include "absl/types/optional.h"
 
 ABSL_DECLARE_FLAG(int64_t, mistyped_int_flag);
 ABSL_DECLARE_FLAG(std::vector<std::string>, mistyped_string_flag);
@@ -1038,7 +1038,7 @@
 template <int id, typename F>
 void TestExpectedLeaks(
     F&& f, uint64_t num_leaks,
-    absl::optional<uint64_t> num_new_instances = absl::nullopt) {
+    std::optional<uint64_t> num_new_instances = std::nullopt) {
   if (!num_new_instances.has_value()) num_new_instances = num_leaks;
 
   auto num_leaked_before = flags::NumLeakedFlagValues();
@@ -1216,14 +1216,14 @@
 
 // --------------------------------------------------------------------
 
-ABSL_FLAG(absl::optional<bool>, optional_bool, absl::nullopt, "help");
-ABSL_FLAG(absl::optional<int>, optional_int, {}, "help");
-ABSL_FLAG(absl::optional<double>, optional_double, 9.3, "help");
-ABSL_FLAG(absl::optional<std::string>, optional_string, absl::nullopt, "help");
-ABSL_FLAG(absl::optional<absl::Duration>, optional_duration, absl::nullopt,
+ABSL_FLAG(std::optional<bool>, optional_bool, std::nullopt, "help");
+ABSL_FLAG(std::optional<int>, optional_int, {}, "help");
+ABSL_FLAG(std::optional<double>, optional_double, 9.3, "help");
+ABSL_FLAG(std::optional<std::string>, optional_string, std::nullopt, "help");
+ABSL_FLAG(std::optional<absl::Duration>, optional_duration, std::nullopt,
           "help");
-ABSL_FLAG(absl::optional<absl::optional<int>>, optional_optional_int,
-          absl::nullopt, "help");
+ABSL_FLAG(std::optional<std::optional<int>>, optional_optional_int,
+          std::nullopt, "help");
 #if defined(ABSL_HAVE_STD_OPTIONAL) && !defined(ABSL_USES_STD_OPTIONAL)
 ABSL_FLAG(std::optional<int64_t>, std_optional_int64, std::nullopt, "help");
 #endif
@@ -1232,7 +1232,7 @@
 
 TEST_F(FlagTest, TestOptionalBool) {
   EXPECT_FALSE(absl::GetFlag(FLAGS_optional_bool).has_value());
-  EXPECT_EQ(absl::GetFlag(FLAGS_optional_bool), absl::nullopt);
+  EXPECT_EQ(absl::GetFlag(FLAGS_optional_bool), std::nullopt);
 
   absl::SetFlag(&FLAGS_optional_bool, false);
   EXPECT_TRUE(absl::GetFlag(FLAGS_optional_bool).has_value());
@@ -1242,16 +1242,16 @@
   EXPECT_TRUE(absl::GetFlag(FLAGS_optional_bool).has_value());
   EXPECT_EQ(absl::GetFlag(FLAGS_optional_bool), true);
 
-  absl::SetFlag(&FLAGS_optional_bool, absl::nullopt);
+  absl::SetFlag(&FLAGS_optional_bool, std::nullopt);
   EXPECT_FALSE(absl::GetFlag(FLAGS_optional_bool).has_value());
-  EXPECT_EQ(absl::GetFlag(FLAGS_optional_bool), absl::nullopt);
+  EXPECT_EQ(absl::GetFlag(FLAGS_optional_bool), std::nullopt);
 }
 
 // --------------------------------------------------------------------
 
 TEST_F(FlagTest, TestOptionalInt) {
   EXPECT_FALSE(absl::GetFlag(FLAGS_optional_int).has_value());
-  EXPECT_EQ(absl::GetFlag(FLAGS_optional_int), absl::nullopt);
+  EXPECT_EQ(absl::GetFlag(FLAGS_optional_int), std::nullopt);
 
   absl::SetFlag(&FLAGS_optional_int, 0);
   EXPECT_TRUE(absl::GetFlag(FLAGS_optional_int).has_value());
@@ -1261,9 +1261,9 @@
   EXPECT_TRUE(absl::GetFlag(FLAGS_optional_int).has_value());
   EXPECT_EQ(absl::GetFlag(FLAGS_optional_int), 10);
 
-  absl::SetFlag(&FLAGS_optional_int, absl::nullopt);
+  absl::SetFlag(&FLAGS_optional_int, std::nullopt);
   EXPECT_FALSE(absl::GetFlag(FLAGS_optional_int).has_value());
-  EXPECT_EQ(absl::GetFlag(FLAGS_optional_int), absl::nullopt);
+  EXPECT_EQ(absl::GetFlag(FLAGS_optional_int), std::nullopt);
 }
 
 // --------------------------------------------------------------------
@@ -1280,16 +1280,16 @@
   EXPECT_TRUE(absl::GetFlag(FLAGS_optional_double).has_value());
   EXPECT_DOUBLE_EQ(*absl::GetFlag(FLAGS_optional_double), 1.234);
 
-  absl::SetFlag(&FLAGS_optional_double, absl::nullopt);
+  absl::SetFlag(&FLAGS_optional_double, std::nullopt);
   EXPECT_FALSE(absl::GetFlag(FLAGS_optional_double).has_value());
-  EXPECT_EQ(absl::GetFlag(FLAGS_optional_double), absl::nullopt);
+  EXPECT_EQ(absl::GetFlag(FLAGS_optional_double), std::nullopt);
 }
 
 // --------------------------------------------------------------------
 
 TEST_F(FlagTest, TestOptionalString) {
   EXPECT_FALSE(absl::GetFlag(FLAGS_optional_string).has_value());
-  EXPECT_EQ(absl::GetFlag(FLAGS_optional_string), absl::nullopt);
+  EXPECT_EQ(absl::GetFlag(FLAGS_optional_string), std::nullopt);
 
   // Setting optional string to "" leads to undefined behavior.
 
@@ -1301,16 +1301,16 @@
   EXPECT_TRUE(absl::GetFlag(FLAGS_optional_string).has_value());
   EXPECT_EQ(absl::GetFlag(FLAGS_optional_string), "QWERTY");
 
-  absl::SetFlag(&FLAGS_optional_string, absl::nullopt);
+  absl::SetFlag(&FLAGS_optional_string, std::nullopt);
   EXPECT_FALSE(absl::GetFlag(FLAGS_optional_string).has_value());
-  EXPECT_EQ(absl::GetFlag(FLAGS_optional_string), absl::nullopt);
+  EXPECT_EQ(absl::GetFlag(FLAGS_optional_string), std::nullopt);
 }
 
 // --------------------------------------------------------------------
 
 TEST_F(FlagTest, TestOptionalDuration) {
   EXPECT_FALSE(absl::GetFlag(FLAGS_optional_duration).has_value());
-  EXPECT_EQ(absl::GetFlag(FLAGS_optional_duration), absl::nullopt);
+  EXPECT_EQ(absl::GetFlag(FLAGS_optional_duration), std::nullopt);
 
   absl::SetFlag(&FLAGS_optional_duration, absl::ZeroDuration());
   EXPECT_TRUE(absl::GetFlag(FLAGS_optional_duration).has_value());
@@ -1320,37 +1320,37 @@
   EXPECT_TRUE(absl::GetFlag(FLAGS_optional_duration).has_value());
   EXPECT_EQ(absl::GetFlag(FLAGS_optional_duration), absl::Hours(3));
 
-  absl::SetFlag(&FLAGS_optional_duration, absl::nullopt);
+  absl::SetFlag(&FLAGS_optional_duration, std::nullopt);
   EXPECT_FALSE(absl::GetFlag(FLAGS_optional_duration).has_value());
-  EXPECT_EQ(absl::GetFlag(FLAGS_optional_duration), absl::nullopt);
+  EXPECT_EQ(absl::GetFlag(FLAGS_optional_duration), std::nullopt);
 }
 
 // --------------------------------------------------------------------
 
 TEST_F(FlagTest, TestOptionalOptional) {
   EXPECT_FALSE(absl::GetFlag(FLAGS_optional_optional_int).has_value());
-  EXPECT_EQ(absl::GetFlag(FLAGS_optional_optional_int), absl::nullopt);
+  EXPECT_EQ(absl::GetFlag(FLAGS_optional_optional_int), std::nullopt);
 
-  absl::optional<int> nullint{absl::nullopt};
+  std::optional<int> nullint{std::nullopt};
 
   absl::SetFlag(&FLAGS_optional_optional_int, nullint);
   EXPECT_TRUE(absl::GetFlag(FLAGS_optional_optional_int).has_value());
   EXPECT_NE(absl::GetFlag(FLAGS_optional_optional_int), nullint);
   EXPECT_EQ(absl::GetFlag(FLAGS_optional_optional_int),
-            absl::optional<absl::optional<int>>{nullint});
+            std::optional<std::optional<int>>{nullint});
 
   absl::SetFlag(&FLAGS_optional_optional_int, 0);
   EXPECT_TRUE(absl::GetFlag(FLAGS_optional_optional_int).has_value());
   EXPECT_EQ(absl::GetFlag(FLAGS_optional_optional_int), 0);
 
-  absl::SetFlag(&FLAGS_optional_optional_int, absl::optional<int>{0});
+  absl::SetFlag(&FLAGS_optional_optional_int, std::optional<int>{0});
   EXPECT_TRUE(absl::GetFlag(FLAGS_optional_optional_int).has_value());
   EXPECT_EQ(absl::GetFlag(FLAGS_optional_optional_int), 0);
-  EXPECT_EQ(absl::GetFlag(FLAGS_optional_optional_int), absl::optional<int>{0});
+  EXPECT_EQ(absl::GetFlag(FLAGS_optional_optional_int), std::optional<int>{0});
 
-  absl::SetFlag(&FLAGS_optional_optional_int, absl::nullopt);
+  absl::SetFlag(&FLAGS_optional_optional_int, std::nullopt);
   EXPECT_FALSE(absl::GetFlag(FLAGS_optional_optional_int).has_value());
-  EXPECT_EQ(absl::GetFlag(FLAGS_optional_optional_int), absl::nullopt);
+  EXPECT_EQ(absl::GetFlag(FLAGS_optional_optional_int), std::nullopt);
 }
 
 // --------------------------------------------------------------------
diff --git a/absl/flags/marshalling.h b/absl/flags/marshalling.h
index 301213a..5e04d6a 100644
--- a/absl/flags/marshalling.h
+++ b/absl/flags/marshalling.h
@@ -199,15 +199,12 @@
 #ifndef ABSL_FLAGS_MARSHALLING_H_
 #define ABSL_FLAGS_MARSHALLING_H_
 
-#include "absl/base/config.h"
-#include "absl/numeric/int128.h"
-
-#if defined(ABSL_HAVE_STD_OPTIONAL) && !defined(ABSL_USES_STD_OPTIONAL)
 #include <optional>
-#endif
 #include <string>
 #include <vector>
 
+#include "absl/base/config.h"
+#include "absl/numeric/int128.h"
 #include "absl/strings/string_view.h"
 #include "absl/types/optional.h"
 
@@ -242,21 +239,6 @@
 bool AbslParseFlag(absl::string_view, std::vector<std::string>*, std::string*);
 
 template <typename T>
-bool AbslParseFlag(absl::string_view text, absl::optional<T>* f,
-                   std::string* err) {
-  if (text.empty()) {
-    *f = absl::nullopt;
-    return true;
-  }
-  T value;
-  if (!absl::ParseFlag(text, &value, err)) return false;
-
-  *f = std::move(value);
-  return true;
-}
-
-#if defined(ABSL_HAVE_STD_OPTIONAL) && !defined(ABSL_USES_STD_OPTIONAL)
-template <typename T>
 bool AbslParseFlag(absl::string_view text, std::optional<T>* f,
                    std::string* err) {
   if (text.empty()) {
@@ -269,7 +251,6 @@
   *f = std::move(value);
   return true;
 }
-#endif
 
 template <typename T>
 bool InvokeParseFlag(absl::string_view input, T* dst, std::string* err) {
@@ -285,16 +266,9 @@
 std::string AbslUnparseFlag(const std::vector<std::string>&);
 
 template <typename T>
-std::string AbslUnparseFlag(const absl::optional<T>& f) {
-  return f.has_value() ? absl::UnparseFlag(*f) : "";
-}
-
-#if defined(ABSL_HAVE_STD_OPTIONAL) && !defined(ABSL_USES_STD_OPTIONAL)
-template <typename T>
 std::string AbslUnparseFlag(const std::optional<T>& f) {
   return f.has_value() ? absl::UnparseFlag(*f) : "";
 }
-#endif
 
 template <typename T>
 std::string Unparse(const T& v) {
diff --git a/absl/flags/marshalling_test.cc b/absl/flags/marshalling_test.cc
index b0e055f..a5faabc 100644
--- a/absl/flags/marshalling_test.cc
+++ b/absl/flags/marshalling_test.cc
@@ -19,6 +19,7 @@
 
 #include <cmath>
 #include <limits>
+#include <optional>
 #include <string>
 #include <vector>
 
@@ -777,7 +778,7 @@
 
 TEST(MarshallingTest, TestOptionalBoolParsing) {
   std::string err;
-  absl::optional<bool> value;
+  std::optional<bool> value;
 
   EXPECT_TRUE(absl::ParseFlag("", &value, &err));
   EXPECT_FALSE(value.has_value());
@@ -797,7 +798,7 @@
 
 TEST(MarshallingTest, TestOptionalIntParsing) {
   std::string err;
-  absl::optional<int> value;
+  std::optional<int> value;
 
   EXPECT_TRUE(absl::ParseFlag("", &value, &err));
   EXPECT_FALSE(value.has_value());
@@ -817,7 +818,7 @@
 
 TEST(MarshallingTest, TestOptionalDoubleParsing) {
   std::string err;
-  absl::optional<double> value;
+  std::optional<double> value;
 
   EXPECT_TRUE(absl::ParseFlag("", &value, &err));
   EXPECT_FALSE(value.has_value());
@@ -837,7 +838,7 @@
 
 TEST(MarshallingTest, TestOptionalStringParsing) {
   std::string err;
-  absl::optional<std::string> value;
+  std::optional<std::string> value;
 
   EXPECT_TRUE(absl::ParseFlag("", &value, &err));
   EXPECT_FALSE(value.has_value());
@@ -1041,49 +1042,49 @@
 // --------------------------------------------------------------------
 
 TEST(MarshallingTest, TestOptionalBoolUnparsing) {
-  absl::optional<bool> value;
+  std::optional<bool> value;
 
   EXPECT_EQ(absl::UnparseFlag(value), "");
   value = true;
   EXPECT_EQ(absl::UnparseFlag(value), "true");
   value = false;
   EXPECT_EQ(absl::UnparseFlag(value), "false");
-  value = absl::nullopt;
+  value = std::nullopt;
   EXPECT_EQ(absl::UnparseFlag(value), "");
 }
 
 // --------------------------------------------------------------------
 
 TEST(MarshallingTest, TestOptionalIntUnparsing) {
-  absl::optional<int> value;
+  std::optional<int> value;
 
   EXPECT_EQ(absl::UnparseFlag(value), "");
   value = 0;
   EXPECT_EQ(absl::UnparseFlag(value), "0");
   value = -12;
   EXPECT_EQ(absl::UnparseFlag(value), "-12");
-  value = absl::nullopt;
+  value = std::nullopt;
   EXPECT_EQ(absl::UnparseFlag(value), "");
 }
 
 // --------------------------------------------------------------------
 
 TEST(MarshallingTest, TestOptionalDoubleUnparsing) {
-  absl::optional<double> value;
+  std::optional<double> value;
 
   EXPECT_EQ(absl::UnparseFlag(value), "");
   value = 1.;
   EXPECT_EQ(absl::UnparseFlag(value), "1");
   value = -1.23;
   EXPECT_EQ(absl::UnparseFlag(value), "-1.23");
-  value = absl::nullopt;
+  value = std::nullopt;
   EXPECT_EQ(absl::UnparseFlag(value), "");
 }
 
 // --------------------------------------------------------------------
 
 TEST(MarshallingTest, TestOptionalStringUnparsing) {
-  absl::optional<std::string> strvalue;
+  std::optional<std::string> strvalue;
   EXPECT_EQ(absl::UnparseFlag(strvalue), "");
 
   strvalue = "asdfg";
diff --git a/absl/functional/BUILD.bazel b/absl/functional/BUILD.bazel
index b7aa31f..dcf808b 100644
--- a/absl/functional/BUILD.bazel
+++ b/absl/functional/BUILD.bazel
@@ -149,7 +149,6 @@
         "//absl/base:config",
         "//absl/strings",
         "//absl/strings:string_view",
-        "//absl/types:variant",
         "@googletest//:gtest",
         "@googletest//:gtest_main",
     ],
diff --git a/absl/functional/CMakeLists.txt b/absl/functional/CMakeLists.txt
index 07f3dc0..4ffb513 100644
--- a/absl/functional/CMakeLists.txt
+++ b/absl/functional/CMakeLists.txt
@@ -135,6 +135,5 @@
     absl::overload
     absl::string_view
     absl::strings
-    absl::variant
     GTest::gmock_main
 )
diff --git a/absl/functional/overload_test.cc b/absl/functional/overload_test.cc
index 802e11f..bb51020 100644
--- a/absl/functional/overload_test.cc
+++ b/absl/functional/overload_test.cc
@@ -17,12 +17,12 @@
 #include <cstdint>
 #include <string>
 #include <type_traits>
+#include <variant>
 
 #include "gtest/gtest.h"
 #include "absl/base/config.h"
 #include "absl/strings/str_cat.h"
 #include "absl/strings/string_view.h"
-#include "absl/types/variant.h"
 
 namespace {
 
@@ -145,32 +145,32 @@
 }
 
 TEST(OverloadTest, VariantVisitDispatchesCorrectly) {
-  absl::variant<int, double, std::string> v(1);
+  std::variant<int, double, std::string> v(1);
   auto overloaded = absl::Overload{
       [](int) -> absl::string_view { return "int"; },
       [](double) -> absl::string_view { return "double"; },
       [](const std::string&) -> absl::string_view { return "string"; },
   };
 
-  EXPECT_EQ("int", absl::visit(overloaded, v));
+  EXPECT_EQ("int", std::visit(overloaded, v));
   v = 1.1;
-  EXPECT_EQ("double", absl::visit(overloaded, v));
+  EXPECT_EQ("double", std::visit(overloaded, v));
   v = "hello";
-  EXPECT_EQ("string", absl::visit(overloaded, v));
+  EXPECT_EQ("string", std::visit(overloaded, v));
 }
 
 TEST(OverloadTest, VariantVisitWithAutoFallbackDispatchesCorrectly) {
-  absl::variant<std::string, int32_t, int64_t> v(int32_t{1});
+  std::variant<std::string, int32_t, int64_t> v(int32_t{1});
   auto overloaded = absl::Overload{
       [](const std::string& s) { return s.size(); },
       [](const auto& s) { return sizeof(s); },
   };
 
-  EXPECT_EQ(4, absl::visit(overloaded, v));
+  EXPECT_EQ(4, std::visit(overloaded, v));
   v = int64_t{1};
-  EXPECT_EQ(8, absl::visit(overloaded, v));
+  EXPECT_EQ(8, std::visit(overloaded, v));
   v = std::string("hello");
-  EXPECT_EQ(5, absl::visit(overloaded, v));
+  EXPECT_EQ(5, std::visit(overloaded, v));
 }
 
 // This API used to be exported as a function, so it should also work fine to
@@ -180,14 +180,14 @@
       absl::Overload([](const std::string& s) { return s.size(); },
                      [](const auto& s) { return sizeof(s); });
 
-  absl::variant<std::string, int32_t, int64_t> v(int32_t{1});
-  EXPECT_EQ(4, absl::visit(overloaded, v));
+  std::variant<std::string, int32_t, int64_t> v(int32_t{1});
+  EXPECT_EQ(4, std::visit(overloaded, v));
 
   v = int64_t{1};
-  EXPECT_EQ(8, absl::visit(overloaded, v));
+  EXPECT_EQ(8, std::visit(overloaded, v));
 
   v = std::string("hello");
-  EXPECT_EQ(5, absl::visit(overloaded, v));
+  EXPECT_EQ(5, std::visit(overloaded, v));
 }
 
 TEST(OverloadTest, HasConstexprConstructor) {
diff --git a/absl/hash/BUILD.bazel b/absl/hash/BUILD.bazel
index 76dd606..a2d3a02 100644
--- a/absl/hash/BUILD.bazel
+++ b/absl/hash/BUILD.bazel
@@ -98,8 +98,6 @@
         "//absl/numeric:bits",
         "//absl/strings:cord_test_helpers",
         "//absl/strings:string_view",
-        "//absl/types:optional",
-        "//absl/types:variant",
         "@googletest//:gtest",
         "@googletest//:gtest_main",
     ],
diff --git a/absl/hash/CMakeLists.txt b/absl/hash/CMakeLists.txt
index c8797ff..c593a5b 100644
--- a/absl/hash/CMakeLists.txt
+++ b/absl/hash/CMakeLists.txt
@@ -76,10 +76,8 @@
     absl::hash_testing
     absl::memory
     absl::meta
-    absl::optional
     absl::spy_hash_state
     absl::string_view
-    absl::variant
     GTest::gmock_main
 )
 
diff --git a/absl/hash/hash_test.cc b/absl/hash/hash_test.cc
index 7395ab7..039515a 100644
--- a/absl/hash/hash_test.cc
+++ b/absl/hash/hash_test.cc
@@ -26,6 +26,7 @@
 #include <ios>
 #include <limits>
 #include <memory>
+#include <optional>
 #include <ostream>
 #include <set>
 #include <string>
@@ -34,6 +35,7 @@
 #include <type_traits>
 #include <unordered_map>
 #include <utility>
+#include <variant>
 #include <vector>
 
 #include "gmock/gmock.h"
@@ -49,8 +51,6 @@
 #include "absl/numeric/bits.h"
 #include "absl/strings/cord_test_helpers.h"
 #include "absl/strings/string_view.h"
-#include "absl/types/optional.h"
-#include "absl/types/variant.h"
 
 #ifdef ABSL_INTERNAL_STD_FILESYSTEM_PATH_HASH_AVAILABLE
 #include <filesystem>  // NOLINT
@@ -748,22 +748,22 @@
 }
 
 TEST(HashValueTest, Optional) {
-  EXPECT_TRUE(is_hashable<absl::optional<Private>>::value);
+  EXPECT_TRUE(is_hashable<std::optional<Private>>::value);
 
-  using O = absl::optional<Private>;
+  using O = std::optional<Private>;
   EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
       std::make_tuple(O{}, O{{1}}, O{{-1}}, O{{10}})));
 }
 
 TEST(HashValueTest, Variant) {
-  using V = absl::variant<Private, std::string>;
+  using V = std::variant<Private, std::string>;
   EXPECT_TRUE(is_hashable<V>::value);
 
   EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
       V(Private{1}), V(Private{-1}), V(Private{2}), V("ABC"), V("BCD"))));
 
   struct S {};
-  EXPECT_FALSE(is_hashable<absl::variant<S>>::value);
+  EXPECT_FALSE(is_hashable<std::variant<S>>::value);
 }
 
 TEST(HashValueTest, ReferenceWrapper) {
diff --git a/absl/hash/hash_testing.h b/absl/hash/hash_testing.h
index 817a40d..509df07 100644
--- a/absl/hash/hash_testing.h
+++ b/absl/hash/hash_testing.h
@@ -20,6 +20,7 @@
 #include <string>
 #include <tuple>
 #include <type_traits>
+#include <variant>
 #include <vector>
 
 #include "gmock/gmock.h"
@@ -193,9 +194,9 @@
     const V& value;
     size_t index;
     std::string ToString() const {
-      return absl::visit(PrintVisitor{index}, value);
+      return std::visit(PrintVisitor{index}, value);
     }
-    SpyHashState expand() const { return absl::visit(ExpandVisitor{}, value); }
+    SpyHashState expand() const { return std::visit(ExpandVisitor{}, value); }
   };
 
   using EqClass = std::vector<Info>;
@@ -206,7 +207,7 @@
   for (const auto& value : values) {
     EqClass* c = nullptr;
     for (auto& eqclass : classes) {
-      if (absl::visit(EqVisitor<Eq>{equals}, value, eqclass[0].value)) {
+      if (std::visit(EqVisitor<Eq>{equals}, value, eqclass[0].value)) {
         c = &eqclass;
         break;
       }
@@ -300,11 +301,11 @@
 
 template <typename... T>
 using VariantForTypes = typename MakeTypeSet<
-    const typename std::decay<T>::type*...>::template apply<absl::variant>;
+    const typename std::decay<T>::type*...>::template apply<std::variant>;
 
 template <typename Container>
 struct ContainerAsVector {
-  using V = absl::variant<const typename Container::value_type*>;
+  using V = std::variant<const typename Container::value_type*>;
   using Out = std::vector<V>;
 
   static Out Do(const Container& values) {
diff --git a/absl/hash/internal/hash.h b/absl/hash/internal/hash.h
index 4fe474e..a6c8313 100644
--- a/absl/hash/internal/hash.h
+++ b/absl/hash/internal/hash.h
@@ -63,6 +63,7 @@
 #include <list>
 #include <map>
 #include <memory>
+#include <optional>
 #include <set>
 #include <string>
 #include <string_view>
@@ -71,6 +72,7 @@
 #include <unordered_map>
 #include <unordered_set>
 #include <utility>
+#include <variant>
 #include <vector>
 
 #include "absl/base/attributes.h"
@@ -898,10 +900,10 @@
   return H::combine(std::move(hash_state), opt.get());
 }
 
-// AbslHashValue for hashing absl::optional
+// AbslHashValue for hashing std::optional
 template <typename H, typename T>
 typename std::enable_if<is_hashable<T>::value, H>::type AbslHashValue(
-    H hash_state, const absl::optional<T>& opt) {
+    H hash_state, const std::optional<T>& opt) {
   if (opt) hash_state = H::combine(std::move(hash_state), *opt);
   return H::combine(std::move(hash_state), opt.has_value());
 }
@@ -915,12 +917,12 @@
   }
 };
 
-// AbslHashValue for hashing absl::variant
+// AbslHashValue for hashing std::variant
 template <typename H, typename... T>
 typename std::enable_if<conjunction<is_hashable<T>...>::value, H>::type
-AbslHashValue(H hash_state, const absl::variant<T...>& v) {
+AbslHashValue(H hash_state, const std::variant<T...>& v) {
   if (!v.valueless_by_exception()) {
-    hash_state = absl::visit(VariantVisitor<H>{std::move(hash_state)}, v);
+    hash_state = std::visit(VariantVisitor<H>{std::move(hash_state)}, v);
   }
   return H::combine(std::move(hash_state), v.index());
 }
@@ -1079,19 +1081,24 @@
   // The general idea here is to do two CRC32 operations in parallel using the
   // low and high 32 bits of state as CRC states. Note that: (1) when absl::Hash
   // is inlined into swisstable lookups, we know that the seed's high bits are
-  // zero so s.u32s.high is available immediately. (2) We chose to rotate value
-  // right by 45 for the low CRC because that minimizes the probe benchmark
-  // geomean across the 64 possible rotations. (3) The union makes it easy for
-  // the compiler to understand that the high and low CRC states are independent
-  // from each other so that when CombineRawImpl is repeated (e.g. for
-  // std::pair<size_t, size_t>), the CRC chains can run in parallel. We
+  // zero so s.u32s.high is available immediately. (2) We chose to multiply
+  // value by 3 for the low CRC because (a) multiplication by 3 can be done in 1
+  // cycle on x86/ARM and (b) multiplication has carry bits so it's nonlinear in
+  // GF(2) and therefore ensures that the two CRCs are independent (unlike bit
+  // rotation, XOR, etc). (3) We also tried using addition instead of
+  // multiplication by 3, but (a) code size is larger and (b) if the input keys
+  // all have 0s in the bits where the addition constant has 1s, then the
+  // addition is equivalent to XOR and linear in GF(2). (4) The union makes it
+  // easy for the compiler to understand that the high and low CRC states are
+  // independent from each other so that when CombineRawImpl is repeated (e.g.
+  // for std::pair<size_t, size_t>), the CRC chains can run in parallel. We
   // originally tried using bswaps rather than shifting by 32 bits (to get from
   // high to low bits) because bswap is one byte smaller in code size, but the
   // compiler couldn't understand that the CRC chains were independent.
   s.u32s.high =
       static_cast<uint32_t>(ABSL_HASH_INTERNAL_CRC32_U64(s.u32s.high, value));
   s.u32s.low = static_cast<uint32_t>(
-      ABSL_HASH_INTERNAL_CRC32_U64(s.u32s.low, absl::rotr(value, 45)));
+      ABSL_HASH_INTERNAL_CRC32_U64(s.u32s.low, 3 * value));
   return s.u64;
 }
 #else   // ABSL_HASH_INTERNAL_HAS_CRC32
diff --git a/absl/hash/internal/spy_hash_state.h b/absl/hash/internal/spy_hash_state.h
index 823e1e9..80c9767 100644
--- a/absl/hash/internal/spy_hash_state.h
+++ b/absl/hash/internal/spy_hash_state.h
@@ -18,6 +18,8 @@
 #include <algorithm>
 #include <cstddef>
 #include <cstdint>
+#include <memory>
+#include <optional>
 #include <ostream>
 #include <string>
 #include <vector>
@@ -44,7 +46,7 @@
 template <typename T>
 class SpyHashStateImpl : public HashStateBase<SpyHashStateImpl<T>> {
  public:
-  SpyHashStateImpl() : error_(std::make_shared<absl::optional<std::string>>()) {
+  SpyHashStateImpl() : error_(std::make_shared<std::optional<std::string>>()) {
     static_assert(std::is_void<T>::value, "");
   }
 
@@ -198,7 +200,7 @@
     return state;
   }
 
-  absl::optional<std::string> error() const {
+  std::optional<std::string> error() const {
     if (moved_from_) {
       return "Returned a moved-from instance of the hash state object.";
     }
@@ -212,7 +214,7 @@
 
   struct UnorderedCombinerCallback {
     std::vector<std::string> element_hash_representations;
-    std::shared_ptr<absl::optional<std::string>> error;
+    std::shared_ptr<std::optional<std::string>> error;
 
     // The inner spy can have a different type.
     template <typename U>
@@ -242,7 +244,7 @@
   // This is a shared_ptr because we want all instances of the particular
   // SpyHashState run to share the field. This way we can set the error for
   // use-after-move and all the copies will see it.
-  std::shared_ptr<absl::optional<std::string>> error_;
+  std::shared_ptr<std::optional<std::string>> error_;
   bool moved_from_ = false;
 };
 
diff --git a/absl/log/BUILD.bazel b/absl/log/BUILD.bazel
index 5bc7150..ec2fde9 100644
--- a/absl/log/BUILD.bazel
+++ b/absl/log/BUILD.bazel
@@ -285,7 +285,6 @@
         ":vlog_is_on",
         "//absl/base:log_severity",
         "//absl/flags:flag",
-        "//absl/types:optional",
         "@googletest//:gtest",
         "@googletest//:gtest_main",
     ],
@@ -501,7 +500,6 @@
         "//absl/log/internal:test_matchers",
         "//absl/strings",
         "//absl/strings:str_format",
-        "//absl/types:optional",
         "@googletest//:gtest",
         "@googletest//:gtest_main",
     ],
diff --git a/absl/log/CMakeLists.txt b/absl/log/CMakeLists.txt
index 9d097ab..609f432 100644
--- a/absl/log/CMakeLists.txt
+++ b/absl/log/CMakeLists.txt
@@ -757,7 +757,6 @@
     absl::nullability
     absl::strings
     absl::synchronization
-    absl::optional
 )
 
 absl_cc_library(
@@ -806,7 +805,6 @@
     absl::vlog_is_on
     absl::log_severity
     absl::flags
-    absl::optional
     GTest::gmock_main
 )
 
@@ -1016,7 +1014,6 @@
     absl::config
     absl::log
     absl::log_internal_test_matchers
-    absl::optional
     absl::scoped_mock_log
     absl::str_format
     absl::strings
diff --git a/absl/log/internal/BUILD.bazel b/absl/log/internal/BUILD.bazel
index 32ae277..833a5f9 100644
--- a/absl/log/internal/BUILD.bazel
+++ b/absl/log/internal/BUILD.bazel
@@ -470,7 +470,6 @@
         "//absl/memory",
         "//absl/strings",
         "//absl/synchronization",
-        "//absl/types:optional",
     ],
 )
 
diff --git a/absl/log/internal/structured_proto.cc b/absl/log/internal/structured_proto.cc
index e3829e4..eed2e88 100644
--- a/absl/log/internal/structured_proto.cc
+++ b/absl/log/internal/structured_proto.cc
@@ -16,11 +16,11 @@
 #include "absl/log/internal/structured_proto.h"
 
 #include <cstdint>
+#include <variant>
 
 #include "absl/base/config.h"
 #include "absl/log/internal/proto.h"
 #include "absl/types/span.h"
-#include "absl/types/variant.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
@@ -81,11 +81,11 @@
 // Handles protobuf-encoding a type contained inside `StructuredProtoField`.
 struct EncoderVisitor final {
   bool operator()(StructuredProtoField::Varint varint) {
-    return absl::visit(VarintEncoderVisitor{field_number, buf}, varint);
+    return std::visit(VarintEncoderVisitor{field_number, buf}, varint);
   }
 
   bool operator()(StructuredProtoField::I64 i64) {
-    return absl::visit(I64EncoderVisitor{field_number, buf}, i64);
+    return std::visit(I64EncoderVisitor{field_number, buf}, i64);
   }
 
   bool operator()(StructuredProtoField::LengthDelimited length_delimited) {
@@ -95,7 +95,7 @@
   }
 
   bool operator()(StructuredProtoField::I32 i32) {
-    return absl::visit(I32EncoderVisitor{field_number, buf}, i32);
+    return std::visit(I32EncoderVisitor{field_number, buf}, i32);
   }
 
   uint64_t field_number;
@@ -106,7 +106,7 @@
 
 bool EncodeStructuredProtoField(StructuredProtoField field,
                                 absl::Span<char>& buf) {
-  return absl::visit(EncoderVisitor{field.field_number, buf}, field.value);
+  return std::visit(EncoderVisitor{field.field_number, buf}, field.value);
 }
 
 }  // namespace log_internal
diff --git a/absl/log/internal/structured_proto.h b/absl/log/internal/structured_proto.h
index 3ebc4be..04ec499 100644
--- a/absl/log/internal/structured_proto.h
+++ b/absl/log/internal/structured_proto.h
@@ -21,6 +21,7 @@
 
 #include <cstddef>
 #include <cstdint>
+#include <variant>
 
 #include "absl/base/config.h"
 #include "absl/log/internal/proto.h"
@@ -35,11 +36,11 @@
 struct StructuredProtoField final {
   // Numeric type encoded with varint encoding:
   // https://protobuf.dev/programming-guides/encoding/#varints
-  using Varint = absl::variant<uint64_t, int64_t, uint32_t, int32_t, bool>;
+  using Varint = std::variant<uint64_t, int64_t, uint32_t, int32_t, bool>;
 
   // Fixed-length 64-bit integer encoding:
   // https://protobuf.dev/programming-guides/encoding/#non-varints
-  using I64 = absl::variant<uint64_t, int64_t, double>;
+  using I64 = std::variant<uint64_t, int64_t, double>;
 
   // Length-delimited record type (string, sub-message):
   // https://protobuf.dev/programming-guides/encoding/#length-types
@@ -47,11 +48,11 @@
 
   // Fixed-length 32-bit integer encoding:
   // https://protobuf.dev/programming-guides/encoding/#non-varints
-  using I32 = absl::variant<uint32_t, int32_t, float>;
+  using I32 = std::variant<uint32_t, int32_t, float>;
 
   // Valid record type:
   // https://protobuf.dev/programming-guides/encoding/#structure
-  using Value = absl::variant<Varint, I64, LengthDelimited, I32>;
+  using Value = std::variant<Varint, I64, LengthDelimited, I32>;
 
   // Field number for the protobuf value.
   uint64_t field_number;
@@ -88,7 +89,7 @@
     uint64_t field_number;
   };
 
-  return absl::visit(BufferSizeVisitor{field.field_number}, field.value);
+  return std::visit(BufferSizeVisitor{field.field_number}, field.value);
 }
 
 // Encodes `field` into `buf` using protobuf encoding.
diff --git a/absl/log/internal/vlog_config.cc b/absl/log/internal/vlog_config.cc
index e9b4827..51f003c 100644
--- a/absl/log/internal/vlog_config.cc
+++ b/absl/log/internal/vlog_config.cc
@@ -20,6 +20,7 @@
 #include <atomic>
 #include <functional>
 #include <memory>
+#include <optional>
 #include <string>
 #include <utility>
 #include <vector>
@@ -38,7 +39,6 @@
 #include "absl/strings/string_view.h"
 #include "absl/strings/strip.h"
 #include "absl/synchronization/mutex.h"
-#include "absl/types/optional.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
@@ -189,7 +189,7 @@
 // Allocates memory.
 int PrependVModuleLocked(absl::string_view module_pattern, int log_level)
     ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex) {
-  absl::optional<int> old_log_level;
+  std::optional<int> old_log_level;
   for (const auto& info : get_vmodule_info()) {
     if (FNMatch(info.module_pattern, module_pattern)) {
       old_log_level = info.vlog_level;
diff --git a/absl/log/log_format_test.cc b/absl/log/log_format_test.cc
index 9f1cc6b..b23d90f 100644
--- a/absl/log/log_format_test.cc
+++ b/absl/log/log_format_test.cc
@@ -19,6 +19,7 @@
 #include <iomanip>
 #include <ios>
 #include <limits>
+#include <optional>
 #include <ostream>
 #include <sstream>
 #include <string>
@@ -28,6 +29,7 @@
 #ifdef __ANDROID__
 #include <android/api-level.h>
 #endif
+
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 #include "absl/base/config.h"
@@ -39,7 +41,6 @@
 #include "absl/strings/str_cat.h"
 #include "absl/strings/str_format.h"
 #include "absl/strings/string_view.h"
-#include "absl/types/optional.h"
 
 namespace {
 using ::absl::log_internal::AsString;
@@ -2096,7 +2097,7 @@
     }
 
    private:
-    absl::optional<size_t> size_;
+    std::optional<size_t> size_;
   } extractor_sink;
   LOG(INFO).NoPrefix().ToSinkOnly(&extractor_sink)
       << std::string(2 * absl::log_internal::kLogMessageBufferSize, 'x');
diff --git a/absl/log/log_streamer.h b/absl/log/log_streamer.h
index 4ed2435..32c3402 100644
--- a/absl/log/log_streamer.h
+++ b/absl/log/log_streamer.h
@@ -24,6 +24,7 @@
 
 #include <ios>
 #include <memory>
+#include <optional>
 #include <ostream>
 #include <string>
 #include <utility>
@@ -131,7 +132,7 @@
   std::string buf_;
   // A disengaged `stream_` indicates a moved-from `LogStreamer` that should not
   // `LOG` upon destruction.
-  absl::optional<absl::strings_internal::OStringStream> stream_;
+  std::optional<absl::strings_internal::OStringStream> stream_;
 };
 
 // LogInfoStreamer()
diff --git a/absl/log/vlog_is_on_test.cc b/absl/log/vlog_is_on_test.cc
index f612283..d523781 100644
--- a/absl/log/vlog_is_on_test.cc
+++ b/absl/log/vlog_is_on_test.cc
@@ -14,6 +14,8 @@
 
 #include "absl/log/vlog_is_on.h"
 
+#include <optional>
+
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 #include "absl/base/log_severity.h"
@@ -22,25 +24,24 @@
 #include "absl/log/globals.h"
 #include "absl/log/log.h"
 #include "absl/log/scoped_mock_log.h"
-#include "absl/types/optional.h"
 
 namespace {
 
 using ::testing::_;
 
-absl::optional<int> MaxLogVerbosity() {
+std::optional<int> MaxLogVerbosity() {
 #ifdef ABSL_MAX_VLOG_VERBOSITY
   return ABSL_MAX_VLOG_VERBOSITY;
 #else
-  return absl::nullopt;
+  return std::nullopt;
 #endif
 }
 
-absl::optional<int> MinLogLevel() {
+std::optional<int> MinLogLevel() {
 #ifdef ABSL_MIN_LOG_LEVEL
   return static_cast<int>(ABSL_MIN_LOG_LEVEL);
 #else
-  return absl::nullopt;
+  return std::nullopt;
 #endif
 }
 
diff --git a/absl/random/CMakeLists.txt b/absl/random/CMakeLists.txt
index e0294a1..7382b0d 100644
--- a/absl/random/CMakeLists.txt
+++ b/absl/random/CMakeLists.txt
@@ -852,7 +852,6 @@
     absl::random_internal_platform
     absl::random_internal_randen_hwaes_impl
     absl::config
-    absl::optional
 )
 
 # Internal-only target, do not depend on directly.
diff --git a/absl/random/internal/BUILD.bazel b/absl/random/internal/BUILD.bazel
index 1a3fef8..d292d34 100644
--- a/absl/random/internal/BUILD.bazel
+++ b/absl/random/internal/BUILD.bazel
@@ -399,7 +399,6 @@
         ":platform",
         ":randen_hwaes_impl",
         "//absl/base:config",
-        "//absl/types:optional",
     ],
 )
 
diff --git a/absl/random/internal/mock_helpers.h b/absl/random/internal/mock_helpers.h
index 85f7387..2d66a3b 100644
--- a/absl/random/internal/mock_helpers.h
+++ b/absl/random/internal/mock_helpers.h
@@ -16,6 +16,7 @@
 #ifndef ABSL_RANDOM_INTERNAL_MOCK_HELPERS_H_
 #define ABSL_RANDOM_INTERNAL_MOCK_HELPERS_H_
 
+#include <optional>
 #include <utility>
 
 #include "absl/base/config.h"
@@ -71,21 +72,21 @@
   // Empty implementation of InvokeMock.
   template <typename KeyT, typename ReturnT, typename ArgTupleT, typename URBG,
             typename... Args>
-  static absl::optional<ReturnT> InvokeMockImpl(char, URBG*, Args&&...) {
-    return absl::nullopt;
+  static std::optional<ReturnT> InvokeMockImpl(char, URBG*, Args&&...) {
+    return std::nullopt;
   }
 
   // Non-empty implementation of InvokeMock.
   template <typename KeyT, typename ReturnT, typename ArgTupleT, typename URBG,
             typename = invoke_mock_t<URBG>, typename... Args>
-  static absl::optional<ReturnT> InvokeMockImpl(int, URBG* urbg,
-                                                Args&&... args) {
+  static std::optional<ReturnT> InvokeMockImpl(int, URBG* urbg,
+                                               Args&&... args) {
     ArgTupleT arg_tuple(std::forward<Args>(args)...);
     ReturnT result;
     if (urbg->InvokeMock(FastTypeId<KeyT>(), &arg_tuple, &result)) {
       return result;
     }
-    return absl::nullopt;
+    return std::nullopt;
   }
 
  public:
@@ -108,7 +109,7 @@
   // the underlying mechanism requires a pointer to an argument tuple.
   template <typename KeyT, typename URBG, typename... Args>
   static auto MaybeInvokeMock(URBG* urbg, Args&&... args)
-      -> absl::optional<typename KeySignature<KeyT>::result_type> {
+      -> std::optional<typename KeySignature<KeyT>::result_type> {
     // Use function overloading to dispatch to the implementation since
     // more modern patterns (e.g. require + constexpr) are not supported in all
     // compiler configurations.
diff --git a/absl/random/internal/randen_detect.cc b/absl/random/internal/randen_detect.cc
index 63e8379..fc8c673 100644
--- a/absl/random/internal/randen_detect.cc
+++ b/absl/random/internal/randen_detect.cc
@@ -31,9 +31,9 @@
 
 #include <cstdint>
 #include <cstring>
+#include <optional>  // IWYU pragma: keep
 
 #include "absl/random/internal/platform.h"
-#include "absl/types/optional.h"  // IWYU pragma: keep
 
 #if !defined(__UCLIBC__) && defined(__GLIBC__) && \
     (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 16))
@@ -115,12 +115,12 @@
 
 #if defined(__APPLE__) && defined(ABSL_ARCH_AARCH64)
 template <typename T>
-static absl::optional<T> ReadSysctlByName(const char* name) {
+static std::optional<T> ReadSysctlByName(const char* name) {
   T val;
   size_t val_size = sizeof(T);
   int ret = sysctlbyname(name, &val, &val_size, nullptr, 0);
   if (ret == -1) {
-    return absl::nullopt;
+    return std::nullopt;
   }
   return val;
 }
@@ -210,7 +210,7 @@
   // Newer XNU kernels support querying all capabilities in a single
   // sysctlbyname.
 #if defined(CAP_BIT_AdvSIMD) && defined(CAP_BIT_FEAT_AES)
-  static const absl::optional<uint64_t> caps =
+  static const std::optional<uint64_t> caps =
       ReadSysctlByName<uint64_t>("hw.optional.arm.caps");
   if (caps.has_value()) {
     constexpr uint64_t kNeonAndAesCaps =
@@ -220,13 +220,13 @@
 #endif
 
   // https://developer.apple.com/documentation/kernel/1387446-sysctlbyname/determining_instruction_set_characteristics#overview
-  static const absl::optional<int> adv_simd =
+  static const std::optional<int> adv_simd =
       ReadSysctlByName<int>("hw.optional.AdvSIMD");
   if (adv_simd.value_or(0) == 0) {
     return false;
   }
   // https://developer.apple.com/documentation/kernel/1387446-sysctlbyname/determining_instruction_set_characteristics#3918855
-  static const absl::optional<int> feat_aes =
+  static const std::optional<int> feat_aes =
       ReadSysctlByName<int>("hw.optional.arm.FEAT_AES");
   if (feat_aes.value_or(0) == 0) {
     return false;
diff --git a/absl/random/internal/salted_seed_seq.h b/absl/random/internal/salted_seed_seq.h
index 0629186..c374d93 100644
--- a/absl/random/internal/salted_seed_seq.h
+++ b/absl/random/internal/salted_seed_seq.h
@@ -20,6 +20,7 @@
 #include <initializer_list>
 #include <iterator>
 #include <memory>
+#include <optional>
 #include <type_traits>
 #include <utility>
 #include <vector>
diff --git a/absl/random/internal/seed_material.cc b/absl/random/internal/seed_material.cc
index b6380c8..f509926 100644
--- a/absl/random/internal/seed_material.cc
+++ b/absl/random/internal/seed_material.cc
@@ -28,6 +28,7 @@
 #include <cstdint>
 #include <cstdlib>
 #include <cstring>
+#include <optional>
 #include <string>
 #include <vector>
 
@@ -38,7 +39,6 @@
 #include "absl/strings/escaping.h"
 #include "absl/strings/string_view.h"
 #include "absl/strings/strip.h"
-#include "absl/types/optional.h"
 #include "absl/types/span.h"
 
 #if defined(_WIN32)
@@ -228,17 +228,17 @@
   }
 }
 
-absl::optional<uint32_t> GetSaltMaterial() {
+std::optional<uint32_t> GetSaltMaterial() {
   // Salt must be common for all generators within the same process so read it
   // only once and store in static variable.
-  static const auto salt_material = []() -> absl::optional<uint32_t> {
+  static const auto salt_material = []() -> std::optional<uint32_t> {
     uint32_t salt_value = 0;
 
     if (ReadSeedMaterialFromOSEntropy(absl::MakeSpan(&salt_value, 1))) {
       return salt_value;
     }
 
-    return absl::nullopt;
+    return std::nullopt;
   }();
 
   return salt_material;
diff --git a/absl/random/internal/seed_material.h b/absl/random/internal/seed_material.h
index b671a8c..23bf4fa 100644
--- a/absl/random/internal/seed_material.h
+++ b/absl/random/internal/seed_material.h
@@ -18,6 +18,7 @@
 #include <cassert>
 #include <cstdint>
 #include <cstdlib>
+#include <optional>
 #include <string>
 #include <vector>
 
@@ -95,7 +96,7 @@
 // Salt is obtained only once and stored in static variable.
 //
 // May return empty value if obtaining the salt was not possible.
-absl::optional<uint32_t> GetSaltMaterial();
+std::optional<uint32_t> GetSaltMaterial();
 
 }  // namespace random_internal
 ABSL_NAMESPACE_END
diff --git a/absl/status/BUILD.bazel b/absl/status/BUILD.bazel
index 394222f..038f1da 100644
--- a/absl/status/BUILD.bazel
+++ b/absl/status/BUILD.bazel
@@ -172,6 +172,7 @@
         ":status",
         ":statusor",
         "//absl/base:config",
+        "//absl/base:core_headers",
         "//absl/strings:string_view",
         "@googletest//:gtest",
     ],
diff --git a/absl/status/CMakeLists.txt b/absl/status/CMakeLists.txt
index d0d134c..a418bd9 100644
--- a/absl/status/CMakeLists.txt
+++ b/absl/status/CMakeLists.txt
@@ -119,6 +119,7 @@
     ${ABSL_DEFAULT_LINKOPTS}
   DEPS
     absl::base
+    absl::core_headers
     absl::status
     absl::statusor
     absl::strings
diff --git a/absl/status/internal/status_internal.cc b/absl/status/internal/status_internal.cc
index 9884189..74bece4 100644
--- a/absl/status/internal/status_internal.cc
+++ b/absl/status/internal/status_internal.cc
@@ -21,6 +21,7 @@
 #include <cstdio>
 #include <cstring>
 #include <memory>
+#include <optional>
 #include <string>
 #include <utility>
 
@@ -40,7 +41,6 @@
 #include "absl/strings/str_format.h"
 #include "absl/strings/str_split.h"
 #include "absl/strings/string_view.h"
-#include "absl/types/optional.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
@@ -56,24 +56,24 @@
   }
 }
 
-static absl::optional<size_t> FindPayloadIndexByUrl(
-    const Payloads* payloads, absl::string_view type_url) {
-  if (payloads == nullptr) return absl::nullopt;
+static std::optional<size_t> FindPayloadIndexByUrl(const Payloads* payloads,
+                                                   absl::string_view type_url) {
+  if (payloads == nullptr) return std::nullopt;
 
   for (size_t i = 0; i < payloads->size(); ++i) {
     if ((*payloads)[i].type_url == type_url) return i;
   }
 
-  return absl::nullopt;
+  return std::nullopt;
 }
 
-absl::optional<absl::Cord> StatusRep::GetPayload(
+std::optional<absl::Cord> StatusRep::GetPayload(
     absl::string_view type_url) const {
-  absl::optional<size_t> index =
+  std::optional<size_t> index =
       status_internal::FindPayloadIndexByUrl(payloads_.get(), type_url);
   if (index.has_value()) return (*payloads_)[index.value()].payload;
 
-  return absl::nullopt;
+  return std::nullopt;
 }
 
 void StatusRep::SetPayload(absl::string_view type_url, absl::Cord payload) {
@@ -81,7 +81,7 @@
     payloads_ = absl::make_unique<status_internal::Payloads>();
   }
 
-  absl::optional<size_t> index =
+  std::optional<size_t> index =
       status_internal::FindPayloadIndexByUrl(payloads_.get(), type_url);
   if (index.has_value()) {
     (*payloads_)[index.value()].payload = std::move(payload);
@@ -92,7 +92,7 @@
 }
 
 StatusRep::EraseResult StatusRep::ErasePayload(absl::string_view type_url) {
-  absl::optional<size_t> index =
+  std::optional<size_t> index =
       status_internal::FindPayloadIndexByUrl(payloads_.get(), type_url);
   if (!index.has_value()) return {false, Status::PointerToRep(this)};
   payloads_->erase(payloads_->begin() + index.value());
@@ -142,7 +142,7 @@
         status_internal::GetStatusPayloadPrinter();
     this->ForEachPayload([&](absl::string_view type_url,
                              const absl::Cord& payload) {
-      absl::optional<std::string> result;
+      std::optional<std::string> result;
       if (printer) result = printer(type_url, payload);
       absl::StrAppend(
           &text, " [", type_url, "='",
diff --git a/absl/status/internal/status_internal.h b/absl/status/internal/status_internal.h
index 35a9f9b..f2bd83a 100644
--- a/absl/status/internal/status_internal.h
+++ b/absl/status/internal/status_internal.h
@@ -20,6 +20,8 @@
 #include <string>
 #include <utility>
 
+#include <optional>
+
 #include "absl/base/attributes.h"
 #include "absl/base/config.h"
 #include "absl/base/nullability.h"
@@ -83,7 +85,7 @@
   void Unref() const;
 
   // Payload methods correspond to the same methods in absl::Status.
-  absl::optional<absl::Cord> GetPayload(absl::string_view type_url) const;
+  std::optional<absl::Cord> GetPayload(absl::string_view type_url) const;
   void SetPayload(absl::string_view type_url, absl::Cord payload);
   struct EraseResult {
     bool erased;
diff --git a/absl/status/internal/status_matchers.h b/absl/status/internal/status_matchers.h
index d11742b..eb61d73 100644
--- a/absl/status/internal/status_matchers.h
+++ b/absl/status/internal/status_matchers.h
@@ -16,12 +16,12 @@
 #define ABSL_STATUS_INTERNAL_STATUS_MATCHERS_H_
 
 #include <ostream>  // NOLINT
-#include <string>
 #include <type_traits>
 #include <utility>
 
 #include "gmock/gmock.h"  // gmock_for_status_matchers.h
 #include "absl/base/config.h"
+#include "absl/base/macros.h"
 #include "absl/status/status.h"
 #include "absl/status/statusor.h"
 #include "absl/strings/string_view.h"
@@ -30,12 +30,20 @@
 ABSL_NAMESPACE_BEGIN
 namespace status_internal {
 
-inline const absl::Status& GetStatus(const absl::Status& status) {
+// TODO(b/323927127): Remove ABSL_REFACTOR_INLINE once callers are cleaned up
+// and move it into a namespace like adl_barrier without types to avoid
+// accidental ADL.
+ABSL_REFACTOR_INLINE inline const absl::Status& GetStatus(
+    const absl::Status& status) {
   return status;
 }
 
+// TODO(b/323927127): Remove ABSL_REFACTOR_INLINE once callers are cleaned up
+// and move it into a namespace like adl_barrier without types to avoid
+// accidental ADL.
 template <typename T>
-inline const absl::Status& GetStatus(const absl::StatusOr<T>& status) {
+ABSL_REFACTOR_INLINE const absl::Status& GetStatus(
+    const absl::StatusOr<T>& status) {
   return status.status();
 }
 
diff --git a/absl/status/status.cc b/absl/status/status.cc
index f219933..479c39f 100644
--- a/absl/status/status.cc
+++ b/absl/status/status.cc
@@ -37,7 +37,6 @@
 #include "absl/strings/str_format.h"
 #include "absl/strings/str_split.h"
 #include "absl/strings/string_view.h"
-#include "absl/types/optional.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
diff --git a/absl/status/status.h b/absl/status/status.h
index b26d072..f81f912 100644
--- a/absl/status/status.h
+++ b/absl/status/status.h
@@ -53,6 +53,7 @@
 
 #include <cassert>
 #include <cstdint>
+#include <optional>
 #include <ostream>
 #include <string>
 #include <utility>
@@ -583,7 +584,7 @@
   // Status::GetPayload()
   //
   // Gets the payload of a status given its unique `type_url` key, if present.
-  absl::optional<absl::Cord> GetPayload(absl::string_view type_url) const;
+  std::optional<absl::Cord> GetPayload(absl::string_view type_url) const;
 
   // Status::SetPayload()
   //
@@ -862,9 +863,9 @@
   swap(a.rep_, b.rep_);
 }
 
-inline absl::optional<absl::Cord> Status::GetPayload(
+inline std::optional<absl::Cord> Status::GetPayload(
     absl::string_view type_url) const {
-  if (IsInlined(rep_)) return absl::nullopt;
+  if (IsInlined(rep_)) return std::nullopt;
   return RepToPointer(rep_)->GetPayload(type_url);
 }
 
diff --git a/absl/status/status_matchers.h b/absl/status/status_matchers.h
index 03e5f49..c418739 100644
--- a/absl/status/status_matchers.h
+++ b/absl/status/status_matchers.h
@@ -129,7 +129,8 @@
 // code matches code_matcher.  See above for details.
 template <typename StatusCodeMatcherT>
 status_internal::StatusIsMatcher StatusIs(StatusCodeMatcherT&& code_matcher) {
-  return StatusIs(std::forward<StatusCodeMatcherT>(code_matcher), ::testing::_);
+  return absl_testing::StatusIs(std::forward<StatusCodeMatcherT>(code_matcher),
+                                ::testing::_);
 }
 
 // Returns a gMock matcher that matches a Status or StatusOr<> which is OK.
diff --git a/absl/status/status_payload_printer.h b/absl/status/status_payload_printer.h
index fc55515..7e2c8c8 100644
--- a/absl/status/status_payload_printer.h
+++ b/absl/status/status_payload_printer.h
@@ -14,6 +14,7 @@
 #ifndef ABSL_STATUS_STATUS_PAYLOAD_PRINTER_H_
 #define ABSL_STATUS_STATUS_PAYLOAD_PRINTER_H_
 
+#include <optional>
 #include <string>
 
 #include "absl/base/nullability.h"
@@ -30,12 +31,12 @@
 // extension point, which is a global printer function that can be set by users
 // to specify how to print payloads. The function takes the type URL and the
 // payload as input, and should return a valid human-readable string on success
-// or `absl::nullopt` on failure (in which case it falls back to the default
+// or `std::nullopt` on failure (in which case it falls back to the default
 // approach of printing the raw bytes).
 // NOTE: This is an internal API and the design is subject to change in the
 // future in a non-backward-compatible way. Since it's only meant for debugging
 // purpose, you should not rely on it in any critical logic.
-using StatusPayloadPrinter = absl::optional<std::string> (*absl_nullable)(
+using StatusPayloadPrinter = std::optional<std::string> (*absl_nullable)(
     absl::string_view, const absl::Cord&);
 
 // Sets the global payload printer. Only one printer should be set per process.
diff --git a/absl/status/statusor.h b/absl/status/statusor.h
index 52294ee..2427d24 100644
--- a/absl/status/statusor.h
+++ b/absl/status/statusor.h
@@ -43,6 +43,7 @@
 #include <string>
 #include <type_traits>
 #include <utility>
+#include <variant>
 
 #include "absl/base/attributes.h"
 #include "absl/base/call_once.h"
diff --git a/absl/status/statusor_test.cc b/absl/status/statusor_test.cc
index 26d4235..82cb930 100644
--- a/absl/status/statusor_test.cc
+++ b/absl/status/statusor_test.cc
@@ -14,6 +14,7 @@
 
 #include "absl/status/statusor.h"
 
+#include <any>
 #include <array>
 #include <cstddef>
 #include <cstdint>
@@ -25,6 +26,7 @@
 #include <string>
 #include <type_traits>
 #include <utility>
+#include <variant>
 #include <vector>
 
 #include "gmock/gmock.h"
@@ -35,8 +37,6 @@
 #include "absl/status/status_matchers.h"
 #include "absl/strings/str_cat.h"
 #include "absl/strings/string_view.h"
-#include "absl/types/any.h"
-#include "absl/types/variant.h"
 #include "absl/utility/utility.h"
 
 namespace {
@@ -696,13 +696,13 @@
 TEST(StatusOr, ImplicitConstruction) {
   // Check implicit casting works.
   auto status_or =
-      absl::implicit_cast<absl::StatusOr<absl::variant<int, std::string>>>(10);
+      absl::implicit_cast<absl::StatusOr<std::variant<int, std::string>>>(10);
   EXPECT_THAT(status_or, IsOkAndHolds(VariantWith<int>(10)));
 }
 
 TEST(StatusOr, ImplicitConstructionFromInitliazerList) {
   // Note: dropping the explicit std::initializer_list<int> is not supported
-  // by absl::StatusOr or absl::optional.
+  // by absl::StatusOr or std::optional.
   auto status_or =
       absl::implicit_cast<absl::StatusOr<std::vector<int>>>({{10, 20, 30}});
   EXPECT_THAT(status_or, IsOkAndHolds(ElementsAre(10, 20, 30)));
@@ -796,49 +796,49 @@
 }
 
 TEST(StatusOr, StatusOrAnyCopyAndMoveConstructorTests) {
-  absl::StatusOr<absl::any> status_or = CopyDetector(10);
-  absl::StatusOr<absl::any> status_error = absl::InvalidArgumentError("foo");
+  absl::StatusOr<std::any> status_or = CopyDetector(10);
+  absl::StatusOr<std::any> status_error = absl::InvalidArgumentError("foo");
   EXPECT_THAT(
       status_or,
       IsOkAndHolds(AnyWith<CopyDetector>(CopyDetectorHas(10, true, false))));
-  absl::StatusOr<absl::any> a = status_or;
+  absl::StatusOr<std::any> a = status_or;
   EXPECT_THAT(
       a, IsOkAndHolds(AnyWith<CopyDetector>(CopyDetectorHas(10, false, true))));
-  absl::StatusOr<absl::any> a_err = status_error;
+  absl::StatusOr<std::any> a_err = status_error;
   EXPECT_THAT(a_err, Not(IsOk()));
 
-  const absl::StatusOr<absl::any>& cref = status_or;
+  const absl::StatusOr<std::any>& cref = status_or;
   // No lint for no-change copy.
-  absl::StatusOr<absl::any> b = cref;  // NOLINT
+  absl::StatusOr<std::any> b = cref;  // NOLINT
   EXPECT_THAT(
       b, IsOkAndHolds(AnyWith<CopyDetector>(CopyDetectorHas(10, false, true))));
-  const absl::StatusOr<absl::any>& cref_err = status_error;
+  const absl::StatusOr<std::any>& cref_err = status_error;
   // No lint for no-change copy.
-  absl::StatusOr<absl::any> b_err = cref_err;  // NOLINT
+  absl::StatusOr<std::any> b_err = cref_err;  // NOLINT
   EXPECT_THAT(b_err, Not(IsOk()));
 
-  absl::StatusOr<absl::any> c = std::move(status_or);
+  absl::StatusOr<std::any> c = std::move(status_or);
   EXPECT_THAT(
       c, IsOkAndHolds(AnyWith<CopyDetector>(CopyDetectorHas(10, true, false))));
-  absl::StatusOr<absl::any> c_err = std::move(status_error);
+  absl::StatusOr<std::any> c_err = std::move(status_error);
   EXPECT_THAT(c_err, Not(IsOk()));
 }
 
 TEST(StatusOr, StatusOrAnyCopyAndMoveAssignment) {
-  absl::StatusOr<absl::any> status_or = CopyDetector(10);
-  absl::StatusOr<absl::any> status_error = absl::InvalidArgumentError("foo");
-  absl::StatusOr<absl::any> a;
+  absl::StatusOr<std::any> status_or = CopyDetector(10);
+  absl::StatusOr<std::any> status_error = absl::InvalidArgumentError("foo");
+  absl::StatusOr<std::any> a;
   a = status_or;
   EXPECT_THAT(
       a, IsOkAndHolds(AnyWith<CopyDetector>(CopyDetectorHas(10, false, true))));
   a = status_error;
   EXPECT_THAT(a, Not(IsOk()));
 
-  const absl::StatusOr<absl::any>& cref = status_or;
+  const absl::StatusOr<std::any>& cref = status_or;
   a = cref;
   EXPECT_THAT(
       a, IsOkAndHolds(AnyWith<CopyDetector>(CopyDetectorHas(10, false, true))));
-  const absl::StatusOr<absl::any>& cref_err = status_error;
+  const absl::StatusOr<std::any>& cref_err = status_error;
   a = cref_err;
   EXPECT_THAT(a, Not(IsOk()));
   a = std::move(status_or);
@@ -876,15 +876,15 @@
 }
 
 TEST(StatusOr, AbslAnyAssignment) {
-  EXPECT_FALSE((std::is_assignable<absl::StatusOr<absl::any>,
+  EXPECT_FALSE((std::is_assignable<absl::StatusOr<std::any>,
                                    absl::StatusOr<int>>::value));
-  absl::StatusOr<absl::any> status_or;
+  absl::StatusOr<std::any> status_or;
   status_or = absl::InvalidArgumentError("foo");
   EXPECT_THAT(status_or, Not(IsOk()));
 }
 
 TEST(StatusOr, ImplicitAssignment) {
-  absl::StatusOr<absl::variant<int, std::string>> status_or;
+  absl::StatusOr<std::variant<int, std::string>> status_or;
   status_or = 10;
   EXPECT_THAT(status_or, IsOkAndHolds(VariantWith<int>(10)));
 }
diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel
index a1e5021..64e207b 100644
--- a/absl/strings/BUILD.bazel
+++ b/absl/strings/BUILD.bazel
@@ -254,7 +254,6 @@
     visibility = ["//visibility:private"],
     deps = [
         ":strings",
-        "//absl/types:optional",
         "@googletest//:gtest",
         "@googletest//:gtest_main",
     ],
@@ -278,7 +277,6 @@
     visibility = ["//visibility:private"],
     deps = [
         ":has_ostream_operator",
-        "//absl/types:optional",
         "@googletest//:gtest",
         "@googletest//:gtest_main",
     ],
@@ -978,7 +976,6 @@
         "//absl/log:check",
         "//absl/random",
         "//absl/types:compare",
-        "//absl/types:optional",
         "@googletest//:gtest",
         "@googletest//:gtest_main",
     ],
@@ -1371,7 +1368,6 @@
         "//absl/numeric:bits",
         "//absl/numeric:int128",
         "//absl/numeric:representation",
-        "//absl/types:optional",
         "//absl/types:span",
         "//absl/utility",
     ],
@@ -1465,7 +1461,6 @@
         "//absl/base:raw_logging_internal",
         "//absl/log",
         "//absl/numeric:int128",
-        "//absl/types:optional",
         "//absl/types:span",
         "@googletest//:gtest",
         "@googletest//:gtest_main",
@@ -1535,7 +1530,6 @@
         ":str_format",
         ":strings",
         "//absl/base",
-        "//absl/types:optional",
     ],
 )
 
diff --git a/absl/strings/CMakeLists.txt b/absl/strings/CMakeLists.txt
index a03943d..0e0adfa 100644
--- a/absl/strings/CMakeLists.txt
+++ b/absl/strings/CMakeLists.txt
@@ -231,7 +231,6 @@
   COPTS
     ${ABSL_TEST_COPTS}
   DEPS
-    absl::optional
     absl::strings
     GTest::gmock_main
 )
@@ -245,7 +244,6 @@
     ${ABSL_TEST_COPTS}
   DEPS
     absl::has_ostream_operator
-    absl::optional
     GTest::gmock_main
 )
 
@@ -1138,7 +1136,6 @@
     absl::hash_testing
     absl::no_destructor
     absl::log
-    absl::optional
     absl::random_random
     absl::str_format
     absl::strings
diff --git a/absl/strings/atod_manual_test.cc b/absl/strings/atod_manual_test.cc
index 6cf28b0..b22657a 100644
--- a/absl/strings/atod_manual_test.cc
+++ b/absl/strings/atod_manual_test.cc
@@ -39,13 +39,13 @@
 
 #include <cstdint>
 #include <cstdio>
+#include <optional>
 #include <string>
 
 #include "absl/base/casts.h"
 #include "absl/strings/numbers.h"
 #include "absl/strings/str_format.h"
 #include "absl/strings/string_view.h"
-#include "absl/types/optional.h"
 
 static constexpr uint8_t kUnhex[256] = {
     0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,  //
@@ -85,10 +85,10 @@
     0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,  //
 };
 
-static absl::optional<std::string> ReadFileToString(const char* filename) {
+static std::optional<std::string> ReadFileToString(const char* filename) {
   FILE* f = fopen(filename, "rb");
   if (!f) {
-    return absl::nullopt;
+    return std::nullopt;
   }
   fseek(f, 0, SEEK_END);
   size_t size = ftell(f);
@@ -97,13 +97,13 @@
   size_t n = fread(&s[0], 1, size, f);
   fclose(f);
   if (n != size) {
-    return absl::nullopt;
+    return std::nullopt;
   }
   return s;
 }
 
 static bool ProcessOneTestFile(const char* filename) {
-  absl::optional<std::string> contents = ReadFileToString(filename);
+  std::optional<std::string> contents = ReadFileToString(filename);
   if (!contents) {
     absl::FPrintF(stderr, "Invalid file: %s\n", filename);
     return false;
diff --git a/absl/strings/cord.cc b/absl/strings/cord.cc
index d3014f3..aa450d3 100644
--- a/absl/strings/cord.cc
+++ b/absl/strings/cord.cc
@@ -26,6 +26,7 @@
 #include <iostream>
 #include <limits>
 #include <memory>
+#include <optional>
 #include <ostream>
 #include <sstream>
 #include <string>
@@ -36,8 +37,8 @@
 #include "absl/base/internal/endian.h"
 #include "absl/base/internal/raw_logging.h"
 #include "absl/base/macros.h"
-#include "absl/base/optimization.h"
 #include "absl/base/nullability.h"
+#include "absl/base/optimization.h"
 #include "absl/container/inlined_vector.h"
 #include "absl/crc/crc32c.h"
 #include "absl/crc/internal/crc_cord_state.h"
@@ -56,7 +57,6 @@
 #include "absl/strings/str_cat.h"
 #include "absl/strings/string_view.h"
 #include "absl/strings/strip.h"
-#include "absl/types/optional.h"
 #include "absl/types/span.h"
 
 namespace absl {
@@ -886,9 +886,9 @@
   return &contents_.tree()->crc()->crc_cord_state;
 }
 
-absl::optional<uint32_t> Cord::ExpectedChecksum() const {
+std::optional<uint32_t> Cord::ExpectedChecksum() const {
   if (!contents_.is_tree() || !contents_.tree()->IsCrc()) {
-    return absl::nullopt;
+    return std::nullopt;
   }
   return static_cast<uint32_t>(
       contents_.tree()->crc()->crc_cord_state.Checksum());
diff --git a/absl/strings/cord.h b/absl/strings/cord.h
index fa6eb8a..3278296 100644
--- a/absl/strings/cord.h
+++ b/absl/strings/cord.h
@@ -67,6 +67,7 @@
 #include <cstring>
 #include <iosfwd>
 #include <iterator>
+#include <optional>
 #include <string>
 #include <type_traits>
 #include <utility>
@@ -222,7 +223,7 @@
   // remain live until the releaser is invoked. The callable releaser also must:
   //
   //   * be move constructible
-  //   * support `void operator()(absl::string_view) const` or `void operator()`
+  //   * support `void operator()(absl::string_view)` or `void operator()()`
   //
   // Example:
   //
@@ -763,7 +764,7 @@
   //
   // If this cord's representation is a single flat array, returns a
   // string_view referencing that array.  Otherwise returns nullopt.
-  absl::optional<absl::string_view> TryFlat() const
+  std::optional<absl::string_view> TryFlat() const
       ABSL_ATTRIBUTE_LIFETIME_BOUND;
 
   // Cord::Flatten()
@@ -816,11 +817,11 @@
 
   // Returns this cord's expected checksum, if it has one.  Otherwise, returns
   // nullopt.
-  absl::optional<uint32_t> ExpectedChecksum() const;
+  std::optional<uint32_t> ExpectedChecksum() const;
 
   template <typename H>
   friend H AbslHashValue(H hash_state, const absl::Cord& c) {
-    absl::optional<absl::string_view> maybe_flat = c.TryFlat();
+    std::optional<absl::string_view> maybe_flat = c.TryFlat();
     if (maybe_flat.has_value()) {
       return H::combine(std::move(hash_state), *maybe_flat);
     }
@@ -1396,7 +1397,7 @@
   return result;
 }
 
-inline absl::optional<absl::string_view> Cord::TryFlat() const
+inline std::optional<absl::string_view> Cord::TryFlat() const
     ABSL_ATTRIBUTE_LIFETIME_BOUND {
   absl::cord_internal::CordRep* rep = contents_.tree();
   if (rep == nullptr) {
@@ -1406,7 +1407,7 @@
   if (GetFlatAux(rep, &fragment)) {
     return fragment;
   }
-  return absl::nullopt;
+  return std::nullopt;
 }
 
 inline absl::string_view Cord::Flatten() ABSL_ATTRIBUTE_LIFETIME_BOUND {
diff --git a/absl/strings/cord_test.cc b/absl/strings/cord_test.cc
index 55007bb..0be2aa4 100644
--- a/absl/strings/cord_test.cc
+++ b/absl/strings/cord_test.cc
@@ -24,6 +24,7 @@
 #include <iostream>
 #include <iterator>
 #include <limits>
+#include <optional>
 #include <random>
 #include <set>
 #include <sstream>
@@ -61,7 +62,6 @@
 #include "absl/strings/str_format.h"
 #include "absl/strings/string_view.h"
 #include "absl/types/compare.h"
-#include "absl/types/optional.h"
 
 // convenience local constants
 static constexpr auto FLAT = absl::cord_internal::FLAT;
@@ -416,7 +416,7 @@
   absl::Cord x(absl::string_view("hi there"));
   absl::Cord y(x);
   MaybeHarden(y);
-  ASSERT_EQ(x.ExpectedChecksum(), absl::nullopt);
+  ASSERT_EQ(x.ExpectedChecksum(), std::nullopt);
   ASSERT_EQ(std::string(x), "hi there");
   ASSERT_EQ(std::string(y), "hi there");
   ASSERT_TRUE(x == y);
@@ -618,7 +618,7 @@
                 std::string(sa))
           << a;
       if (pos != 0 || end_pos != a.size()) {
-        ASSERT_EQ(sa.ExpectedChecksum(), absl::nullopt);
+        ASSERT_EQ(sa.ExpectedChecksum(), std::nullopt);
       }
     }
   }
@@ -662,7 +662,7 @@
   MaybeHarden(x);
   swap(x, y);
   if (UseCrc()) {
-    ASSERT_EQ(x.ExpectedChecksum(), absl::nullopt);
+    ASSERT_EQ(x.ExpectedChecksum(), std::nullopt);
     ASSERT_EQ(y.ExpectedChecksum(), 1);
   }
   ASSERT_EQ(x, absl::Cord(b));
@@ -670,7 +670,7 @@
   x.swap(y);
   if (UseCrc()) {
     ASSERT_EQ(x.ExpectedChecksum(), 1);
-    ASSERT_EQ(y.ExpectedChecksum(), absl::nullopt);
+    ASSERT_EQ(y.ExpectedChecksum(), std::nullopt);
   }
   ASSERT_EQ(x, absl::Cord(a));
   ASSERT_EQ(y, absl::Cord(b));
@@ -1072,7 +1072,7 @@
 TEST_P(CordTest, TryFlatConcat) {
   absl::Cord c = absl::MakeFragmentedCord({"hel", "lo"});
   MaybeHarden(c);
-  EXPECT_EQ(c.TryFlat(), absl::nullopt);
+  EXPECT_EQ(c.TryFlat(), std::nullopt);
 }
 
 TEST_P(CordTest, TryFlatExternal) {
@@ -1766,6 +1766,34 @@
   EXPECT_TRUE(invoked);
 }
 
+TEST_P(CordTest, ConstructFromExternalNonConstReleaser) {
+  struct Releaser {
+    explicit Releaser(bool* invoked) : invoked(invoked) {}
+    // Non const method.
+    void operator()(absl::string_view) { *invoked = true; }
+
+    bool* invoked;
+  };
+
+  bool invoked = false;
+  (void)MaybeHardened(absl::MakeCordFromExternal("dummy", Releaser(&invoked)));
+  EXPECT_TRUE(invoked);
+}
+
+TEST_P(CordTest, ConstructFromExternalNonConstNoArgReleaser) {
+  struct Releaser {
+    explicit Releaser(bool* invoked) : invoked(invoked) {}
+    // Non const method.
+    void operator()() { *invoked = true; }
+
+    bool* invoked;
+  };
+
+  bool invoked = false;
+  (void)MaybeHardened(absl::MakeCordFromExternal("dummy", Releaser(&invoked)));
+  EXPECT_TRUE(invoked);
+}
+
 TEST_P(CordTest, ConstructFromExternalNoArgLambda) {
   bool invoked = false;
   (void)MaybeHardened(
@@ -3138,13 +3166,13 @@
           continue;
         }
 
-        EXPECT_EQ(c2.ExpectedChecksum(), absl::nullopt);
+        EXPECT_EQ(c2.ExpectedChecksum(), std::nullopt);
 
         if (mutator.CanUndo()) {
           // Undoing an operation should not restore the checksum
           mutator.Undo(c2);
           EXPECT_EQ(c2, base_value);
-          EXPECT_EQ(c2.ExpectedChecksum(), absl::nullopt);
+          EXPECT_EQ(c2.ExpectedChecksum(), std::nullopt);
         }
       }
 
@@ -3254,7 +3282,7 @@
       // Not a mutation
       continue;
     }
-    EXPECT_EQ(c2.ExpectedChecksum(), absl::nullopt);
+    EXPECT_EQ(c2.ExpectedChecksum(), std::nullopt);
 
     if (mutator.CanUndo()) {
       mutator.Undo(c2);
diff --git a/absl/strings/has_absl_stringify_test.cc b/absl/strings/has_absl_stringify_test.cc
index 59e7e1d..1aee904 100644
--- a/absl/strings/has_absl_stringify_test.cc
+++ b/absl/strings/has_absl_stringify_test.cc
@@ -14,10 +14,10 @@
 
 #include "absl/strings/has_absl_stringify.h"
 
+#include <optional>
 #include <string>
 
 #include "gtest/gtest.h"
-#include "absl/types/optional.h"
 
 namespace {
 
@@ -34,7 +34,7 @@
   EXPECT_FALSE(absl::HasAbslStringify<TypeWithoutAbslStringify>::value);
   EXPECT_TRUE(absl::HasAbslStringify<TypeWithAbslStringify>::value);
   EXPECT_FALSE(
-      absl::HasAbslStringify<absl::optional<TypeWithAbslStringify>>::value);
+      absl::HasAbslStringify<std::optional<TypeWithAbslStringify>>::value);
 }
 
 }  // namespace
diff --git a/absl/strings/has_ostream_operator_test.cc b/absl/strings/has_ostream_operator_test.cc
index 9ef4136..720ebd5 100644
--- a/absl/strings/has_ostream_operator_test.cc
+++ b/absl/strings/has_ostream_operator_test.cc
@@ -14,11 +14,11 @@
 
 #include "absl/strings/has_ostream_operator.h"
 
+#include <optional>
 #include <ostream>
 #include <string>
 
 #include "gtest/gtest.h"
-#include "absl/types/optional.h"
 
 namespace {
 
@@ -33,7 +33,7 @@
 TEST(HasOstreamOperatorTest, Works) {
   EXPECT_TRUE(absl::HasOstreamOperator<int>::value);
   EXPECT_TRUE(absl::HasOstreamOperator<std::string>::value);
-  EXPECT_FALSE(absl::HasOstreamOperator<absl::optional<int>>::value);
+  EXPECT_FALSE(absl::HasOstreamOperator<std::optional<int>>::value);
   EXPECT_FALSE(absl::HasOstreamOperator<TypeWithoutOstreamOp>::value);
   EXPECT_TRUE(absl::HasOstreamOperator<TypeWithOstreamOp>::value);
 }
diff --git a/absl/strings/internal/str_format/convert_test.cc b/absl/strings/internal/str_format/convert_test.cc
index f340df4..fb9b5ba 100644
--- a/absl/strings/internal/str_format/convert_test.cc
+++ b/absl/strings/internal/str_format/convert_test.cc
@@ -24,6 +24,7 @@
 #include <cstring>
 #include <cwctype>
 #include <limits>
+#include <optional>
 #include <set>
 #include <sstream>
 #include <string>
@@ -44,7 +45,6 @@
 #include "absl/strings/match.h"
 #include "absl/strings/str_format.h"
 #include "absl/strings/string_view.h"
-#include "absl/types/optional.h"
 #include "absl/types/span.h"
 
 namespace absl {
@@ -593,11 +593,11 @@
 }
 
 template <typename T>
-absl::optional<std::string> StrPrintChar(T c) {
+std::optional<std::string> StrPrintChar(T c) {
   return StrPrint("%c", static_cast<int>(c));
 }
 template <>
-absl::optional<std::string> StrPrintChar(wchar_t c) {
+std::optional<std::string> StrPrintChar(wchar_t c) {
   // musl libc has a bug where ("%lc", 0) writes no characters, and Android
   // doesn't support forcing UTF-8 via setlocale(). Hardcode the expected
   // answers for ASCII inputs to maximize test coverage on these platforms.
@@ -611,7 +611,7 @@
   // call.
   std::string old_locale = setlocale(LC_CTYPE, nullptr);
   if (!setlocale(LC_CTYPE, "en_US.UTF-8")) {
-    return absl::nullopt;
+    return std::nullopt;
   }
   const std::string output = StrPrint("%lc", static_cast<wint_t>(c));
   setlocale(LC_CTYPE, old_locale.c_str());
@@ -666,7 +666,7 @@
     SCOPED_TRACE(Esc(c));
     const FormatArgImpl args[] = {FormatArgImpl(c)};
     UntypedFormatSpecImpl format("%c");
-    absl::optional<std::string> result = StrPrintChar(c);
+    std::optional<std::string> result = StrPrintChar(c);
     if (result.has_value()) {
       EXPECT_EQ(result.value(), FormatPack(format, absl::MakeSpan(args)));
     }
diff --git a/absl/strings/internal/str_format/float_conversion.cc b/absl/strings/internal/str_format/float_conversion.cc
index bcef275..89275d4 100644
--- a/absl/strings/internal/str_format/float_conversion.cc
+++ b/absl/strings/internal/str_format/float_conversion.cc
@@ -37,7 +37,6 @@
 #include "absl/strings/internal/str_format/extension.h"
 #include "absl/strings/numbers.h"
 #include "absl/strings/string_view.h"
-#include "absl/types/optional.h"
 #include "absl/types/span.h"
 
 namespace absl {
diff --git a/absl/time/clock_interface.h b/absl/time/clock_interface.h
index 25ccf6e..a14d852 100644
--- a/absl/time/clock_interface.h
+++ b/absl/time/clock_interface.h
@@ -36,6 +36,8 @@
 // Clocks into interfaces rather than having implementations call absl::Now()
 // directly.
 //
+// Implementations of this interface must be thread-safe.
+//
 // The Clock::GetRealClock() function returns a reference to the global realtime
 // clock.
 //
diff --git a/absl/types/BUILD.bazel b/absl/types/BUILD.bazel
index cac5e4b..a52c358 100644
--- a/absl/types/BUILD.bazel
+++ b/absl/types/BUILD.bazel
@@ -164,3 +164,29 @@
         "@googletest//:gtest_main",
     ],
 )
+
+cc_library(
+    name = "optional_ref",
+    hdrs = ["optional_ref.h"],
+    copts = ABSL_DEFAULT_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    deps = [
+        "//absl/base:config",
+        "//absl/base:core_headers",
+    ],
+)
+
+cc_test(
+    name = "optional_ref_test",
+    size = "small",
+    srcs = ["optional_ref_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    deps = [
+        ":optional_ref",
+        "//absl/base:config",
+        "//absl/log",
+        "//absl/strings",
+        "@googletest//:gtest",
+        "@googletest//:gtest_main",
+    ],
+)
diff --git a/absl/types/CMakeLists.txt b/absl/types/CMakeLists.txt
index 20a7e90..75dd07d 100644
--- a/absl/types/CMakeLists.txt
+++ b/absl/types/CMakeLists.txt
@@ -154,6 +154,34 @@
     GTest::gmock_main
 )
 
+absl_cc_library(
+  NAME
+    internal_optional_ref
+  HDRS
+    "optional_ref.h"
+  COPTS
+    ${ABSL_DEFAULT_COPTS}
+  DEPS
+    absl::config
+    absl::core_headers
+  PUBLIC
+)
+
+absl_cc_test(
+  NAME
+    optional_ref_test
+  SRCS
+    "optional_ref_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  DEPS
+    absl::base
+    absl::config
+    absl::internal_optional_ref
+    absl::strings
+    GTest::gmock_main
+)
+
 # Deprecated empty library.
 # Clients should remove this dependency.
 absl_cc_library(
diff --git a/absl/types/optional_ref.h b/absl/types/optional_ref.h
new file mode 100644
index 0000000..fb21333
--- /dev/null
+++ b/absl/types/optional_ref.h
@@ -0,0 +1,294 @@
+// Copyright 2026 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: optional_ref.h
+// -----------------------------------------------------------------------------
+//
+// `optional_ref<T>` provides a `std::optional`-like interface around `T*`.
+// It is similar to C++26's `std::optional<T&>`, but with slight enhancements,
+// such as the fact that it permits construction from rvalues. That is, it
+// relaxes the std::reference_constructs_from_temporary constraint. Its intent
+// is to make it easier for functions to accept nullable object addresses,
+// regardless of whether or not they point to temporaries.
+//
+// It can be constructed in the following ways:
+//   * optional_ref<T> ref;
+//   * optional_ref<T> ref = std::nullopt;
+//   * T foo; optional_ref<T> ref = foo;
+//   * std::optional<T> foo; optional_ref<T> ref = foo;
+//   * T* foo = ...; optional_ref<T> ref = foo;
+//   * optional_ref<T> foo; optional_ref<const T> ref = foo;
+//
+// Since it is trivially copyable and destructible, it should be passed by
+// value.
+//
+// Other properties:
+//   * Assignment is not allowed. Example:
+//       optional_ref<int> ref;
+//       // Compile error.
+//       ref = 2;
+//
+//   * operator bool() is intentionally not defined, as it would be error prone
+//     for optional_ref<bool>.
+//
+// Example usage, assuming some type `T` that is expensive to copy:
+//   void ProcessT(optional_ref<const T> input) {
+//     if (!input.has_value()) {
+//       // Handle empty case.
+//       return;
+//     }
+//     const T& val = *input;
+//     // Do something with val.
+//   }
+//
+//   ProcessT(std::nullopt);
+//   ProcessT(BuildT());
+
+#ifndef ABSL_TYPES_OPTIONAL_REF_H_
+#define ABSL_TYPES_OPTIONAL_REF_H_
+
+#include <cstddef>
+#include <memory>
+#include <optional>
+#include <type_traits>
+#include <utility>
+
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+#include "absl/base/macros.h"
+#include "absl/base/optimization.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+template <typename T>
+class optional_ref {
+  template <typename U>
+  using EnableIfConvertibleFrom =
+      std::enable_if_t<std::is_convertible_v<U*, T*>>;
+
+ public:
+  using value_type = T;
+
+  constexpr optional_ref() : ptr_(nullptr) {}
+  constexpr optional_ref(  // NOLINT(google-explicit-constructor)
+      std::nullopt_t)
+      : ptr_(nullptr) {}
+
+  // Constructor given a concrete value.
+  constexpr optional_ref(  // NOLINT(google-explicit-constructor)
+      T& input ABSL_ATTRIBUTE_LIFETIME_BOUND)
+      : ptr_(std::addressof(input)) {}
+
+  // Constructors given an existing std::optional value.
+  // Templated on the input optional's type to avoid creating a temporary.
+  template <typename U, typename = EnableIfConvertibleFrom<const U>>
+  constexpr optional_ref(  // NOLINT(google-explicit-constructor)
+      const std::optional<U>& input ABSL_ATTRIBUTE_LIFETIME_BOUND)
+      : ptr_(input.has_value() ? std::addressof(*input) : nullptr) {}
+  template <typename U, typename = EnableIfConvertibleFrom<U>>
+  constexpr optional_ref(  // NOLINT(google-explicit-constructor)
+      std::optional<U>& input ABSL_ATTRIBUTE_LIFETIME_BOUND)
+      : ptr_(input.has_value() ? std::addressof(*input) : nullptr) {}
+
+  // Constructor given a T*, where nullptr indicates empty/absent.
+  constexpr optional_ref(  // NOLINT(google-explicit-constructor)
+      T* input ABSL_ATTRIBUTE_LIFETIME_BOUND)
+      : ptr_(input) {}
+
+  // Don't allow naked nullptr as input, as this creates confusion in the case
+  // of optional_ref<T*>. Use std::nullopt instead to create an empty
+  // optional_ref.
+  constexpr optional_ref(  // NOLINT(google-explicit-constructor)
+      std::nullptr_t) = delete;
+
+  // Copying is allowed.
+  optional_ref(const optional_ref<T>&) = default;
+  // Assignment is not allowed.
+  optional_ref<T>& operator=(const optional_ref<T>&) = delete;
+
+  // Conversion from optional_ref<U> is allowed iff U* is convertible to T*.
+  // (Note this also allows non-const to const conversions.)
+  template <typename U, typename = EnableIfConvertibleFrom<U>>
+  constexpr optional_ref(  // NOLINT(google-explicit-constructor)
+      optional_ref<U> input)
+      : ptr_(input.as_pointer()) {}
+
+  // Determines whether the `optional_ref` contains a value. Returns `false` if
+  // and only if `*this` is empty.
+  constexpr bool has_value() const { return ptr_ != nullptr; }
+
+  // Returns a reference to an `optional_ref`s underlying value. The constness
+  // and lvalue/rvalue-ness of the `optional_ref` is preserved to the view of
+  // the `T` sub-object. Throws the same error as `std::optional`'s `value()`
+  // when the `optional_ref` is empty.
+  constexpr T& value() const {
+    return ABSL_PREDICT_TRUE(ptr_ != nullptr)
+               ? *ptr_
+               // Replicate the same error logic as in `std::optional`'s
+               // `value()`. It either throws an exception or aborts the
+               // program. We intentionally ignore the return value of
+               // the constructed optional's value as we only need to run
+               // the code for error checking.
+               : ((void)std::optional<T>().value(), *ptr_);
+  }
+
+  // Returns the value iff *this has a value, otherwise returns `default_value`.
+  template <typename U>
+  constexpr T value_or(U&& default_value) const {
+    // Instantiate std::optional<T>::value_or(U) to trigger its static_asserts.
+    if (false) {
+      // We use `std::add_const_t` here since just using `const` makes MSVC
+      // complain about the syntax.
+      (void)std::add_const_t<std::optional<T>>{}.value_or(
+          std::forward<U>(default_value));
+    }
+    return ptr_ != nullptr ? *ptr_
+                           : static_cast<T>(std::forward<U>(default_value));
+  }
+
+  // Accesses the underlying `T` value of an `optional_ref`. If the
+  // `optional_ref` is empty, behavior is undefined.
+  constexpr T& operator*() const {
+    ABSL_HARDENING_ASSERT(ptr_ != nullptr);
+    return *ptr_;
+  }
+  constexpr T* operator->() const {
+    ABSL_HARDENING_ASSERT(ptr_ != nullptr);
+    return ptr_;
+  }
+
+  // Convenience function to represent the `optional_ref` as a `T*` pointer.
+  constexpr T* as_pointer() const { return ptr_; }
+  // Convenience function to represent the `optional_ref` as an `optional`,
+  // which incurs a copy when the `optional_ref` is non-empty. The template type
+  // allows for implicit type conversion; example:
+  //   optional_ref<std::string> a = ...;
+  //   std::optional<std::string_view> b = a.as_optional<std::string_view>();
+  template <typename U = std::decay_t<T>>
+  constexpr std::optional<U> as_optional() const {
+    if (ptr_ == nullptr) return std::nullopt;
+    return *ptr_;
+  }
+
+ private:
+  T* const ptr_;
+
+  // T constraint checks.  You can't have an optional of nullopt_t or
+  // in_place_t.
+  static_assert(!std::is_same_v<std::nullopt_t, std::remove_cv_t<T>>,
+                "optional_ref<nullopt_t> is not allowed.");
+  static_assert(!std::is_same_v<std::in_place_t, std::remove_cv_t<T>>,
+                "optional_ref<in_place_t> is not allowed.");
+};
+
+// Template type deduction guides:
+
+template <typename T>
+optional_ref(const T&) -> optional_ref<const T>;
+template <typename T>
+optional_ref(T&) -> optional_ref<T>;
+
+template <typename T>
+optional_ref(const std::optional<T>&) -> optional_ref<const T>;
+template <typename T>
+optional_ref(std::optional<T>&) -> optional_ref<T>;
+
+template <typename T>
+optional_ref(T*) -> optional_ref<T>;
+
+namespace optional_ref_internal {
+
+// This is a C++-11 compatible version of std::equality_comparable_with that
+// only requires `t == u` is a valid boolean expression.
+//
+// We still need this for a couple reasons:
+// -  As of 2026-02-13, Abseil supports C++17.
+//  - Even for targets that are built with the default toolchain, using
+//    std::equality_comparable_with gives us an error due to mutual recursion
+//    between its definition and our definition of operator==.
+//
+template <typename T, typename U>
+using enable_if_equality_comparable_t = std::enable_if_t<std::is_convertible_v<
+    decltype(std::declval<T>() == std::declval<U>()), bool>>;
+
+}  // namespace optional_ref_internal
+
+// Compare an optional referenced value to std::nullopt.
+
+template <typename T>
+constexpr bool operator==(optional_ref<T> a, std::nullopt_t) {
+  return !a.has_value();
+}
+template <typename T>
+constexpr bool operator==(std::nullopt_t, optional_ref<T> b) {
+  return !b.has_value();
+}
+template <typename T>
+constexpr bool operator!=(optional_ref<T> a, std::nullopt_t) {
+  return a.has_value();
+}
+template <typename T>
+constexpr bool operator!=(std::nullopt_t, optional_ref<T> b) {
+  return b.has_value();
+}
+
+// Compare two optional referenced values. Note, this does not test that the
+// contained `ptr_`s are equal. If the caller wants "shallow" reference equality
+// semantics, they should use `as_pointer()` explicitly.
+
+template <typename T, typename U>
+constexpr bool operator==(optional_ref<T> a, optional_ref<U> b) {
+  return a.has_value() ? *a == b : !b.has_value();
+}
+
+// Compare an optional referenced value to a non-optional value.
+
+template <
+    typename T, typename U,
+    typename = optional_ref_internal::enable_if_equality_comparable_t<T, U>>
+constexpr bool operator==(const T& a, optional_ref<U> b) {
+  return b.has_value() && a == *b;
+}
+template <
+    typename T, typename U,
+    typename = optional_ref_internal::enable_if_equality_comparable_t<T, U>>
+constexpr bool operator==(optional_ref<T> a, const U& b) {
+  return b == a;
+}
+
+// Inequality operators, as above.
+
+template <typename T, typename U>
+constexpr bool operator!=(optional_ref<T> a, optional_ref<U> b) {
+  return !(a == b);
+}
+template <
+    typename T, typename U,
+    typename = optional_ref_internal::enable_if_equality_comparable_t<T, U>>
+constexpr bool operator!=(optional_ref<T> a, const U& b) {
+  return !(a == b);
+}
+template <
+    typename T, typename U,
+    typename = optional_ref_internal::enable_if_equality_comparable_t<T, U>>
+constexpr bool operator!=(const T& a, optional_ref<U> b) {
+  return !(a == b);
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_TYPES_OPTIONAL_REF_H_
diff --git a/absl/types/optional_ref_test.cc b/absl/types/optional_ref_test.cc
new file mode 100644
index 0000000..dda1624
--- /dev/null
+++ b/absl/types/optional_ref_test.cc
@@ -0,0 +1,370 @@
+// Copyright 2026 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/types/optional_ref.h"
+
+#include <cstddef>
+#include <memory>
+#include <optional>
+#include <string>
+#include <string_view>
+#include <type_traits>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/config.h"
+#include "absl/log/log.h"
+#include "absl/strings/str_cat.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace {
+
+using ::testing::Optional;
+using ::testing::Pointee;
+
+TEST(OptionalRefTest, SimpleType) {
+  int val = 5;
+  optional_ref<int> ref = optional_ref(val);
+  optional_ref<int> empty_ref = std::nullopt;
+  EXPECT_THAT(ref, Optional(5));
+  EXPECT_TRUE(ref.has_value());
+  EXPECT_EQ(*ref, val);
+  EXPECT_EQ(ref.value(), val);
+  EXPECT_EQ(ref, ref);
+  EXPECT_EQ(ref, val);
+  EXPECT_EQ(val, ref);
+  EXPECT_NE(ref, empty_ref);
+  EXPECT_NE(empty_ref, ref);
+}
+
+TEST(OptionalRefTest, SimpleConstType) {
+  const int val = 5;
+  optional_ref<const int> ref = optional_ref(val);
+  EXPECT_THAT(ref, Optional(5));
+}
+
+TEST(OptionalRefTest, DefaultConstructed) {
+  optional_ref<int> ref;
+  EXPECT_EQ(ref, std::nullopt);
+  EXPECT_EQ(std::nullopt, ref);
+}
+
+TEST(OptionalRefTest, EmptyOptional) {
+  auto ref = optional_ref<int>(std::nullopt);
+  EXPECT_EQ(ref, std::nullopt);
+  EXPECT_EQ(std::nullopt, ref);
+}
+
+TEST(OptionalRefTest, OptionalType) {
+  const std::optional<int> val = 5;
+  optional_ref<const int> ref = val;
+  EXPECT_THAT(ref, Optional(5));
+  EXPECT_EQ(ref.as_pointer(), &*val);
+
+  const std::optional<int> empty;
+  optional_ref<const int> empty_ref = empty;
+  EXPECT_EQ(empty_ref, std::nullopt);
+
+  // Cannot make non-const reference to const optional.
+  static_assert(
+      !std::is_convertible_v<const std::optional<int>&, optional_ref<int>>);
+}
+
+TEST(OptionalRefTest, NonConstOptionalType) {
+  std::optional<int> val = 5;
+  optional_ref<int> ref = val;
+  EXPECT_THAT(ref, Optional(5));
+  EXPECT_EQ(ref.as_pointer(), &*val);
+
+  std::optional<int> empty;
+  optional_ref<int> empty_ref = empty;
+  EXPECT_EQ(empty_ref, std::nullopt);
+}
+
+TEST(OptionalRefTest, NonConstOptionalTypeToConstRef) {
+  std::optional<int> val = 5;
+  optional_ref<const int> ref = val;
+  EXPECT_THAT(ref, Optional(5));
+  EXPECT_EQ(ref.as_pointer(), &*val);
+
+  std::optional<int> empty;
+  optional_ref<const int> empty_ref = empty;
+  EXPECT_EQ(empty_ref, std::nullopt);
+}
+
+TEST(OptionalRefTest, NonConstOptionalWithConstValueType) {
+  std::optional<const int> val = 5;
+  optional_ref<const int> ref = val;
+  EXPECT_THAT(ref, Optional(5));
+  EXPECT_EQ(ref.as_pointer(), &*val);
+
+  std::optional<const int> empty;
+  optional_ref<const int> empty_ref = empty;
+  EXPECT_EQ(empty_ref, std::nullopt);
+
+  // Not possible to convert to non-const reference.
+  static_assert(
+      !std::is_convertible_v<std::optional<const int>&, optional_ref<int>>);
+}
+
+class TestInterface {};
+class TestDerivedClass : public TestInterface {};
+
+TEST(OptionalRefTest, BaseDerivedConvertibleOptionalType) {
+  const std::optional<TestDerivedClass> dc = TestDerivedClass{};
+  optional_ref<const TestInterface> ref = dc;
+  EXPECT_NE(ref, std::nullopt);
+  EXPECT_EQ(ref.as_pointer(), &*dc);
+
+  const std::optional<TestDerivedClass> empty;
+  optional_ref<const TestInterface> empty_ref = empty;
+  EXPECT_EQ(empty_ref, std::nullopt);
+
+  // Not possible in the other direction.
+  static_assert(!std::is_convertible_v<const std::optional<TestInterface>&,
+                                       optional_ref<const TestDerivedClass>>);
+  static_assert(!std::is_convertible_v<const std::optional<TestDerivedClass>&,
+                                       optional_ref<TestInterface>>);
+}
+
+TEST(OptionalRefTest, NonConstBaseDerivedConvertibleOptionalType) {
+  std::optional<TestDerivedClass> dc = TestDerivedClass{};
+  optional_ref<TestInterface> ref = dc;
+  EXPECT_NE(ref, std::nullopt);
+  EXPECT_EQ(ref.as_pointer(), &*dc);
+
+  std::optional<TestDerivedClass> empty;
+  optional_ref<TestInterface> empty_ref = empty;
+  EXPECT_EQ(empty_ref, std::nullopt);
+
+  // Not possible in the other direction.
+  static_assert(!std::is_convertible_v<std::optional<TestInterface>&,
+                                       optional_ref<TestDerivedClass>>);
+}
+
+TEST(OptionalRefTest, NonConstBaseDerivedConvertibleOptionalTypeToConstRef) {
+  std::optional<TestDerivedClass> dc = TestDerivedClass{};
+  optional_ref<const TestInterface> ref = dc;
+  EXPECT_NE(ref, std::nullopt);
+  EXPECT_EQ(ref.as_pointer(), &*dc);
+
+  std::optional<TestDerivedClass> empty;
+  optional_ref<const TestInterface> empty_ref = empty;
+  EXPECT_EQ(empty_ref, std::nullopt);
+
+  // Not possible in the other direction.
+  static_assert(!std::is_convertible_v<std::optional<TestInterface>&,
+                                       optional_ref<const TestDerivedClass>>);
+  static_assert(!std::is_convertible_v<const std::optional<TestInterface>&,
+                                       optional_ref<const TestDerivedClass>>);
+}
+
+TEST(OptionalRefTest, PointerCtor) {
+  int val = 5;
+  optional_ref<const int> ref = &val;
+  EXPECT_THAT(ref, Optional(5));
+
+  auto auto_ref = optional_ref(&val);
+  static_assert(std::is_same_v<decltype(auto_ref), optional_ref<int>>,
+                "optional_ref(T*) should deduce to optional_ref<T>.");
+  EXPECT_THAT(auto_ref, Optional(5));
+
+  int* foo = nullptr;
+  optional_ref<const int> empty_ref = foo;
+  EXPECT_EQ(empty_ref, std::nullopt);
+
+  optional_ref<int*> ptr_ref = foo;
+  EXPECT_THAT(ptr_ref, Optional(nullptr));
+  static_assert(
+      !std::is_constructible_v<optional_ref<int*>, std::nullptr_t>,
+      "optional_ref should not be constructible with std::nullptr_t.");
+
+  // Pointer polymorphism works.
+  TestDerivedClass dc;
+  optional_ref<const TestInterface> dc_ref = &dc;
+  EXPECT_NE(dc_ref, std::nullopt);
+}
+
+TEST(OptionalRefTest, ValueDeathWhenEmpty) {
+  optional_ref<int> ref;
+#ifdef ABSL_HAVE_EXCEPTIONS
+  EXPECT_THROW(ref.value(), std::bad_optional_access);
+#else
+  EXPECT_DEATH_IF_SUPPORTED(ref.value(), "");
+#endif
+}
+
+TEST(OptionalRefTest, ImplicitCtor) {
+  const int val = 5;
+  optional_ref<const int> ref = val;
+  EXPECT_THAT(ref, Optional(5));
+}
+
+TEST(OptionalRefTest, DoesNotCopy) {
+  // Non-copyable type.
+  auto val = std::make_unique<int>(5);
+  optional_ref<std::unique_ptr<int>> ref = optional_ref(val);
+  EXPECT_THAT(ref, Optional(Pointee(5)));
+}
+
+TEST(OptionalRefTest, DoesNotCopyConst) {
+  // Non-copyable type.
+  const auto val = std::make_unique<int>(5);
+  optional_ref<const std::unique_ptr<int>> ref = optional_ref(val);
+  EXPECT_THAT(ref, Optional(Pointee(5)));
+}
+
+TEST(OptionalRefTest, RefCopyable) {
+  auto val = std::make_unique<int>(5);
+  optional_ref<std::unique_ptr<int>> ref = optional_ref(val);
+  optional_ref<std::unique_ptr<int>> copy = ref;
+  EXPECT_THAT(copy, Optional(Pointee(5)));
+}
+
+TEST(OptionalRefTest, ConstConvertible) {
+  auto val = std::make_unique<int>(5);
+  optional_ref<std::unique_ptr<int>> ref = optional_ref(val);
+  optional_ref<const std::unique_ptr<int>> converted = ref;
+  EXPECT_THAT(converted, Optional(Pointee(5)));
+  EXPECT_EQ(converted.as_pointer(), &val);
+
+  // Not possible in the other direction.
+  static_assert(!std::is_convertible_v<optional_ref<const std::unique_ptr<int>>,
+                                       optional_ref<std::unique_ptr<int>>>);
+}
+
+TEST(OptionalRefTest, BaseDerivedConvertible) {
+  TestDerivedClass dc;
+  optional_ref<TestDerivedClass> dc_ref = dc;
+  optional_ref<TestInterface> converted = dc_ref;
+  EXPECT_NE(converted, std::nullopt);
+  EXPECT_EQ(converted.as_pointer(), &dc);
+
+  // Not possible in the other direction.
+  static_assert(!std::is_convertible_v<optional_ref<TestInterface>,
+                                       optional_ref<TestDerivedClass>>);
+}
+
+TEST(OptionalRefTest, BaseDerivedConstConvertible) {
+  TestDerivedClass dc;
+  optional_ref<TestDerivedClass> dc_ref = dc;
+  optional_ref<const TestInterface> converted = dc_ref;
+  EXPECT_NE(converted, std::nullopt);
+  EXPECT_EQ(converted.as_pointer(), &dc);
+
+  // Not possible in the other direction.
+  static_assert(!std::is_convertible_v<optional_ref<const TestInterface>,
+                                       optional_ref<TestDerivedClass>>);
+  static_assert(!std::is_convertible_v<optional_ref<const TestDerivedClass>,
+                                       optional_ref<TestInterface>>);
+}
+
+TEST(OptionalRefTest, BaseDerivedBothConstConvertible) {
+  TestDerivedClass dc;
+  optional_ref<const TestDerivedClass> dc_ref = dc;
+  optional_ref<const TestInterface> converted = dc_ref;
+  EXPECT_NE(converted, std::nullopt);
+  EXPECT_EQ(converted.as_pointer(), &dc);
+
+  // Not possible in the other direction.
+  static_assert(!std::is_convertible_v<optional_ref<const TestInterface>,
+                                       optional_ref<const TestDerivedClass>>);
+}
+
+TEST(OptionalRefTest, TriviallyCopyable) {
+  static_assert(
+      std::is_trivially_copyable_v<optional_ref<std::unique_ptr<int>>>);
+}
+
+TEST(OptionalRefTest, TriviallyDestructible) {
+  static_assert(
+      std::is_trivially_destructible_v<optional_ref<std::unique_ptr<int>>>);
+}
+
+TEST(OptionalRefTest, RefNotAssignable) {
+  static_assert(!std::is_copy_assignable_v<optional_ref<int>>);
+  static_assert(!std::is_move_assignable_v<optional_ref<int>>);
+}
+
+struct TestStructWithCopy {
+  TestStructWithCopy() = default;
+  TestStructWithCopy(TestStructWithCopy&&) {
+    LOG(FATAL) << "Move constructor should not be called";
+  }
+  TestStructWithCopy(const TestStructWithCopy&) {
+    LOG(FATAL) << "Copy constructor should not be called";
+  }
+  TestStructWithCopy& operator=(const TestStructWithCopy&) {
+    LOG(FATAL) << "Assign operator should not be called";
+  }
+};
+
+TEST(OptionalRefTest, DoesNotCopyUsingFatalCopyAssignOps) {
+  TestStructWithCopy val;
+  optional_ref<TestStructWithCopy> ref = optional_ref(val);
+  EXPECT_NE(ref, std::nullopt);
+  EXPECT_NE(optional_ref(TestStructWithCopy{}), std::nullopt);
+}
+
+std::string AddExclamation(optional_ref<const std::string> input) {
+  if (!input.has_value()) {
+    return "";
+  }
+  return absl::StrCat(*input, "!");
+}
+
+TEST(OptionalRefTest, RefAsFunctionParameter) {
+  EXPECT_EQ(AddExclamation(std::nullopt), "");
+  EXPECT_EQ(AddExclamation(std::string("abc")), "abc!");
+  std::string s = "def";
+  EXPECT_EQ(AddExclamation(s), "def!");
+  EXPECT_EQ(AddExclamation(std::make_optional<std::string>(s)), "def!");
+}
+
+TEST(OptionalRefTest, ValueOrWhenHasValue) {
+  std::optional<int> val = 5;
+  EXPECT_EQ(optional_ref(val).value_or(2), 5);
+}
+
+TEST(OptionalRefTest, ValueOrWhenEmpty) {
+  std::optional<int> val = std::nullopt;
+  EXPECT_EQ(optional_ref(val).value_or(2), 2);
+}
+
+TEST(OptionalRefTest, AsOptional) {
+  EXPECT_EQ(optional_ref<int>().as_optional(), std::nullopt);
+  std::string val = "foo";
+  optional_ref<const std::string> ref = val;
+  static_assert(
+      std::is_same_v<decltype(ref.as_optional()), std::optional<std::string>>,
+      "The type parameter of optional_ref should decay by default for the "
+      "return type in as_optional().");
+  std::optional<std::string> opt_string = ref.as_optional();
+  EXPECT_THAT(opt_string, Optional(val));
+
+  std::optional<std::string_view> opt_view =
+      ref.as_optional<std::string_view>();
+  EXPECT_THAT(opt_view, Optional(val));
+}
+
+TEST(OptionalRefTest, Constexpr) {
+  static constexpr int foo = 123;
+  constexpr optional_ref<const int> ref(foo);
+  static_assert(ref.has_value() && *ref == foo && ref.value() == foo, "");
+}
+
+}  // namespace
+ABSL_NAMESPACE_END
+}  // namespace absl